summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSteve Reinhardt <stever@eecs.umich.edu>2006-05-22 14:29:33 -0400
committerSteve Reinhardt <stever@eecs.umich.edu>2006-05-22 14:29:33 -0400
commitba2eae5d528487900d1510fc0a160e660f2c394c (patch)
treea2c6dd5948f6ff353763cb3f83ddd734077e646e /src
parent86777c9db174c74be49667bce3dda99f8ba23696 (diff)
downloadgem5-ba2eae5d528487900d1510fc0a160e660f2c394c.tar.xz
New directory structure:
- simulator source now in 'src' subdirectory - imported files from 'ext' repository - support building in arbitrary places, including outside of the source tree. See comment at top of SConstruct file for more details. Regression tests are temporarily disabled; that syetem needs more extensive revisions. SConstruct: Update for new directory structure. Modify to support build trees that are not subdirectories of the source tree. See comment at top of file for more details. Regression tests are temporarily disabled. src/arch/SConscript: src/arch/isa_parser.py: src/python/SConscript: Update for new directory structure. --HG-- rename : build/SConstruct => SConstruct rename : build/default_options/ALPHA_FS => build_opts/ALPHA_FS rename : build/default_options/ALPHA_FS_TL => build_opts/ALPHA_FS_TL rename : build/default_options/ALPHA_SE => build_opts/ALPHA_SE rename : build/default_options/MIPS_SE => build_opts/MIPS_SE rename : build/default_options/SPARC_SE => build_opts/SPARC_SE rename : Doxyfile => src/Doxyfile rename : SConscript => src/SConscript rename : arch/SConscript => src/arch/SConscript rename : arch/alpha/SConscript => src/arch/alpha/SConscript rename : arch/alpha/aout_machdep.h => src/arch/alpha/aout_machdep.h rename : arch/alpha/arguments.cc => src/arch/alpha/arguments.cc rename : arch/alpha/arguments.hh => src/arch/alpha/arguments.hh rename : arch/alpha/ecoff_machdep.h => src/arch/alpha/ecoff_machdep.h rename : arch/alpha/ev5.cc => src/arch/alpha/ev5.cc rename : arch/alpha/ev5.hh => src/arch/alpha/ev5.hh rename : arch/alpha/faults.cc => src/arch/alpha/faults.cc rename : arch/alpha/faults.hh => src/arch/alpha/faults.hh rename : arch/alpha/freebsd/system.cc => src/arch/alpha/freebsd/system.cc rename : arch/alpha/freebsd/system.hh => src/arch/alpha/freebsd/system.hh rename : arch/alpha/isa/branch.isa => src/arch/alpha/isa/branch.isa rename : arch/alpha/isa/decoder.isa => src/arch/alpha/isa/decoder.isa rename : arch/alpha/isa/fp.isa => src/arch/alpha/isa/fp.isa rename : arch/alpha/isa/int.isa => src/arch/alpha/isa/int.isa rename : arch/alpha/isa/main.isa => src/arch/alpha/isa/main.isa rename : arch/alpha/isa/mem.isa => src/arch/alpha/isa/mem.isa rename : arch/alpha/isa/opcdec.isa => src/arch/alpha/isa/opcdec.isa rename : arch/alpha/isa/pal.isa => src/arch/alpha/isa/pal.isa rename : arch/alpha/isa/unimp.isa => src/arch/alpha/isa/unimp.isa rename : arch/alpha/isa/unknown.isa => src/arch/alpha/isa/unknown.isa rename : arch/alpha/isa/util.isa => src/arch/alpha/isa/util.isa rename : arch/alpha/isa_traits.hh => src/arch/alpha/isa_traits.hh rename : arch/alpha/linux/aligned.hh => src/arch/alpha/linux/aligned.hh rename : arch/alpha/linux/hwrpb.hh => src/arch/alpha/linux/hwrpb.hh rename : arch/alpha/linux/linux.cc => src/arch/alpha/linux/linux.cc rename : arch/alpha/linux/linux.hh => src/arch/alpha/linux/linux.hh rename : arch/alpha/linux/process.cc => src/arch/alpha/linux/process.cc rename : arch/alpha/linux/process.hh => src/arch/alpha/linux/process.hh rename : arch/alpha/linux/system.cc => src/arch/alpha/linux/system.cc rename : arch/alpha/linux/system.hh => src/arch/alpha/linux/system.hh rename : arch/alpha/linux/thread_info.hh => src/arch/alpha/linux/thread_info.hh rename : arch/alpha/linux/threadinfo.hh => src/arch/alpha/linux/threadinfo.hh rename : arch/alpha/osfpal.cc => src/arch/alpha/osfpal.cc rename : arch/alpha/osfpal.hh => src/arch/alpha/osfpal.hh rename : arch/alpha/process.cc => src/arch/alpha/process.cc rename : arch/alpha/process.hh => src/arch/alpha/process.hh rename : arch/alpha/regfile.hh => src/arch/alpha/regfile.hh rename : arch/alpha/stacktrace.cc => src/arch/alpha/stacktrace.cc rename : arch/alpha/stacktrace.hh => src/arch/alpha/stacktrace.hh rename : arch/alpha/system.cc => src/arch/alpha/system.cc rename : arch/alpha/system.hh => src/arch/alpha/system.hh rename : arch/alpha/tlb.cc => src/arch/alpha/tlb.cc rename : arch/alpha/tlb.hh => src/arch/alpha/tlb.hh rename : arch/alpha/tru64/process.cc => src/arch/alpha/tru64/process.cc rename : arch/alpha/tru64/process.hh => src/arch/alpha/tru64/process.hh rename : arch/alpha/tru64/system.cc => src/arch/alpha/tru64/system.cc rename : arch/alpha/tru64/system.hh => src/arch/alpha/tru64/system.hh rename : arch/alpha/tru64/tru64.cc => src/arch/alpha/tru64/tru64.cc rename : arch/alpha/tru64/tru64.hh => src/arch/alpha/tru64/tru64.hh rename : arch/alpha/types.hh => src/arch/alpha/types.hh rename : arch/alpha/utility.hh => src/arch/alpha/utility.hh rename : arch/alpha/vtophys.cc => src/arch/alpha/vtophys.cc rename : arch/alpha/vtophys.hh => src/arch/alpha/vtophys.hh rename : arch/isa_parser.py => src/arch/isa_parser.py rename : arch/isa_specific.hh => src/arch/isa_specific.hh rename : arch/mips/SConscript => src/arch/mips/SConscript rename : arch/mips/faults.cc => src/arch/mips/faults.cc rename : arch/mips/faults.hh => src/arch/mips/faults.hh rename : arch/mips/isa/base.isa => src/arch/mips/isa/base.isa rename : arch/mips/isa/bitfields.isa => src/arch/mips/isa/bitfields.isa rename : arch/mips/isa/decoder.isa => src/arch/mips/isa/decoder.isa rename : arch/mips/isa/formats/basic.isa => src/arch/mips/isa/formats/basic.isa rename : arch/mips/isa/formats/branch.isa => src/arch/mips/isa/formats/branch.isa rename : arch/mips/isa/formats/formats.isa => src/arch/mips/isa/formats/formats.isa rename : arch/mips/isa/formats/fp.isa => src/arch/mips/isa/formats/fp.isa rename : arch/mips/isa/formats/int.isa => src/arch/mips/isa/formats/int.isa rename : arch/mips/isa/formats/mem.isa => src/arch/mips/isa/formats/mem.isa rename : arch/mips/isa/formats/noop.isa => src/arch/mips/isa/formats/noop.isa rename : arch/mips/isa/formats/tlbop.isa => src/arch/mips/isa/formats/tlbop.isa rename : arch/mips/isa/formats/trap.isa => src/arch/mips/isa/formats/trap.isa rename : arch/mips/isa/formats/unimp.isa => src/arch/mips/isa/formats/unimp.isa rename : arch/mips/isa/formats/unknown.isa => src/arch/mips/isa/formats/unknown.isa rename : arch/mips/isa/formats/util.isa => src/arch/mips/isa/formats/util.isa rename : arch/mips/isa/includes.isa => src/arch/mips/isa/includes.isa rename : arch/mips/isa/main.isa => src/arch/mips/isa/main.isa rename : arch/mips/isa/operands.isa => src/arch/mips/isa/operands.isa rename : arch/mips/isa_traits.cc => src/arch/mips/isa_traits.cc rename : arch/mips/isa_traits.hh => src/arch/mips/isa_traits.hh rename : arch/mips/linux/linux.cc => src/arch/mips/linux/linux.cc rename : arch/mips/linux/linux.hh => src/arch/mips/linux/linux.hh rename : arch/mips/linux/process.cc => src/arch/mips/linux/process.cc rename : arch/mips/linux/process.hh => src/arch/mips/linux/process.hh rename : arch/mips/process.cc => src/arch/mips/process.cc rename : arch/mips/process.hh => src/arch/mips/process.hh rename : arch/mips/regfile/float_regfile.hh => src/arch/mips/regfile/float_regfile.hh rename : arch/mips/regfile/int_regfile.hh => src/arch/mips/regfile/int_regfile.hh rename : arch/mips/regfile/misc_regfile.hh => src/arch/mips/regfile/misc_regfile.hh rename : arch/mips/regfile/regfile.hh => src/arch/mips/regfile/regfile.hh rename : arch/mips/stacktrace.hh => src/arch/mips/stacktrace.hh rename : arch/mips/types.hh => src/arch/mips/types.hh rename : arch/mips/utility.hh => src/arch/mips/utility.hh rename : arch/sparc/SConscript => src/arch/sparc/SConscript rename : arch/sparc/faults.cc => src/arch/sparc/faults.cc rename : arch/sparc/faults.hh => src/arch/sparc/faults.hh rename : arch/sparc/isa/base.isa => src/arch/sparc/isa/base.isa rename : arch/sparc/isa/bitfields.isa => src/arch/sparc/isa/bitfields.isa rename : arch/sparc/isa/decoder.isa => src/arch/sparc/isa/decoder.isa rename : arch/sparc/isa/formats.isa => src/arch/sparc/isa/formats.isa rename : arch/sparc/isa/formats/basic.isa => src/arch/sparc/isa/formats/basic.isa rename : arch/sparc/isa/formats/branch.isa => src/arch/sparc/isa/formats/branch.isa rename : arch/sparc/isa/formats/integerop.isa => src/arch/sparc/isa/formats/integerop.isa rename : arch/sparc/isa/formats/mem.isa => src/arch/sparc/isa/formats/mem.isa rename : arch/sparc/isa/formats/nop.isa => src/arch/sparc/isa/formats/nop.isa rename : arch/sparc/isa/formats/priv.isa => src/arch/sparc/isa/formats/priv.isa rename : arch/sparc/isa/formats/trap.isa => src/arch/sparc/isa/formats/trap.isa rename : arch/sparc/isa/formats/unknown.isa => src/arch/sparc/isa/formats/unknown.isa rename : arch/sparc/isa/includes.isa => src/arch/sparc/isa/includes.isa rename : arch/sparc/isa/main.isa => src/arch/sparc/isa/main.isa rename : arch/sparc/isa/operands.isa => src/arch/sparc/isa/operands.isa rename : arch/sparc/isa_traits.hh => src/arch/sparc/isa_traits.hh rename : arch/sparc/linux/linux.cc => src/arch/sparc/linux/linux.cc rename : arch/sparc/linux/linux.hh => src/arch/sparc/linux/linux.hh rename : arch/sparc/linux/process.cc => src/arch/sparc/linux/process.cc rename : arch/sparc/linux/process.hh => src/arch/sparc/linux/process.hh rename : arch/sparc/process.cc => src/arch/sparc/process.cc rename : arch/sparc/process.hh => src/arch/sparc/process.hh rename : arch/sparc/regfile.hh => src/arch/sparc/regfile.hh rename : arch/sparc/solaris/process.cc => src/arch/sparc/solaris/process.cc rename : arch/sparc/solaris/process.hh => src/arch/sparc/solaris/process.hh rename : arch/sparc/solaris/solaris.cc => src/arch/sparc/solaris/solaris.cc rename : arch/sparc/solaris/solaris.hh => src/arch/sparc/solaris/solaris.hh rename : arch/sparc/stacktrace.hh => src/arch/sparc/stacktrace.hh rename : arch/sparc/system.cc => src/arch/sparc/system.cc rename : arch/sparc/system.hh => src/arch/sparc/system.hh rename : arch/sparc/utility.hh => src/arch/sparc/utility.hh rename : base/bitfield.hh => src/base/bitfield.hh rename : base/callback.hh => src/base/callback.hh rename : base/chunk_generator.hh => src/base/chunk_generator.hh rename : base/circlebuf.cc => src/base/circlebuf.cc rename : base/circlebuf.hh => src/base/circlebuf.hh rename : base/compression/lzss_compression.cc => src/base/compression/lzss_compression.cc rename : base/compression/lzss_compression.hh => src/base/compression/lzss_compression.hh rename : base/compression/null_compression.hh => src/base/compression/null_compression.hh rename : base/cprintf.cc => src/base/cprintf.cc rename : base/cprintf.hh => src/base/cprintf.hh rename : base/cprintf_formats.hh => src/base/cprintf_formats.hh rename : base/crc.cc => src/base/crc.cc rename : base/crc.hh => src/base/crc.hh rename : base/date.cc => src/base/date.cc rename : base/dbl_list.hh => src/base/dbl_list.hh rename : base/endian.hh => src/base/endian.hh rename : base/fast_alloc.cc => src/base/fast_alloc.cc rename : base/fast_alloc.hh => src/base/fast_alloc.hh rename : base/fenv.hh => src/base/fenv.hh rename : base/fifo_buffer.cc => src/base/fifo_buffer.cc rename : base/fifo_buffer.hh => src/base/fifo_buffer.hh rename : base/hashmap.hh => src/base/hashmap.hh rename : base/hostinfo.cc => src/base/hostinfo.cc rename : base/hostinfo.hh => src/base/hostinfo.hh rename : base/hybrid_pred.cc => src/base/hybrid_pred.cc rename : base/hybrid_pred.hh => src/base/hybrid_pred.hh rename : base/inet.cc => src/base/inet.cc rename : base/inet.hh => src/base/inet.hh rename : base/inifile.cc => src/base/inifile.cc rename : base/inifile.hh => src/base/inifile.hh rename : base/intmath.cc => src/base/intmath.cc rename : base/intmath.hh => src/base/intmath.hh rename : base/kgdb.h => src/base/kgdb.h rename : base/loader/aout_object.cc => src/base/loader/aout_object.cc rename : base/loader/aout_object.hh => src/base/loader/aout_object.hh rename : base/loader/coff_sym.h => src/base/loader/coff_sym.h rename : base/loader/coff_symconst.h => src/base/loader/coff_symconst.h rename : base/loader/ecoff_object.cc => src/base/loader/ecoff_object.cc rename : base/loader/ecoff_object.hh => src/base/loader/ecoff_object.hh rename : base/loader/elf_object.cc => src/base/loader/elf_object.cc rename : base/loader/elf_object.hh => src/base/loader/elf_object.hh rename : base/loader/exec_aout.h => src/base/loader/exec_aout.h rename : base/loader/exec_ecoff.h => src/base/loader/exec_ecoff.h rename : base/loader/object_file.cc => src/base/loader/object_file.cc rename : base/loader/object_file.hh => src/base/loader/object_file.hh rename : base/loader/symtab.cc => src/base/loader/symtab.cc rename : base/loader/symtab.hh => src/base/loader/symtab.hh rename : base/match.cc => src/base/match.cc rename : base/match.hh => src/base/match.hh rename : base/misc.cc => src/base/misc.cc rename : base/misc.hh => src/base/misc.hh rename : base/mod_num.hh => src/base/mod_num.hh rename : base/mysql.cc => src/base/mysql.cc rename : base/mysql.hh => src/base/mysql.hh rename : base/output.cc => src/base/output.cc rename : base/output.hh => src/base/output.hh rename : base/pollevent.cc => src/base/pollevent.cc rename : base/pollevent.hh => src/base/pollevent.hh rename : base/predictor.hh => src/base/predictor.hh rename : base/random.cc => src/base/random.cc rename : base/random.hh => src/base/random.hh rename : base/range.cc => src/base/range.cc rename : base/range.hh => src/base/range.hh rename : base/refcnt.hh => src/base/refcnt.hh rename : base/remote_gdb.cc => src/base/remote_gdb.cc rename : base/remote_gdb.hh => src/base/remote_gdb.hh rename : base/res_list.hh => src/base/res_list.hh rename : base/sat_counter.cc => src/base/sat_counter.cc rename : base/sat_counter.hh => src/base/sat_counter.hh rename : base/sched_list.hh => src/base/sched_list.hh rename : base/socket.cc => src/base/socket.cc rename : base/socket.hh => src/base/socket.hh rename : base/statistics.cc => src/base/statistics.cc rename : base/statistics.hh => src/base/statistics.hh rename : base/stats/events.cc => src/base/stats/events.cc rename : base/stats/events.hh => src/base/stats/events.hh rename : base/stats/flags.hh => src/base/stats/flags.hh rename : base/stats/mysql.cc => src/base/stats/mysql.cc rename : base/stats/mysql.hh => src/base/stats/mysql.hh rename : base/stats/mysql_run.hh => src/base/stats/mysql_run.hh rename : base/stats/output.hh => src/base/stats/output.hh rename : base/stats/statdb.cc => src/base/stats/statdb.cc rename : base/stats/statdb.hh => src/base/stats/statdb.hh rename : base/stats/text.cc => src/base/stats/text.cc rename : base/stats/text.hh => src/base/stats/text.hh rename : base/stats/types.hh => src/base/stats/types.hh rename : base/stats/visit.cc => src/base/stats/visit.cc rename : base/stats/visit.hh => src/base/stats/visit.hh rename : base/str.cc => src/base/str.cc rename : base/str.hh => src/base/str.hh rename : base/time.cc => src/base/time.cc rename : base/time.hh => src/base/time.hh rename : base/timebuf.hh => src/base/timebuf.hh rename : base/trace.cc => src/base/trace.cc rename : base/trace.hh => src/base/trace.hh rename : base/traceflags.py => src/base/traceflags.py rename : base/userinfo.cc => src/base/userinfo.cc rename : base/userinfo.hh => src/base/userinfo.hh rename : cpu/SConscript => src/cpu/SConscript rename : cpu/base.cc => src/cpu/base.cc rename : cpu/base.hh => src/cpu/base.hh rename : cpu/base_dyn_inst.cc => src/cpu/base_dyn_inst.cc rename : cpu/base_dyn_inst.hh => src/cpu/base_dyn_inst.hh rename : cpu/cpu_exec_context.cc => src/cpu/cpu_exec_context.cc rename : cpu/cpu_exec_context.hh => src/cpu/cpu_exec_context.hh rename : cpu/cpu_models.py => src/cpu/cpu_models.py rename : cpu/exec_context.hh => src/cpu/exec_context.hh rename : cpu/exetrace.cc => src/cpu/exetrace.cc rename : cpu/exetrace.hh => src/cpu/exetrace.hh rename : cpu/inst_seq.hh => src/cpu/inst_seq.hh rename : cpu/intr_control.cc => src/cpu/intr_control.cc rename : cpu/intr_control.hh => src/cpu/intr_control.hh rename : cpu/memtest/memtest.cc => src/cpu/memtest/memtest.cc rename : cpu/memtest/memtest.hh => src/cpu/memtest/memtest.hh rename : cpu/o3/2bit_local_pred.cc => src/cpu/o3/2bit_local_pred.cc rename : cpu/o3/2bit_local_pred.hh => src/cpu/o3/2bit_local_pred.hh rename : cpu/o3/alpha_cpu.cc => src/cpu/o3/alpha_cpu.cc rename : cpu/o3/alpha_cpu.hh => src/cpu/o3/alpha_cpu.hh rename : cpu/o3/alpha_cpu_builder.cc => src/cpu/o3/alpha_cpu_builder.cc rename : cpu/o3/alpha_cpu_impl.hh => src/cpu/o3/alpha_cpu_impl.hh rename : cpu/o3/alpha_dyn_inst.cc => src/cpu/o3/alpha_dyn_inst.cc rename : cpu/o3/alpha_dyn_inst.hh => src/cpu/o3/alpha_dyn_inst.hh rename : cpu/o3/alpha_dyn_inst_impl.hh => src/cpu/o3/alpha_dyn_inst_impl.hh rename : cpu/o3/alpha_impl.hh => src/cpu/o3/alpha_impl.hh rename : cpu/o3/alpha_params.hh => src/cpu/o3/alpha_params.hh rename : cpu/o3/bpred_unit.cc => src/cpu/o3/bpred_unit.cc rename : cpu/o3/bpred_unit.hh => src/cpu/o3/bpred_unit.hh rename : cpu/o3/bpred_unit_impl.hh => src/cpu/o3/bpred_unit_impl.hh rename : cpu/o3/btb.cc => src/cpu/o3/btb.cc rename : cpu/o3/btb.hh => src/cpu/o3/btb.hh rename : cpu/o3/comm.hh => src/cpu/o3/comm.hh rename : cpu/o3/commit.cc => src/cpu/o3/commit.cc rename : cpu/o3/commit.hh => src/cpu/o3/commit.hh rename : cpu/o3/commit_impl.hh => src/cpu/o3/commit_impl.hh rename : cpu/o3/cpu.cc => src/cpu/o3/cpu.cc rename : cpu/o3/cpu.hh => src/cpu/o3/cpu.hh rename : cpu/o3/cpu_policy.hh => src/cpu/o3/cpu_policy.hh rename : cpu/o3/decode.cc => src/cpu/o3/decode.cc rename : cpu/o3/decode.hh => src/cpu/o3/decode.hh rename : cpu/o3/decode_impl.hh => src/cpu/o3/decode_impl.hh rename : cpu/o3/fetch.cc => src/cpu/o3/fetch.cc rename : cpu/o3/fetch.hh => src/cpu/o3/fetch.hh rename : cpu/o3/fetch_impl.hh => src/cpu/o3/fetch_impl.hh rename : cpu/o3/free_list.cc => src/cpu/o3/free_list.cc rename : cpu/o3/free_list.hh => src/cpu/o3/free_list.hh rename : cpu/o3/iew.cc => src/cpu/o3/iew.cc rename : cpu/o3/iew.hh => src/cpu/o3/iew.hh rename : cpu/o3/iew_impl.hh => src/cpu/o3/iew_impl.hh rename : cpu/o3/inst_queue.cc => src/cpu/o3/inst_queue.cc rename : cpu/o3/inst_queue.hh => src/cpu/o3/inst_queue.hh rename : cpu/o3/inst_queue_impl.hh => src/cpu/o3/inst_queue_impl.hh rename : cpu/o3/mem_dep_unit.cc => src/cpu/o3/mem_dep_unit.cc rename : cpu/o3/mem_dep_unit.hh => src/cpu/o3/mem_dep_unit.hh rename : cpu/o3/mem_dep_unit_impl.hh => src/cpu/o3/mem_dep_unit_impl.hh rename : cpu/o3/ras.cc => src/cpu/o3/ras.cc rename : cpu/o3/ras.hh => src/cpu/o3/ras.hh rename : cpu/o3/regfile.hh => src/cpu/o3/regfile.hh rename : cpu/o3/rename.cc => src/cpu/o3/rename.cc rename : cpu/o3/rename.hh => src/cpu/o3/rename.hh rename : cpu/o3/rename_impl.hh => src/cpu/o3/rename_impl.hh rename : cpu/o3/rename_map.cc => src/cpu/o3/rename_map.cc rename : cpu/o3/rename_map.hh => src/cpu/o3/rename_map.hh rename : cpu/o3/rob.cc => src/cpu/o3/rob.cc rename : cpu/o3/rob.hh => src/cpu/o3/rob.hh rename : cpu/o3/rob_impl.hh => src/cpu/o3/rob_impl.hh rename : cpu/o3/sat_counter.cc => src/cpu/o3/sat_counter.cc rename : cpu/o3/sat_counter.hh => src/cpu/o3/sat_counter.hh rename : cpu/o3/store_set.cc => src/cpu/o3/store_set.cc rename : cpu/o3/store_set.hh => src/cpu/o3/store_set.hh rename : cpu/o3/tournament_pred.cc => src/cpu/o3/tournament_pred.cc rename : cpu/o3/tournament_pred.hh => src/cpu/o3/tournament_pred.hh rename : cpu/op_class.cc => src/cpu/op_class.cc rename : cpu/op_class.hh => src/cpu/op_class.hh rename : cpu/ozone/cpu.cc => src/cpu/ozone/cpu.cc rename : cpu/ozone/cpu.hh => src/cpu/ozone/cpu.hh rename : cpu/ozone/cpu_impl.hh => src/cpu/ozone/cpu_impl.hh rename : cpu/ozone/ea_list.cc => src/cpu/ozone/ea_list.cc rename : cpu/ozone/ea_list.hh => src/cpu/ozone/ea_list.hh rename : cpu/pc_event.cc => src/cpu/pc_event.cc rename : cpu/pc_event.hh => src/cpu/pc_event.hh rename : cpu/profile.cc => src/cpu/profile.cc rename : cpu/profile.hh => src/cpu/profile.hh rename : cpu/simple/atomic.cc => src/cpu/simple/atomic.cc rename : cpu/simple/atomic.hh => src/cpu/simple/atomic.hh rename : cpu/simple/base.cc => src/cpu/simple/base.cc rename : cpu/simple/base.hh => src/cpu/simple/base.hh rename : cpu/simple/timing.cc => src/cpu/simple/timing.cc rename : cpu/simple/timing.hh => src/cpu/simple/timing.hh rename : cpu/smt.hh => src/cpu/smt.hh rename : cpu/static_inst.cc => src/cpu/static_inst.cc rename : cpu/static_inst.hh => src/cpu/static_inst.hh rename : cpu/trace/opt_cpu.cc => src/cpu/trace/opt_cpu.cc rename : cpu/trace/opt_cpu.hh => src/cpu/trace/opt_cpu.hh rename : cpu/trace/reader/ibm_reader.cc => src/cpu/trace/reader/ibm_reader.cc rename : cpu/trace/reader/ibm_reader.hh => src/cpu/trace/reader/ibm_reader.hh rename : cpu/trace/reader/itx_reader.cc => src/cpu/trace/reader/itx_reader.cc rename : cpu/trace/reader/itx_reader.hh => src/cpu/trace/reader/itx_reader.hh rename : cpu/trace/reader/m5_reader.cc => src/cpu/trace/reader/m5_reader.cc rename : cpu/trace/reader/m5_reader.hh => src/cpu/trace/reader/m5_reader.hh rename : cpu/trace/reader/mem_trace_reader.cc => src/cpu/trace/reader/mem_trace_reader.cc rename : cpu/trace/reader/mem_trace_reader.hh => src/cpu/trace/reader/mem_trace_reader.hh rename : cpu/trace/trace_cpu.cc => src/cpu/trace/trace_cpu.cc rename : cpu/trace/trace_cpu.hh => src/cpu/trace/trace_cpu.hh rename : dev/alpha_access.h => src/dev/alpha_access.h rename : dev/alpha_console.cc => src/dev/alpha_console.cc rename : dev/alpha_console.hh => src/dev/alpha_console.hh rename : dev/baddev.cc => src/dev/baddev.cc rename : dev/baddev.hh => src/dev/baddev.hh rename : dev/disk_image.cc => src/dev/disk_image.cc rename : dev/disk_image.hh => src/dev/disk_image.hh rename : dev/etherbus.cc => src/dev/etherbus.cc rename : dev/etherbus.hh => src/dev/etherbus.hh rename : dev/etherdump.cc => src/dev/etherdump.cc rename : dev/etherdump.hh => src/dev/etherdump.hh rename : dev/etherint.cc => src/dev/etherint.cc rename : dev/etherint.hh => src/dev/etherint.hh rename : dev/etherlink.cc => src/dev/etherlink.cc rename : dev/etherlink.hh => src/dev/etherlink.hh rename : dev/etherpkt.cc => src/dev/etherpkt.cc rename : dev/etherpkt.hh => src/dev/etherpkt.hh rename : dev/ethertap.cc => src/dev/ethertap.cc rename : dev/ethertap.hh => src/dev/ethertap.hh rename : dev/ide_atareg.h => src/dev/ide_atareg.h rename : dev/ide_ctrl.cc => src/dev/ide_ctrl.cc rename : dev/ide_ctrl.hh => src/dev/ide_ctrl.hh rename : dev/ide_disk.cc => src/dev/ide_disk.cc rename : dev/ide_disk.hh => src/dev/ide_disk.hh rename : dev/ide_wdcreg.h => src/dev/ide_wdcreg.h rename : dev/io_device.cc => src/dev/io_device.cc rename : dev/io_device.hh => src/dev/io_device.hh rename : dev/isa_fake.cc => src/dev/isa_fake.cc rename : dev/isa_fake.hh => src/dev/isa_fake.hh rename : dev/ns_gige.cc => src/dev/ns_gige.cc rename : dev/ns_gige.hh => src/dev/ns_gige.hh rename : dev/ns_gige_reg.h => src/dev/ns_gige_reg.h rename : dev/pciconfigall.cc => src/dev/pciconfigall.cc rename : dev/pciconfigall.hh => src/dev/pciconfigall.hh rename : dev/pcidev.cc => src/dev/pcidev.cc rename : dev/pcidev.hh => src/dev/pcidev.hh rename : dev/pcireg.h => src/dev/pcireg.h rename : dev/pitreg.h => src/dev/pitreg.h rename : dev/pktfifo.cc => src/dev/pktfifo.cc rename : dev/pktfifo.hh => src/dev/pktfifo.hh rename : dev/platform.cc => src/dev/platform.cc rename : dev/platform.hh => src/dev/platform.hh rename : dev/rtcreg.h => src/dev/rtcreg.h rename : dev/simconsole.cc => src/dev/simconsole.cc rename : dev/simconsole.hh => src/dev/simconsole.hh rename : dev/simple_disk.cc => src/dev/simple_disk.cc rename : dev/simple_disk.hh => src/dev/simple_disk.hh rename : dev/sinic.cc => src/dev/sinic.cc rename : dev/sinic.hh => src/dev/sinic.hh rename : dev/sinicreg.hh => src/dev/sinicreg.hh rename : dev/tsunami.cc => src/dev/tsunami.cc rename : dev/tsunami.hh => src/dev/tsunami.hh rename : dev/tsunami_cchip.cc => src/dev/tsunami_cchip.cc rename : dev/tsunami_cchip.hh => src/dev/tsunami_cchip.hh rename : dev/tsunami_io.cc => src/dev/tsunami_io.cc rename : dev/tsunami_io.hh => src/dev/tsunami_io.hh rename : dev/tsunami_pchip.cc => src/dev/tsunami_pchip.cc rename : dev/tsunami_pchip.hh => src/dev/tsunami_pchip.hh rename : dev/tsunamireg.h => src/dev/tsunamireg.h rename : dev/uart.cc => src/dev/uart.cc rename : dev/uart.hh => src/dev/uart.hh rename : dev/uart8250.cc => src/dev/uart8250.cc rename : dev/uart8250.hh => src/dev/uart8250.hh rename : kern/kernel_stats.cc => src/kern/kernel_stats.cc rename : kern/kernel_stats.hh => src/kern/kernel_stats.hh rename : kern/linux/events.cc => src/kern/linux/events.cc rename : kern/linux/events.hh => src/kern/linux/events.hh rename : kern/linux/linux.hh => src/kern/linux/linux.hh rename : kern/linux/linux_syscalls.cc => src/kern/linux/linux_syscalls.cc rename : kern/linux/linux_syscalls.hh => src/kern/linux/linux_syscalls.hh rename : kern/linux/printk.cc => src/kern/linux/printk.cc rename : kern/linux/printk.hh => src/kern/linux/printk.hh rename : kern/linux/sched.hh => src/kern/linux/sched.hh rename : kern/solaris/solaris.hh => src/kern/solaris/solaris.hh rename : kern/system_events.cc => src/kern/system_events.cc rename : kern/system_events.hh => src/kern/system_events.hh rename : kern/tru64/dump_mbuf.cc => src/kern/tru64/dump_mbuf.cc rename : kern/tru64/dump_mbuf.hh => src/kern/tru64/dump_mbuf.hh rename : kern/tru64/mbuf.hh => src/kern/tru64/mbuf.hh rename : kern/tru64/printf.cc => src/kern/tru64/printf.cc rename : kern/tru64/printf.hh => src/kern/tru64/printf.hh rename : kern/tru64/tru64.hh => src/kern/tru64/tru64.hh rename : kern/tru64/tru64_events.cc => src/kern/tru64/tru64_events.cc rename : kern/tru64/tru64_events.hh => src/kern/tru64/tru64_events.hh rename : kern/tru64/tru64_syscalls.cc => src/kern/tru64/tru64_syscalls.cc rename : kern/tru64/tru64_syscalls.hh => src/kern/tru64/tru64_syscalls.hh rename : mem/bridge.cc => src/mem/bridge.cc rename : mem/bridge.hh => src/mem/bridge.hh rename : mem/bus.cc => src/mem/bus.cc rename : mem/bus.hh => src/mem/bus.hh rename : mem/cache/prefetch/tagged_prefetcher_impl.hh => src/mem/cache/prefetch/tagged_prefetcher_impl.hh rename : mem/config/prefetch.hh => src/mem/config/prefetch.hh rename : mem/mem_object.cc => src/mem/mem_object.cc rename : mem/mem_object.hh => src/mem/mem_object.hh rename : mem/packet.cc => src/mem/packet.cc rename : mem/packet.hh => src/mem/packet.hh rename : mem/page_table.cc => src/mem/page_table.cc rename : mem/page_table.hh => src/mem/page_table.hh rename : mem/physical.cc => src/mem/physical.cc rename : mem/physical.hh => src/mem/physical.hh rename : mem/port.cc => src/mem/port.cc rename : mem/port.hh => src/mem/port.hh rename : mem/request.hh => src/mem/request.hh rename : mem/translating_port.cc => src/mem/translating_port.cc rename : mem/translating_port.hh => src/mem/translating_port.hh rename : mem/vport.cc => src/mem/vport.cc rename : mem/vport.hh => src/mem/vport.hh rename : python/SConscript => src/python/SConscript rename : python/m5/__init__.py => src/python/m5/__init__.py rename : python/m5/config.py => src/python/m5/config.py rename : python/m5/convert.py => src/python/m5/convert.py rename : python/m5/multidict.py => src/python/m5/multidict.py rename : python/m5/objects/AlphaConsole.py => src/python/m5/objects/AlphaConsole.py rename : python/m5/objects/AlphaFullCPU.py => src/python/m5/objects/AlphaFullCPU.py rename : python/m5/objects/AlphaTLB.py => src/python/m5/objects/AlphaTLB.py rename : python/m5/objects/BadDevice.py => src/python/m5/objects/BadDevice.py rename : python/m5/objects/BaseCPU.py => src/python/m5/objects/BaseCPU.py rename : python/m5/objects/BaseCache.py => src/python/m5/objects/BaseCache.py rename : python/m5/objects/Bridge.py => src/python/m5/objects/Bridge.py rename : python/m5/objects/Bus.py => src/python/m5/objects/Bus.py rename : python/m5/objects/CoherenceProtocol.py => src/python/m5/objects/CoherenceProtocol.py rename : python/m5/objects/Device.py => src/python/m5/objects/Device.py rename : python/m5/objects/DiskImage.py => src/python/m5/objects/DiskImage.py rename : python/m5/objects/Ethernet.py => src/python/m5/objects/Ethernet.py rename : python/m5/objects/Ide.py => src/python/m5/objects/Ide.py rename : python/m5/objects/IntrControl.py => src/python/m5/objects/IntrControl.py rename : python/m5/objects/MemObject.py => src/python/m5/objects/MemObject.py rename : python/m5/objects/MemTest.py => src/python/m5/objects/MemTest.py rename : python/m5/objects/Pci.py => src/python/m5/objects/Pci.py rename : python/m5/objects/PhysicalMemory.py => src/python/m5/objects/PhysicalMemory.py rename : python/m5/objects/Platform.py => src/python/m5/objects/Platform.py rename : python/m5/objects/Process.py => src/python/m5/objects/Process.py rename : python/m5/objects/Repl.py => src/python/m5/objects/Repl.py rename : python/m5/objects/Root.py => src/python/m5/objects/Root.py rename : python/m5/objects/SimConsole.py => src/python/m5/objects/SimConsole.py rename : python/m5/objects/SimpleDisk.py => src/python/m5/objects/SimpleDisk.py rename : python/m5/objects/System.py => src/python/m5/objects/System.py rename : python/m5/objects/Tsunami.py => src/python/m5/objects/Tsunami.py rename : python/m5/objects/Uart.py => src/python/m5/objects/Uart.py rename : python/m5/smartdict.py => src/python/m5/smartdict.py rename : sim/async.hh => src/sim/async.hh rename : sim/builder.cc => src/sim/builder.cc rename : sim/builder.hh => src/sim/builder.hh rename : sim/byteswap.hh => src/sim/byteswap.hh rename : sim/debug.cc => src/sim/debug.cc rename : sim/debug.hh => src/sim/debug.hh rename : sim/eventq.cc => src/sim/eventq.cc rename : sim/eventq.hh => src/sim/eventq.hh rename : sim/faults.cc => src/sim/faults.cc rename : sim/faults.hh => src/sim/faults.hh rename : sim/host.hh => src/sim/host.hh rename : sim/main.cc => src/sim/main.cc rename : sim/param.cc => src/sim/param.cc rename : sim/param.hh => src/sim/param.hh rename : sim/process.cc => src/sim/process.cc rename : sim/process.hh => src/sim/process.hh rename : sim/pseudo_inst.cc => src/sim/pseudo_inst.cc rename : sim/pseudo_inst.hh => src/sim/pseudo_inst.hh rename : sim/root.cc => src/sim/root.cc rename : sim/serialize.cc => src/sim/serialize.cc rename : sim/serialize.hh => src/sim/serialize.hh rename : sim/sim_events.cc => src/sim/sim_events.cc rename : sim/sim_events.hh => src/sim/sim_events.hh rename : sim/sim_exit.hh => src/sim/sim_exit.hh rename : sim/sim_object.cc => src/sim/sim_object.cc rename : sim/sim_object.hh => src/sim/sim_object.hh rename : sim/startup.cc => src/sim/startup.cc rename : sim/startup.hh => src/sim/startup.hh rename : sim/stat_control.cc => src/sim/stat_control.cc rename : sim/stat_control.hh => src/sim/stat_control.hh rename : sim/stats.hh => src/sim/stats.hh rename : sim/syscall_emul.cc => src/sim/syscall_emul.cc rename : sim/syscall_emul.hh => src/sim/syscall_emul.hh rename : sim/system.cc => src/sim/system.cc rename : sim/system.hh => src/sim/system.hh rename : sim/vptr.hh => src/sim/vptr.hh rename : test/Makefile => src/unittest/Makefile rename : test/bitvectest.cc => src/unittest/bitvectest.cc rename : test/circletest.cc => src/unittest/circletest.cc rename : test/cprintftest.cc => src/unittest/cprintftest.cc rename : test/foo.ini => src/unittest/foo.ini rename : test/genini.py => src/unittest/genini.py rename : test/initest.cc => src/unittest/initest.cc rename : test/initest.ini => src/unittest/initest.ini rename : test/lru_test.cc => src/unittest/lru_test.cc rename : test/nmtest.cc => src/unittest/nmtest.cc rename : test/offtest.cc => src/unittest/offtest.cc rename : test/paramtest.cc => src/unittest/paramtest.cc rename : test/rangetest.cc => src/unittest/rangetest.cc rename : test/sized_test.cc => src/unittest/sized_test.cc rename : test/stattest.cc => src/unittest/stattest.cc rename : test/strnumtest.cc => src/unittest/strnumtest.cc rename : test/symtest.cc => src/unittest/symtest.cc rename : test/tokentest.cc => src/unittest/tokentest.cc rename : test/tracetest.cc => src/unittest/tracetest.cc extra : convert_revision : cab6a5271ca1b368193cd948e5d3dcc47ab1bd48
Diffstat (limited to 'src')
-rw-r--r--src/Doxyfile1127
-rw-r--r--src/SConscript402
-rw-r--r--src/arch/SConscript150
-rw-r--r--src/arch/alpha/SConscript93
-rw-r--r--src/arch/alpha/aout_machdep.h67
-rw-r--r--src/arch/alpha/arguments.cc68
-rw-r--r--src/arch/alpha/arguments.hh147
-rw-r--r--src/arch/alpha/ecoff_machdep.h73
-rw-r--r--src/arch/alpha/ev5.cc577
-rw-r--r--src/arch/alpha/ev5.hh121
-rw-r--r--src/arch/alpha/faults.cc176
-rw-r--r--src/arch/alpha/faults.hh352
-rw-r--r--src/arch/alpha/freebsd/system.cc156
-rw-r--r--src/arch/alpha/freebsd/system.hh56
-rw-r--r--src/arch/alpha/isa/branch.isa259
-rw-r--r--src/arch/alpha/isa/decoder.isa819
-rw-r--r--src/arch/alpha/isa/fp.isa301
-rw-r--r--src/arch/alpha/isa/int.isa128
-rw-r--r--src/arch/alpha/isa/main.isa449
-rw-r--r--src/arch/alpha/isa/mem.isa729
-rw-r--r--src/arch/alpha/isa/opcdec.isa72
-rw-r--r--src/arch/alpha/isa/pal.isa271
-rw-r--r--src/arch/alpha/isa/unimp.isa165
-rw-r--r--src/arch/alpha/isa/unknown.isa52
-rw-r--r--src/arch/alpha/isa/util.isa112
-rw-r--r--src/arch/alpha/isa_traits.hh112
-rw-r--r--src/arch/alpha/linux/aligned.hh47
-rw-r--r--src/arch/alpha/linux/hwrpb.hh42
-rw-r--r--src/arch/alpha/linux/linux.cc70
-rw-r--r--src/arch/alpha/linux/linux.hh128
-rw-r--r--src/arch/alpha/linux/process.cc591
-rw-r--r--src/arch/alpha/linux/process.hh60
-rw-r--r--src/arch/alpha/linux/system.cc265
-rw-r--r--src/arch/alpha/linux/system.hh145
-rw-r--r--src/arch/alpha/linux/thread_info.hh41
-rw-r--r--src/arch/alpha/linux/threadinfo.hh89
-rw-r--r--src/arch/alpha/osfpal.cc304
-rw-r--r--src/arch/alpha/osfpal.hh80
-rw-r--r--src/arch/alpha/process.cc167
-rw-r--r--src/arch/alpha/process.hh64
-rw-r--r--src/arch/alpha/regfile.hh278
-rw-r--r--src/arch/alpha/stacktrace.cc344
-rw-r--r--src/arch/alpha/stacktrace.hh119
-rw-r--r--src/arch/alpha/system.cc280
-rw-r--r--src/arch/alpha/system.hh108
-rw-r--r--src/arch/alpha/tlb.cc628
-rw-r--r--src/arch/alpha/tlb.hh121
-rw-r--r--src/arch/alpha/tru64/process.cc586
-rw-r--r--src/arch/alpha/tru64/process.hh61
-rw-r--r--src/arch/alpha/tru64/system.cc151
-rw-r--r--src/arch/alpha/tru64/system.hh71
-rw-r--r--src/arch/alpha/tru64/tru64.cc70
-rw-r--r--src/arch/alpha/tru64/tru64.hh127
-rw-r--r--src/arch/alpha/types.hh64
-rw-r--r--src/arch/alpha/utility.hh156
-rw-r--r--src/arch/alpha/vtophys.cc162
-rw-r--r--src/arch/alpha/vtophys.hh52
-rwxr-xr-xsrc/arch/isa_parser.py1810
-rw-r--r--src/arch/isa_specific.hh62
-rw-r--r--src/arch/mips/SConscript83
-rw-r--r--src/arch/mips/faults.cc131
-rw-r--r--src/arch/mips/faults.hh269
-rw-r--r--src/arch/mips/isa/base.isa88
-rw-r--r--src/arch/mips/isa/bitfields.isa71
-rw-r--r--src/arch/mips/isa/decoder.isa1688
-rw-r--r--src/arch/mips/isa/formats/basic.isa66
-rw-r--r--src/arch/mips/isa/formats/branch.isa324
-rw-r--r--src/arch/mips/isa/formats/formats.isa35
-rw-r--r--src/arch/mips/isa/formats/fp.isa109
-rw-r--r--src/arch/mips/isa/formats/int.isa131
-rw-r--r--src/arch/mips/isa/formats/mem.isa473
-rw-r--r--src/arch/mips/isa/formats/noop.isa94
-rw-r--r--src/arch/mips/isa/formats/tlbop.isa53
-rw-r--r--src/arch/mips/isa/formats/trap.isa52
-rw-r--r--src/arch/mips/isa/formats/unimp.isa166
-rw-r--r--src/arch/mips/isa/formats/unknown.isa74
-rw-r--r--src/arch/mips/isa/formats/util.isa129
-rw-r--r--src/arch/mips/isa/includes.isa48
-rw-r--r--src/arch/mips/isa/main.isa52
-rw-r--r--src/arch/mips/isa/operands.isa61
-rw-r--r--src/arch/mips/isa_traits.cc229
-rw-r--r--src/arch/mips/isa_traits.hh199
-rw-r--r--src/arch/mips/linux/linux.cc72
-rw-r--r--src/arch/mips/linux/linux.hh126
-rw-r--r--src/arch/mips/linux/process.cc429
-rw-r--r--src/arch/mips/linux/process.hh59
-rw-r--r--src/arch/mips/process.cc161
-rw-r--r--src/arch/mips/process.hh64
-rw-r--r--src/arch/mips/regfile/float_regfile.hh159
-rw-r--r--src/arch/mips/regfile/int_regfile.hh73
-rw-r--r--src/arch/mips/regfile/misc_regfile.hh96
-rw-r--r--src/arch/mips/regfile/regfile.hh199
-rw-r--r--src/arch/mips/stacktrace.hh119
-rw-r--r--src/arch/mips/types.hh92
-rw-r--r--src/arch/mips/utility.hh44
-rw-r--r--src/arch/sparc/SConscript84
-rw-r--r--src/arch/sparc/faults.cc255
-rw-r--r--src/arch/sparc/faults.hh591
-rw-r--r--src/arch/sparc/isa/base.isa252
-rw-r--r--src/arch/sparc/isa/bitfields.isa78
-rw-r--r--src/arch/sparc/isa/decoder.isa721
-rw-r--r--src/arch/sparc/isa/formats.isa28
-rw-r--r--src/arch/sparc/isa/formats/basic.isa97
-rw-r--r--src/arch/sparc/isa/formats/branch.isa337
-rw-r--r--src/arch/sparc/isa/formats/integerop.isa379
-rw-r--r--src/arch/sparc/isa/formats/mem.isa171
-rw-r--r--src/arch/sparc/isa/formats/nop.isa91
-rw-r--r--src/arch/sparc/isa/formats/priv.isa169
-rw-r--r--src/arch/sparc/isa/formats/trap.isa93
-rw-r--r--src/arch/sparc/isa/formats/unknown.isa75
-rw-r--r--src/arch/sparc/isa/includes.isa76
-rw-r--r--src/arch/sparc/isa/main.isa52
-rw-r--r--src/arch/sparc/isa/operands.isa145
-rw-r--r--src/arch/sparc/isa_traits.hh187
-rw-r--r--src/arch/sparc/linux/linux.cc68
-rw-r--r--src/arch/sparc/linux/linux.hh61
-rw-r--r--src/arch/sparc/linux/process.cc407
-rw-r--r--src/arch/sparc/linux/process.hh65
-rw-r--r--src/arch/sparc/process.cc388
-rw-r--r--src/arch/sparc/process.hh79
-rw-r--r--src/arch/sparc/regfile.hh812
-rw-r--r--src/arch/sparc/solaris/process.cc347
-rw-r--r--src/arch/sparc/solaris/process.hh63
-rw-r--r--src/arch/sparc/solaris/solaris.cc74
-rw-r--r--src/arch/sparc/solaris/solaris.hh62
-rw-r--r--src/arch/sparc/stacktrace.hh119
-rw-r--r--src/arch/sparc/system.cc200
-rw-r--r--src/arch/sparc/system.hh114
-rw-r--r--src/arch/sparc/utility.hh89
-rw-r--r--src/base/bitfield.hh69
-rw-r--r--src/base/callback.hh122
-rw-r--r--src/base/chunk_generator.hh141
-rw-r--r--src/base/circlebuf.cc213
-rw-r--r--src/base/circlebuf.hh62
-rw-r--r--src/base/compression/lzss_compression.cc171
-rw-r--r--src/base/compression/lzss_compression.hh101
-rw-r--r--src/base/compression/null_compression.hh76
-rw-r--r--src/base/cprintf.cc268
-rw-r--r--src/base/cprintf.hh197
-rw-r--r--src/base/cprintf_formats.hh353
-rw-r--r--src/base/crc.cc114
-rw-r--r--src/base/crc.hh37
-rw-r--r--src/base/date.cc29
-rw-r--r--src/base/dbl_list.hh165
-rw-r--r--src/base/endian.hh41
-rw-r--r--src/base/fast_alloc.cc195
-rw-r--r--src/base/fast_alloc.hh214
-rw-r--r--src/base/fenv.hh52
-rw-r--r--src/base/fifo_buffer.cc40
-rw-r--r--src/base/fifo_buffer.hh86
-rw-r--r--src/base/hashmap.hh85
-rw-r--r--src/base/hostinfo.cc85
-rw-r--r--src/base/hostinfo.hh43
-rw-r--r--src/base/hybrid_pred.cc273
-rw-r--r--src/base/hybrid_pred.hh201
-rw-r--r--src/base/inet.cc207
-rw-r--r--src/base/inet.hh407
-rw-r--r--src/base/inifile.cc433
-rw-r--r--src/base/inifile.hh208
-rw-r--r--src/base/intmath.cc58
-rw-r--r--src/base/intmath.hh230
-rw-r--r--src/base/kgdb.h174
-rw-r--r--src/base/loader/aout_object.cc94
-rw-r--r--src/base/loader/aout_object.hh56
-rw-r--r--src/base/loader/coff_sym.h519
-rw-r--r--src/base/loader/coff_symconst.h200
-rw-r--r--src/base/loader/ecoff_object.cc153
-rw-r--r--src/base/loader/ecoff_object.hh60
-rw-r--r--src/base/loader/elf_object.cc315
-rw-r--r--src/base/loader/elf_object.hh55
-rw-r--r--src/base/loader/exec_aout.h61
-rw-r--r--src/base/loader/exec_ecoff.h110
-rw-r--r--src/base/loader/object_file.cc145
-rw-r--r--src/base/loader/object_file.hh119
-rw-r--r--src/base/loader/symtab.cc137
-rw-r--r--src/base/loader/symtab.hh173
-rw-r--r--src/base/match.cc96
-rw-r--r--src/base/match.hh57
-rw-r--r--src/base/misc.cc124
-rw-r--r--src/base/misc.hh85
-rw-r--r--src/base/mod_num.hh201
-rw-r--r--src/base/mysql.cc110
-rw-r--r--src/base/mysql.hh423
-rw-r--r--src/base/output.cc129
-rw-r--r--src/base/output.hh61
-rw-r--r--src/base/pollevent.cc273
-rw-r--r--src/base/pollevent.hh97
-rw-r--r--src/base/predictor.hh60
-rw-r--r--src/base/random.cc97
-rw-r--r--src/base/random.hh126
-rw-r--r--src/base/range.cc83
-rw-r--r--src/base/range.hh355
-rw-r--r--src/base/refcnt.hh123
-rw-r--r--src/base/remote_gdb.cc1175
-rw-r--r--src/base/remote_gdb.hh209
-rw-r--r--src/base/res_list.hh755
-rw-r--r--src/base/sat_counter.cc268
-rw-r--r--src/base/sat_counter.hh190
-rw-r--r--src/base/sched_list.hh178
-rw-r--r--src/base/socket.cc111
-rw-r--r--src/base/socket.hh49
-rw-r--r--src/base/statistics.cc356
-rw-r--r--src/base/statistics.hh2896
-rw-r--r--src/base/stats/events.cc169
-rw-r--r--src/base/stats/events.hh66
-rw-r--r--src/base/stats/flags.hh73
-rw-r--r--src/base/stats/mysql.cc900
-rw-r--r--src/base/stats/mysql.hh155
-rw-r--r--src/base/stats/mysql_run.hh65
-rw-r--r--src/base/stats/output.hh47
-rw-r--r--src/base/stats/statdb.cc93
-rw-r--r--src/base/stats/statdb.hh74
-rw-r--r--src/base/stats/text.cc736
-rw-r--r--src/base/stats/text.hh77
-rw-r--r--src/base/stats/types.hh49
-rw-r--r--src/base/stats/visit.cc41
-rw-r--r--src/base/stats/visit.hh63
-rw-r--r--src/base/str.cc373
-rw-r--r--src/base/str.hh141
-rw-r--r--src/base/time.cc131
-rw-r--r--src/base/time.hh65
-rw-r--r--src/base/timebuf.hh218
-rw-r--r--src/base/trace.cc350
-rw-r--r--src/base/trace.hh231
-rw-r--r--src/base/traceflags.py316
-rw-r--r--src/base/userinfo.cc41
-rw-r--r--src/base/userinfo.hh36
-rw-r--r--src/cpu/SConscript143
-rw-r--r--src/cpu/base.cc398
-rw-r--r--src/cpu/base.hh241
-rw-r--r--src/cpu/base_dyn_inst.cc364
-rw-r--r--src/cpu/base_dyn_inst.hh530
-rw-r--r--src/cpu/cpu_exec_context.cc320
-rw-r--r--src/cpu/cpu_exec_context.hh546
-rw-r--r--src/cpu/cpu_models.py74
-rw-r--r--src/cpu/exec_context.hh450
-rw-r--r--src/cpu/exetrace.cc226
-rw-r--r--src/cpu/exetrace.hh188
-rw-r--r--src/cpu/inst_seq.hh40
-rw-r--r--src/cpu/intr_control.cc97
-rw-r--r--src/cpu/intr_control.hh58
-rw-r--r--src/cpu/memtest/memtest.cc440
-rw-r--r--src/cpu/memtest/memtest.hh156
-rw-r--r--src/cpu/o3/2bit_local_pred.cc129
-rw-r--r--src/cpu/o3/2bit_local_pred.hh86
-rw-r--r--src/cpu/o3/alpha_cpu.cc36
-rw-r--r--src/cpu/o3/alpha_cpu.hh291
-rw-r--r--src/cpu/o3/alpha_cpu_builder.cc392
-rw-r--r--src/cpu/o3/alpha_cpu_impl.hh371
-rw-r--r--src/cpu/o3/alpha_dyn_inst.cc34
-rw-r--r--src/cpu/o3/alpha_dyn_inst.hh264
-rw-r--r--src/cpu/o3/alpha_dyn_inst_impl.hh120
-rw-r--r--src/cpu/o3/alpha_impl.hh79
-rw-r--r--src/cpu/o3/alpha_params.hh163
-rw-r--r--src/cpu/o3/bpred_unit.cc33
-rw-r--r--src/cpu/o3/bpred_unit.hh133
-rw-r--r--src/cpu/o3/bpred_unit_impl.hh276
-rw-r--r--src/cpu/o3/btb.cc120
-rw-r--r--src/cpu/o3/btb.hh80
-rw-r--r--src/cpu/o3/comm.hh163
-rw-r--r--src/cpu/o3/commit.cc33
-rw-r--r--src/cpu/o3/commit.hh180
-rw-r--r--src/cpu/o3/commit_impl.hh502
-rw-r--r--src/cpu/o3/cpu.cc566
-rw-r--r--src/cpu/o3/cpu.hh363
-rw-r--r--src/cpu/o3/cpu_policy.hh88
-rw-r--r--src/cpu/o3/decode.cc33
-rw-r--r--src/cpu/o3/decode.hh165
-rw-r--r--src/cpu/o3/decode_impl.hh425
-rw-r--r--src/cpu/o3/fetch.cc33
-rw-r--r--src/cpu/o3/fetch.hh223
-rw-r--r--src/cpu/o3/fetch_impl.hh617
-rw-r--r--src/cpu/o3/free_list.cc82
-rw-r--r--src/cpu/o3/free_list.hh195
-rw-r--r--src/cpu/o3/iew.cc34
-rw-r--r--src/cpu/o3/iew.hh239
-rw-r--r--src/cpu/o3/iew_impl.hh736
-rw-r--r--src/cpu/o3/inst_queue.cc38
-rw-r--r--src/cpu/o3/inst_queue.hh336
-rw-r--r--src/cpu/o3/inst_queue_impl.hh1136
-rw-r--r--src/cpu/o3/mem_dep_unit.cc36
-rw-r--r--src/cpu/o3/mem_dep_unit.hh164
-rw-r--r--src/cpu/o3/mem_dep_unit_impl.hh419
-rw-r--r--src/cpu/o3/ras.cc73
-rw-r--r--src/cpu/o3/ras.hh68
-rw-r--r--src/cpu/o3/regfile.hh299
-rw-r--r--src/cpu/o3/rename.cc33
-rw-r--r--src/cpu/o3/rename.hh233
-rw-r--r--src/cpu/o3/rename_impl.hh754
-rw-r--r--src/cpu/o3/rename_map.cc346
-rw-r--r--src/cpu/o3/rename_map.hh173
-rw-r--r--src/cpu/o3/rob.cc34
-rw-r--r--src/cpu/o3/rob.hh164
-rw-r--r--src/cpu/o3/rob_impl.hh312
-rw-r--r--src/cpu/o3/sat_counter.cc71
-rw-r--r--src/cpu/o3/sat_counter.hh90
-rw-r--r--src/cpu/o3/store_set.cc282
-rw-r--r--src/cpu/o3/store_set.hh86
-rw-r--r--src/cpu/o3/tournament_pred.cc256
-rw-r--r--src/cpu/o3/tournament_pred.hh143
-rw-r--r--src/cpu/op_class.cc50
-rw-r--r--src/cpu/op_class.hh64
-rw-r--r--src/cpu/ozone/cpu.cc33
-rw-r--r--src/cpu/ozone/cpu.hh638
-rw-r--r--src/cpu/ozone/cpu_impl.hh48
-rw-r--r--src/cpu/ozone/ea_list.cc77
-rw-r--r--src/cpu/ozone/ea_list.hh72
-rw-r--r--src/cpu/pc_event.cc155
-rw-r--r--src/cpu/pc_event.hh140
-rw-r--r--src/cpu/profile.cc155
-rw-r--r--src/cpu/profile.hh89
-rw-r--r--src/cpu/simple/atomic.cc560
-rw-r--r--src/cpu/simple/atomic.hh139
-rw-r--r--src/cpu/simple/base.cc478
-rw-r--r--src/cpu/simple/base.hh316
-rw-r--r--src/cpu/simple/timing.cc570
-rw-r--r--src/cpu/simple/timing.hh150
-rw-r--r--src/cpu/smt.hh59
-rw-r--r--src/cpu/static_inst.cc74
-rw-r--r--src/cpu/static_inst.hh475
-rw-r--r--src/cpu/trace/opt_cpu.cc239
-rw-r--r--src/cpu/trace/opt_cpu.hh223
-rw-r--r--src/cpu/trace/reader/ibm_reader.cc120
-rw-r--r--src/cpu/trace/reader/ibm_reader.hh73
-rw-r--r--src/cpu/trace/reader/itx_reader.cc206
-rw-r--r--src/cpu/trace/reader/itx_reader.hh84
-rw-r--r--src/cpu/trace/reader/m5_reader.cc97
-rw-r--r--src/cpu/trace/reader/m5_reader.hh67
-rw-r--r--src/cpu/trace/reader/mem_trace_reader.cc37
-rw-r--r--src/cpu/trace/reader/mem_trace_reader.hh57
-rw-r--r--src/cpu/trace/trace_cpu.cc179
-rw-r--r--src/cpu/trace/trace_cpu.hh140
-rw-r--r--src/dev/alpha_access.h73
-rw-r--r--src/dev/alpha_console.cc343
-rw-r--r--src/dev/alpha_console.hh129
-rw-r--r--src/dev/baddev.cc97
-rw-r--r--src/dev/baddev.hh72
-rw-r--r--src/dev/disk_image.cc470
-rw-r--r--src/dev/disk_image.hh133
-rw-r--r--src/dev/etherbus.cc125
-rw-r--r--src/dev/etherbus.hh79
-rw-r--r--src/dev/etherdump.cc136
-rw-r--r--src/dev/etherdump.hh59
-rw-r--r--src/dev/etherint.cc45
-rw-r--r--src/dev/etherint.hh66
-rw-r--r--src/dev/etherlink.cc300
-rw-r--r--src/dev/etherlink.hh130
-rw-r--r--src/dev/etherpkt.cc53
-rw-r--r--src/dev/etherpkt.hh84
-rw-r--r--src/dev/ethertap.cc345
-rw-r--r--src/dev/ethertap.hh107
-rw-r--r--src/dev/ide_atareg.h276
-rw-r--r--src/dev/ide_ctrl.cc814
-rw-r--r--src/dev/ide_ctrl.hh241
-rw-r--r--src/dev/ide_disk.cc1146
-rw-r--r--src/dev/ide_disk.hh367
-rw-r--r--src/dev/ide_wdcreg.h197
-rw-r--r--src/dev/io_device.cc238
-rw-r--r--src/dev/io_device.hh335
-rw-r--r--src/dev/isa_fake.cc121
-rw-r--r--src/dev/isa_fake.hh78
-rw-r--r--src/dev/ns_gige.cc2914
-rw-r--r--src/dev/ns_gige.hh463
-rw-r--r--src/dev/ns_gige_reg.h351
-rw-r--r--src/dev/pciconfigall.cc224
-rw-r--r--src/dev/pciconfigall.hh128
-rw-r--r--src/dev/pcidev.cc386
-rw-r--r--src/dev/pcidev.hh230
-rw-r--r--src/dev/pcireg.h156
-rw-r--r--src/dev/pitreg.h73
-rw-r--r--src/dev/pktfifo.cc99
-rw-r--r--src/dev/pktfifo.hh168
-rw-r--r--src/dev/platform.cc64
-rw-r--r--src/dev/platform.hh73
-rw-r--r--src/dev/rtcreg.h57
-rw-r--r--src/dev/simconsole.cc414
-rw-r--r--src/dev/simconsole.hh165
-rw-r--r--src/dev/simple_disk.cc111
-rw-r--r--src/dev/simple_disk.hh62
-rw-r--r--src/dev/sinic.cc1756
-rw-r--r--src/dev/sinic.hh371
-rw-r--r--src/dev/sinicreg.hh220
-rw-r--r--src/dev/tsunami.cc127
-rw-r--r--src/dev/tsunami.hh130
-rw-r--r--src/dev/tsunami_cchip.cc554
-rw-r--r--src/dev/tsunami_cchip.hh150
-rw-r--r--src/dev/tsunami_io.cc679
-rw-r--r--src/dev/tsunami_io.hh351
-rw-r--r--src/dev/tsunami_pchip.cc358
-rw-r--r--src/dev/tsunami_pchip.hh98
-rw-r--r--src/dev/tsunamireg.h171
-rw-r--r--src/dev/uart.cc52
-rw-r--r--src/dev/uart.hh79
-rw-r--r--src/dev/uart8250.cc366
-rw-r--r--src/dev/uart8250.hh105
-rw-r--r--src/kern/kernel_stats.cc299
-rw-r--r--src/kern/kernel_stats.hh192
-rw-r--r--src/kern/linux/events.cc55
-rw-r--r--src/kern/linux/events.hh50
-rw-r--r--src/kern/linux/linux.hh283
-rw-r--r--src/kern/linux/linux_syscalls.cc374
-rw-r--r--src/kern/linux/linux_syscalls.hh326
-rw-r--r--src/kern/linux/printk.cc261
-rw-r--r--src/kern/linux/printk.hh36
-rw-r--r--src/kern/linux/sched.hh45
-rw-r--r--src/kern/solaris/solaris.hh304
-rw-r--r--src/kern/system_events.cc91
-rw-r--r--src/kern/system_events.hh86
-rw-r--r--src/kern/tru64/dump_mbuf.cc78
-rw-r--r--src/kern/tru64/dump_mbuf.hh38
-rw-r--r--src/kern/tru64/mbuf.hh98
-rw-r--r--src/kern/tru64/printf.cc266
-rw-r--r--src/kern/tru64/printf.hh38
-rw-r--r--src/kern/tru64/tru64.hh1240
-rw-r--r--src/kern/tru64/tru64_events.cc105
-rw-r--r--src/kern/tru64/tru64_events.hh83
-rw-r--r--src/kern/tru64/tru64_syscalls.cc438
-rw-r--r--src/kern/tru64/tru64_syscalls.hh359
-rw-r--r--src/mem/bridge.cc263
-rw-r--r--src/mem/bridge.hh214
-rw-r--r--src/mem/bus.cc188
-rw-r--r--src/mem/bus.hh164
-rw-r--r--src/mem/cache/prefetch/tagged_prefetcher_impl.hh73
-rw-r--r--src/mem/config/prefetch.hh39
-rw-r--r--src/mem/mem_object.cc37
-rw-r--r--src/mem/mem_object.hh54
-rw-r--r--src/mem/packet.cc94
-rw-r--r--src/mem/packet.hh194
-rw-r--r--src/mem/page_table.cc134
-rw-r--r--src/mem/page_table.hh90
-rw-r--r--src/mem/physical.cc373
-rw-r--r--src/mem/physical.hh127
-rw-r--r--src/mem/port.cc78
-rw-r--r--src/mem/port.hh247
-rw-r--r--src/mem/request.hh200
-rw-r--r--src/mem/translating_port.cc186
-rw-r--r--src/mem/translating_port.hh64
-rw-r--r--src/mem/vport.cc69
-rw-r--r--src/mem/vport.hh76
-rw-r--r--src/python/SConscript207
-rw-r--r--src/python/m5/__init__.py74
-rw-r--r--src/python/m5/config.py1323
-rw-r--r--src/python/m5/convert.py227
-rw-r--r--src/python/m5/multidict.py184
-rw-r--r--src/python/m5/objects/AlphaConsole.py9
-rw-r--r--src/python/m5/objects/AlphaFullCPU.py80
-rw-r--r--src/python/m5/objects/AlphaTLB.py13
-rw-r--r--src/python/m5/objects/BadDevice.py6
-rw-r--r--src/python/m5/objects/BaseCPU.py27
-rw-r--r--src/python/m5/objects/BaseCache.py65
-rw-r--r--src/python/m5/objects/Bridge.py9
-rw-r--r--src/python/m5/objects/Bus.py6
-rw-r--r--src/python/m5/objects/CoherenceProtocol.py7
-rw-r--r--src/python/m5/objects/Device.py18
-rw-r--r--src/python/m5/objects/DiskImage.py15
-rw-r--r--src/python/m5/objects/Ethernet.py115
-rw-r--r--src/python/m5/objects/Ide.py14
-rw-r--r--src/python/m5/objects/IntrControl.py4
-rw-r--r--src/python/m5/objects/MemObject.py5
-rw-r--r--src/python/m5/objects/MemTest.py19
-rw-r--r--src/python/m5/objects/Pci.py55
-rw-r--r--src/python/m5/objects/PhysicalMemory.py8
-rw-r--r--src/python/m5/objects/Platform.py5
-rw-r--r--src/python/m5/objects/Process.py27
-rw-r--r--src/python/m5/objects/Repl.py10
-rw-r--r--src/python/m5/objects/Root.py23
-rw-r--r--src/python/m5/objects/SimConsole.py12
-rw-r--r--src/python/m5/objects/SimpleDisk.py5
-rw-r--r--src/python/m5/objects/System.py21
-rw-r--r--src/python/m5/objects/Tsunami.py27
-rw-r--r--src/python/m5/objects/Uart.py15
-rw-r--r--src/python/m5/smartdict.py152
-rw-r--r--src/sim/async.hh49
-rw-r--r--src/sim/builder.cc177
-rw-r--r--src/sim/builder.hh189
-rw-r--r--src/sim/byteswap.hh163
-rw-r--r--src/sim/debug.cc136
-rw-r--r--src/sim/debug.hh34
-rw-r--r--src/sim/eventq.cc258
-rw-r--r--src/sim/eventq.hh407
-rw-r--r--src/sim/faults.cc52
-rw-r--r--src/sim/faults.hh80
-rw-r--r--src/sim/host.hh67
-rw-r--r--src/sim/main.cc433
-rw-r--r--src/sim/param.cc793
-rw-r--r--src/sim/param.hh788
-rw-r--r--src/sim/process.cc361
-rw-r--r--src/sim/process.hh192
-rw-r--r--src/sim/pseudo_inst.cc284
-rw-r--r--src/sim/pseudo_inst.hh62
-rw-r--r--src/sim/root.cc156
-rw-r--r--src/sim/serialize.cc484
-rw-r--r--src/sim/serialize.hh243
-rw-r--r--src/sim/sim_events.cc148
-rw-r--r--src/sim/sim_events.hh126
-rw-r--r--src/sim/sim_exit.hh44
-rw-r--r--src/sim/sim_object.cc258
-rw-r--r--src/sim/sim_object.hh119
-rw-r--r--src/sim/startup.cc63
-rw-r--r--src/sim/startup.hh41
-rw-r--r--src/sim/stat_control.cc227
-rw-r--r--src/sim/stat_control.hh52
-rw-r--r--src/sim/stats.hh37
-rw-r--r--src/sim/syscall_emul.cc454
-rw-r--r--src/sim/syscall_emul.hh849
-rw-r--r--src/sim/system.cc265
-rw-r--r--src/sim/system.hh229
-rw-r--r--src/sim/vptr.hh122
-rw-r--r--src/unittest/Makefile98
-rw-r--r--src/unittest/bitvectest.cc66
-rw-r--r--src/unittest/circletest.cc72
-rw-r--r--src/unittest/cprintftest.cc163
-rw-r--r--src/unittest/foo.ini10
-rwxr-xr-xsrc/unittest/genini.py72
-rw-r--r--src/unittest/initest.cc142
-rw-r--r--src/unittest/initest.ini14
-rw-r--r--src/unittest/lru_test.cc82
-rw-r--r--src/unittest/nmtest.cc83
-rw-r--r--src/unittest/offtest.cc70
-rw-r--r--src/unittest/paramtest.cc105
-rw-r--r--src/unittest/rangetest.cc74
-rw-r--r--src/unittest/sized_test.cc67
-rw-r--r--src/unittest/stattest.cc560
-rw-r--r--src/unittest/strnumtest.cc76
-rw-r--r--src/unittest/symtest.cc77
-rw-r--r--src/unittest/tokentest.cc81
-rw-r--r--src/unittest/tracetest.cc54
527 files changed, 110701 insertions, 0 deletions
diff --git a/src/Doxyfile b/src/Doxyfile
new file mode 100644
index 000000000..38116f6b0
--- /dev/null
+++ b/src/Doxyfile
@@ -0,0 +1,1127 @@
+# Doxyfile 1.3.6
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = M5
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = docs/doxygen
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch,
+# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en
+# (Japanese with English messages), Korean, Korean-en, Norwegian, Polish, Portuguese,
+# Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# This tag can be used to specify the encoding used in the generated output.
+# The encoding is not always determined by the language that is chosen,
+# but also whether or not the output is meant for Windows or non-Windows users.
+# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES
+# forces the Windows encoding (this is the default for the Windows binary),
+# whereas setting the tag to NO uses a Unix-style encoding (the default for
+# all platforms other than Windows).
+
+USE_WINDOWS_ENCODING = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is used
+# as the annotated text. Otherwise, the brief description is used as-is. If left
+# blank, the following values are used ("$name" is automatically replaced with the
+# name of the entity): "The $name class" "The $name widget" "The $name file"
+# "is" "provides" "specifies" "contains" "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = YES
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited
+# members of a class in the documentation of that class as if those members were
+# ordinary class members. Constructors, destructors and assignment operators of
+# the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. It is allowed to use relative paths in the argument list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH = .
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explicit @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF = YES
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources
+# only. Doxygen will then generate output that is more tailored for Java.
+# For instance, namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = YES
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = YES
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = .
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp
+# *.h++ *.idl *.odl *.cs *.php *.php3 *.inc
+
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.h \
+ *.hh \
+ *.doxygen
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE = build \
+ configs \
+ setup \
+ PENDING \
+ RESYNC
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories
+# that are symbolic links (a Unix filesystem feature) are excluded from the input.
+
+EXCLUDE_SYMLINKS = YES
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+
+EXCLUDE_PATTERNS = */BitKeeper/* \
+ */Attic/* \
+ */SCCS/*
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+
+INPUT_FILTER =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 3
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER = docs/footer.html
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed.
+
+PREDEFINED = DOXYGEN_SHOULD_SKIP_THIS
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse the
+# parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or
+# super classes. Setting the tag to NO turns the diagrams off. Note that this
+# option is superseded by the HAVE_DOT option below. This is only a fallback. It is
+# recommended to install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a call dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+
+CALL_GRAPH = YES
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found on the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_WIDTH = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT = 1024
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes that
+# lay further from the root node will be omitted. Note that setting this option to
+# 1 or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that a graph may be further truncated if the graph's image dimensions are
+# not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT).
+# If 0 is used for the depth value (the default), the graph is not depth-constrained.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
diff --git a/src/SConscript b/src/SConscript
new file mode 100644
index 000000000..a2d5de279
--- /dev/null
+++ b/src/SConscript
@@ -0,0 +1,402 @@
+# -*- mode:python -*-
+
+# Copyright (c) 2004-2005 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import os
+import sys
+from os.path import isdir
+
+# This file defines how to build a particular configuration of M5
+# based on variable settings in the 'env' build environment.
+
+# Import build environment variable from SConstruct.
+Import('env')
+
+###################################################
+#
+# Define needed sources.
+#
+###################################################
+
+# Base sources used by all configurations.
+
+base_sources = Split('''
+ base/circlebuf.cc
+ base/copyright.cc
+ base/cprintf.cc
+ base/embedfile.cc
+ base/fast_alloc.cc
+ base/fifo_buffer.cc
+ base/hostinfo.cc
+ base/hybrid_pred.cc
+ base/inifile.cc
+ base/intmath.cc
+ base/match.cc
+ base/misc.cc
+ base/output.cc
+ base/pollevent.cc
+ base/range.cc
+ base/random.cc
+ base/sat_counter.cc
+ base/serializer.cc
+ base/socket.cc
+ base/statistics.cc
+ base/str.cc
+ base/time.cc
+ base/trace.cc
+ base/traceflags.cc
+ base/userinfo.cc
+ base/compression/lzss_compression.cc
+ base/loader/aout_object.cc
+ base/loader/ecoff_object.cc
+ base/loader/elf_object.cc
+ base/loader/object_file.cc
+ base/loader/symtab.cc
+ base/stats/events.cc
+ base/stats/statdb.cc
+ base/stats/visit.cc
+ base/stats/text.cc
+
+ cpu/base.cc
+ cpu/cpu_exec_context.cc
+ cpu/exetrace.cc
+ cpu/op_class.cc
+ cpu/pc_event.cc
+ cpu/static_inst.cc
+ cpu/sampler/sampler.cc
+
+ mem/bridge.cc
+ mem/bus.cc
+ mem/connector.cc
+ mem/mem_object.cc
+ mem/packet.cc
+ mem/physical.cc
+ mem/port.cc
+ mem/request.cc
+
+ python/pyconfig.cc
+ python/embedded_py.cc
+
+ sim/builder.cc
+ sim/configfile.cc
+ sim/debug.cc
+ sim/eventq.cc
+ sim/faults.cc
+ sim/main.cc
+ sim/param.cc
+ sim/profile.cc
+ sim/root.cc
+ sim/serialize.cc
+ sim/sim_events.cc
+ sim/sim_exit.cc
+ sim/sim_object.cc
+ sim/startup.cc
+ sim/stat_context.cc
+ sim/stat_control.cc
+ sim/system.cc
+ sim/trace_context.cc
+ ''')
+
+# Old FullCPU sources
+full_cpu_sources = Split('''
+ encumbered/cpu/full/bpred.cc
+ encumbered/cpu/full/commit.cc
+ encumbered/cpu/full/cpu.cc
+ encumbered/cpu/full/create_vector.cc
+ encumbered/cpu/full/cv_spec_state.cc
+ encumbered/cpu/full/dd_queue.cc
+ encumbered/cpu/full/dep_link.cc
+ encumbered/cpu/full/dispatch.cc
+ encumbered/cpu/full/dyn_inst.cc
+ encumbered/cpu/full/execute.cc
+ encumbered/cpu/full/fetch.cc
+ encumbered/cpu/full/floss_reasons.cc
+ encumbered/cpu/full/fu_pool.cc
+ encumbered/cpu/full/inst_fifo.cc
+ encumbered/cpu/full/instpipe.cc
+ encumbered/cpu/full/issue.cc
+ encumbered/cpu/full/ls_queue.cc
+ encumbered/cpu/full/machine_queue.cc
+ encumbered/cpu/full/pipetrace.cc
+ encumbered/cpu/full/readyq.cc
+ encumbered/cpu/full/reg_info.cc
+ encumbered/cpu/full/rob_station.cc
+ encumbered/cpu/full/spec_memory.cc
+ encumbered/cpu/full/spec_state.cc
+ encumbered/cpu/full/storebuffer.cc
+ encumbered/cpu/full/writeback.cc
+ encumbered/cpu/full/iq/iq_station.cc
+ encumbered/cpu/full/iq/iqueue.cc
+ encumbered/cpu/full/iq/segmented/chain_info.cc
+ encumbered/cpu/full/iq/segmented/chain_wire.cc
+ encumbered/cpu/full/iq/segmented/iq_seg.cc
+ encumbered/cpu/full/iq/segmented/iq_segmented.cc
+ encumbered/cpu/full/iq/segmented/seg_chain.cc
+ encumbered/cpu/full/iq/seznec/iq_seznec.cc
+ encumbered/cpu/full/iq/standard/iq_standard.cc
+ ''')
+
+trace_reader_sources = Split('''
+ cpu/trace/reader/mem_trace_reader.cc
+ cpu/trace/reader/ibm_reader.cc
+ cpu/trace/reader/itx_reader.cc
+ cpu/trace/reader/m5_reader.cc
+ cpu/trace/opt_cpu.cc
+ cpu/trace/trace_cpu.cc
+ ''')
+
+
+
+# MySql sources
+mysql_sources = Split('''
+ base/mysql.cc
+ base/stats/mysql.cc
+ ''')
+
+# Full-system sources
+full_system_sources = Split('''
+ base/crc.cc
+ base/inet.cc
+ base/remote_gdb.cc
+
+ cpu/intr_control.cc
+ cpu/profile.cc
+
+ dev/alpha_console.cc
+ dev/baddev.cc
+ dev/disk_image.cc
+ dev/etherbus.cc
+ dev/etherdump.cc
+ dev/etherint.cc
+ dev/etherlink.cc
+ dev/etherpkt.cc
+ dev/ethertap.cc
+ dev/ide_ctrl.cc
+ dev/ide_disk.cc
+ dev/io_device.cc
+ dev/isa_fake.cc
+ dev/ns_gige.cc
+ dev/pciconfigall.cc
+ dev/pcidev.cc
+ dev/pcifake.cc
+ dev/pktfifo.cc
+ dev/platform.cc
+ dev/simconsole.cc
+ dev/simple_disk.cc
+ dev/sinic.cc
+ dev/tsunami.cc
+ dev/tsunami_cchip.cc
+ dev/tsunami_io.cc
+ dev/tsunami_fake.cc
+ dev/tsunami_pchip.cc
+
+ dev/uart.cc
+ dev/uart8250.cc
+
+ kern/kernel_binning.cc
+ kern/kernel_stats.cc
+ kern/system_events.cc
+ kern/linux/events.cc
+ kern/linux/linux_syscalls.cc
+ kern/linux/printk.cc
+
+ mem/vport.cc
+
+ sim/pseudo_inst.cc
+ ''')
+
+
+if env['TARGET_ISA'] == 'alpha':
+ full_system_sources += Split('''
+ kern/tru64/dump_mbuf.cc
+ kern/tru64/printf.cc
+ kern/tru64/tru64_events.cc
+ kern/tru64/tru64_syscalls.cc
+ ''')
+
+# turbolaser encumbered sources
+turbolaser_sources = Split('''
+ encumbered/dev/dma.cc
+ encumbered/dev/etherdev.cc
+ encumbered/dev/scsi.cc
+ encumbered/dev/scsi_ctrl.cc
+ encumbered/dev/scsi_disk.cc
+ encumbered/dev/scsi_none.cc
+ encumbered/dev/tlaser_clock.cc
+ encumbered/dev/tlaser_ipi.cc
+ encumbered/dev/tlaser_mbox.cc
+ encumbered/dev/tlaser_mc146818.cc
+ encumbered/dev/tlaser_node.cc
+ encumbered/dev/tlaser_pcia.cc
+ encumbered/dev/tlaser_pcidev.cc
+ encumbered/dev/tlaser_serial.cc
+ encumbered/dev/turbolaser.cc
+ encumbered/dev/uart8530.cc
+ ''')
+
+# Syscall emulation (non-full-system) sources
+syscall_emulation_sources = Split('''
+ mem/translating_port.cc
+ mem/page_table.cc
+ sim/process.cc
+ sim/syscall_emul.cc
+ ''')
+
+#if env['TARGET_ISA'] == 'alpha':
+# syscall_emulation_sources += Split('''
+# kern/tru64/tru64.cc
+# ''')
+
+alpha_eio_sources = Split('''
+ encumbered/eio/exolex.cc
+ encumbered/eio/libexo.cc
+ encumbered/eio/eio.cc
+ ''')
+
+if env['TARGET_ISA'] == 'ALPHA_ISA':
+ syscall_emulation_sources += alpha_eio_sources
+
+memtest_sources = Split('''
+ cpu/memtest/memtest.cc
+ ''')
+
+# Add a flag defining what THE_ISA should be for all compilation
+env.Append(CPPDEFINES=[('THE_ISA','%s_ISA' % env['TARGET_ISA'].upper())])
+
+arch_sources = SConscript('arch/SConscript',
+ exports = 'env', duplicate = False)
+
+cpu_sources = SConscript('cpu/SConscript',
+ exports = 'env', duplicate = False)
+
+# This is outside of cpu/SConscript since the source directory isn't
+# underneath 'cpu'.
+if 'FullCPU' in env['CPU_MODELS']:
+ cpu_sources += full_cpu_sources
+
+# Set up complete list of sources based on configuration.
+sources = base_sources + arch_sources + cpu_sources
+
+if env['FULL_SYSTEM']:
+ sources += full_system_sources
+ if env['ALPHA_TLASER']:
+ sources += turbolaser_sources
+else:
+ sources += syscall_emulation_sources
+
+if env['USE_MYSQL']:
+ sources += mysql_sources
+
+for opt in env.ExportOptions:
+ env.ConfigFile(opt)
+
+###################################################
+#
+# Special build rules.
+#
+###################################################
+
+# base/traceflags.{cc,hh} are generated from base/traceflags.py.
+# $TARGET.base will expand to "<build-dir>/base/traceflags".
+env.Command(Split('base/traceflags.hh base/traceflags.cc'),
+ 'base/traceflags.py',
+ 'python $SOURCE $TARGET.base')
+
+# libelf build is described in its own SConscript file.
+# SConscript-local is the per-config build, which just copies some
+# header files into a place where they can be found.
+SConscript('libelf/SConscript-local', exports = 'env', duplicate=0)
+SConscript('python/SConscript', exports = ['env'], duplicate=0)
+
+# This function adds the specified sources to the given build
+# environment, and returns a list of all the corresponding SCons
+# Object nodes (including an extra one for date.cc). We explicitly
+# add the Object nodes so we can set up special dependencies for
+# date.cc.
+def make_objs(sources, env):
+ objs = [env.Object(s) for s in sources]
+ # make date.cc depend on all other objects so it always gets
+ # recompiled whenever anything else does
+ date_obj = env.Object('base/date.cc')
+ env.Depends(date_obj, objs)
+ objs.append(date_obj)
+ return objs
+
+###################################################
+#
+# Define binaries. Each different build type (debug, opt, etc.) gets
+# a slightly different build environment.
+#
+###################################################
+
+# Include file paths are rooted in this directory. SCons will
+# automatically expand '.' to refer to both the source directory and
+# the corresponding build directory to pick up generated include
+# files.
+env.Append(CPPPATH='.')
+env.Append(CPPPATH='./libelf')
+
+# Debug binary
+debugEnv = env.Copy(OBJSUFFIX='.do')
+debugEnv.Label = 'debug'
+debugEnv.Append(CCFLAGS=Split('-g3 -gdwarf-2 -O0'))
+debugEnv.Append(CPPDEFINES='DEBUG')
+tlist = debugEnv.Program(target = 'm5.debug',
+ source = make_objs(sources, debugEnv))
+debugEnv.M5Binary = tlist[0]
+
+# Optimized binary
+optEnv = env.Copy()
+optEnv.Label = 'opt'
+optEnv.Append(CCFLAGS=Split('-g -O3'))
+tlist = optEnv.Program(target = 'm5.opt',
+ source = make_objs(sources, optEnv))
+optEnv.M5Binary = tlist[0]
+
+# "Fast" binary
+fastEnv = env.Copy(OBJSUFFIX='.fo')
+fastEnv.Label = 'fast'
+fastEnv.Append(CCFLAGS=Split('-O3'))
+fastEnv.Append(CPPDEFINES='NDEBUG')
+fastEnv.Program(target = 'm5.fast.unstripped',
+ source = make_objs(sources, fastEnv))
+tlist = fastEnv.Command(target = 'm5.fast',
+ source = 'm5.fast.unstripped',
+ action = 'strip $SOURCE -o $TARGET')
+fastEnv.M5Binary = tlist[0]
+
+# Profiled binary
+profEnv = env.Copy(OBJSUFFIX='.po')
+profEnv.Label = 'prof'
+profEnv.Append(CCFLAGS=Split('-O3 -g -pg'), LINKFLAGS='-pg')
+tlist = profEnv.Program(target = 'm5.prof',
+ source = make_objs(sources, profEnv))
+profEnv.M5Binary = tlist[0]
+
+envList = [debugEnv, optEnv, fastEnv, profEnv]
+
+Return('envList')
diff --git a/src/arch/SConscript b/src/arch/SConscript
new file mode 100644
index 000000000..06b8e8dde
--- /dev/null
+++ b/src/arch/SConscript
@@ -0,0 +1,150 @@
+# -*- mode:python -*-
+
+# Copyright (c) 2006 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import os.path
+
+# Import build environment variable from SConstruct.
+Import('env')
+
+# Right now there are no source files immediately in this directory
+sources = []
+
+#################################################################
+#
+# ISA "switch header" generation.
+#
+# Auto-generate arch headers that include the right ISA-specific
+# header based on the setting of THE_ISA preprocessor variable.
+#
+#################################################################
+
+# List of headers to generate
+isa_switch_hdrs = Split('''
+ arguments.hh
+ constants.hh
+ faults.hh
+ isa_traits.hh
+ process.hh
+ regfile.hh
+ stacktrace.hh
+ tlb.hh
+ types.hh
+ utility.hh
+ vtophys.hh
+ ''')
+
+# Generate the header. target[0] is the full path of the output
+# header to generate. 'source' is a dummy variable, since we get the
+# list of ISAs from env['ALL_ISA_LIST'].
+def gen_switch_hdr(target, source, env):
+ fname = str(target[0])
+ basename = os.path.basename(fname)
+ f = open(fname, 'w')
+ f.write('#include "arch/isa_specific.hh"\n')
+ cond = '#if'
+ for isa in env['ALL_ISA_LIST']:
+ f.write('%s THE_ISA == %s_ISA\n#include "arch/%s/%s"\n'
+ % (cond, isa.upper(), isa, basename))
+ cond = '#elif'
+ f.write('#else\n#error "THE_ISA not set"\n#endif\n')
+ f.close()
+ return 0
+
+# String to print when generating header
+def gen_switch_hdr_string(target, source, env):
+ return "Generating ISA switch header " + str(target[0])
+
+# Build SCons Action object. 'varlist' specifies env vars that this
+# action depends on; when env['ALL_ISA_LIST'] changes these actions
+# should get re-executed.
+switch_hdr_action = Action(gen_switch_hdr, gen_switch_hdr_string,
+ varlist=['ALL_ISA_LIST'])
+
+# Instantiate actions for each header
+for hdr in isa_switch_hdrs:
+ env.Command(hdr, [], switch_hdr_action)
+
+#################################################################
+#
+# Include architecture-specific files.
+#
+#################################################################
+
+#
+# Build a SCons scanner for ISA files
+#
+import SCons.Scanner
+
+isa_scanner = SCons.Scanner.Classic("ISAScan",
+ [".isa", ".ISA"],
+ "SRCDIR",
+ r'^\s*##include\s+"([\w/.-]*)"')
+
+env.Append(SCANNERS = isa_scanner)
+
+#
+# Now create a Builder object that uses isa_parser.py to generate C++
+# output from the ISA description (*.isa) files.
+#
+
+# Convert to File node to fix path
+isa_parser = File('isa_parser.py')
+cpu_models_file = File('../cpu/cpu_models.py')
+
+# This sucks in the defintions of the CpuModel objects.
+execfile(cpu_models_file.srcnode().abspath)
+
+# Several files are generated from the ISA description.
+# We always get the basic decoder and header file.
+isa_desc_gen_files = Split('decoder.cc decoder.hh')
+# We also get an execute file for each selected CPU model.
+isa_desc_gen_files += [CpuModel.dict[cpu].filename
+ for cpu in env['CPU_MODELS']]
+
+# The emitter patches up the sources & targets to include the
+# autogenerated files as targets and isa parser itself as a source.
+def isa_desc_emitter(target, source, env):
+ return (isa_desc_gen_files, [isa_parser, cpu_models_file] + source)
+
+# Pieces are in place, so create the builder.
+isa_desc_builder = Builder(action='python $SOURCES $TARGET.dir $CPU_MODELS',
+ emitter = isa_desc_emitter)
+
+env.Append(BUILDERS = { 'ISADesc' : isa_desc_builder })
+
+#
+# Now include other ISA-specific sources from the ISA subdirectories.
+#
+
+isa = env['TARGET_ISA'] # someday this may be a list of ISAs
+
+# Let the target architecture define what additional sources it needs
+sources += SConscript(os.path.join(isa, 'SConscript'),
+ exports = 'env', duplicate = False)
+
+Return('sources')
diff --git a/src/arch/alpha/SConscript b/src/arch/alpha/SConscript
new file mode 100644
index 000000000..1b20f8b1f
--- /dev/null
+++ b/src/arch/alpha/SConscript
@@ -0,0 +1,93 @@
+# -*- mode:python -*-
+
+# Copyright (c) 2004-2005 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import os
+import sys
+from os.path import isdir
+
+# This file defines how to build a particular configuration of M5
+# based on variable settings in the 'env' build environment.
+
+# Import build environment variable from SConstruct.
+Import('env')
+
+###################################################
+#
+# Define needed sources.
+#
+###################################################
+
+# Base sources used by all configurations.
+base_sources = Split('''
+ faults.cc
+ isa_traits.cc
+ ''')
+
+# Full-system sources
+full_system_sources = Split('''
+ tlb.cc
+ arguments.cc
+ ev5.cc
+ osfpal.cc
+ stacktrace.cc
+ vtophys.cc
+ system.cc
+ freebsd/system.cc
+ linux/system.cc
+ tru64/system.cc
+ ''')
+
+
+# Syscall emulation (non-full-system) sources
+syscall_emulation_sources = Split('''
+ linux/linux.cc
+ linux/process.cc
+ tru64/tru64.cc
+ tru64/process.cc
+ process.cc
+ ''')
+
+# Set up complete list of sources based on configuration.
+sources = base_sources
+
+if env['FULL_SYSTEM']:
+ sources += full_system_sources
+else:
+ sources += syscall_emulation_sources
+
+# Convert file names to SCons File objects. This takes care of the
+# path relative to the top of the directory tree.
+sources = [File(s) for s in sources]
+
+# Add in files generated by the ISA description.
+isa_desc_files = env.ISADesc('isa/main.isa')
+# Only non-header files need to be compiled.
+isa_desc_sources = [f for f in isa_desc_files if not f.path.endswith('.hh')]
+sources += isa_desc_sources
+
+Return('sources')
diff --git a/src/arch/alpha/aout_machdep.h b/src/arch/alpha/aout_machdep.h
new file mode 100644
index 000000000..df9d9ac6a
--- /dev/null
+++ b/src/arch/alpha/aout_machdep.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __AOUT_MACHDEP_H__
+#define __AOUT_MACHDEP_H__
+
+///
+/// Funky Alpha 64-bit a.out header used for PAL code.
+///
+struct aout_exechdr {
+ uint16_t magic; ///< magic number
+ uint16_t vstamp; ///< version stamp?
+ uint16_t bldrev; ///< ???
+ uint16_t padcell; ///< padding
+ uint64_t tsize; ///< text segment size
+ uint64_t dsize; ///< data segment size
+ uint64_t bsize; ///< bss segment size
+ uint64_t entry; ///< entry point
+ uint64_t text_start; ///< text base address
+ uint64_t data_start; ///< data base address
+ uint64_t bss_start; ///< bss base address
+ uint32_t gprmask; ///< GPR mask (unused, AFAIK)
+ uint32_t fprmask; ///< FPR mask (unused, AFAIK)
+ uint64_t gp_value; ///< global pointer reg value
+};
+
+#define AOUT_LDPGSZ 8192
+
+#define N_GETMAGIC(ex) ((ex).magic)
+
+#define N_BADMAX
+
+#define N_TXTADDR(ex) ((ex).text_start)
+#define N_DATADDR(ex) ((ex).data_start)
+#define N_BSSADDR(ex) ((ex).bss_start)
+
+#define N_TXTOFF(ex) \
+ (N_GETMAGIC(ex) == ZMAGIC ? 0 : sizeof(struct aout_exechdr))
+
+#define N_DATOFF(ex) N_ALIGN(ex, N_TXTOFF(ex) + (ex).tsize)
+
+#endif /* !__AOUT_MACHDEP_H__*/
diff --git a/src/arch/alpha/arguments.cc b/src/arch/alpha/arguments.cc
new file mode 100644
index 000000000..adc371682
--- /dev/null
+++ b/src/arch/alpha/arguments.cc
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "arch/alpha/arguments.hh"
+#include "arch/alpha/vtophys.hh"
+#include "cpu/exec_context.hh"
+#include "mem/vport.hh"
+
+using namespace AlphaISA;
+
+AlphaArguments::Data::~Data()
+{
+ while (!data.empty()) {
+ delete [] data.front();
+ data.pop_front();
+ }
+}
+
+char *
+AlphaArguments::Data::alloc(size_t size)
+{
+ char *buf = new char[size];
+ data.push_back(buf);
+ return buf;
+}
+
+uint64_t
+AlphaArguments::getArg(bool fp)
+{
+ if (number < 6) {
+ if (fp)
+ return xc->readFloatRegBits(16 + number);
+ else
+ return xc->readIntReg(16 + number);
+ } else {
+ Addr sp = xc->readIntReg(30);
+ VirtualPort *vp = xc->getVirtPort(xc);
+ uint64_t arg = vp->read<uint64_t>(sp + (number-6) * sizeof(uint64_t));
+ xc->delVirtPort(vp);
+ return arg;
+ }
+}
+
diff --git a/src/arch/alpha/arguments.hh b/src/arch/alpha/arguments.hh
new file mode 100644
index 000000000..bd1c6cb1d
--- /dev/null
+++ b/src/arch/alpha/arguments.hh
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ARCH_ALPHA_ARGUMENTS_HH__
+#define __ARCH_ALPHA_ARGUMENTS_HH__
+
+#include <assert.h>
+
+#include "arch/alpha/vtophys.hh"
+#include "base/refcnt.hh"
+#include "sim/host.hh"
+
+class ExecContext;
+
+namespace AlphaISA {
+
+class AlphaArguments
+{
+ protected:
+ ExecContext *xc;
+ int number;
+ uint64_t getArg(bool fp = false);
+
+ protected:
+ class Data : public RefCounted
+ {
+ public:
+ Data(){}
+ ~Data();
+
+ private:
+ std::list<char *> data;
+
+ public:
+ char *alloc(size_t size);
+ };
+
+ RefCountingPtr<Data> data;
+
+ public:
+ AlphaArguments(ExecContext *ctx, int n = 0)
+ : xc(ctx), number(n), data(NULL)
+ { assert(number >= 0); data = new Data;}
+ AlphaArguments(const AlphaArguments &args)
+ : xc(args.xc), number(args.number), data(args.data) {}
+ ~AlphaArguments() {}
+
+ ExecContext *getExecContext() const { return xc; }
+
+ const AlphaArguments &operator=(const AlphaArguments &args) {
+ xc = args.xc;
+ number = args.number;
+ data = args.data;
+ return *this;
+ }
+
+ AlphaArguments &operator++() {
+ ++number;
+ assert(number >= 0);
+ return *this;
+ }
+
+ AlphaArguments operator++(int) {
+ AlphaArguments args = *this;
+ ++number;
+ assert(number >= 0);
+ return args;
+ }
+
+ AlphaArguments &operator--() {
+ --number;
+ assert(number >= 0);
+ return *this;
+ }
+
+ AlphaArguments operator--(int) {
+ AlphaArguments args = *this;
+ --number;
+ assert(number >= 0);
+ return args;
+ }
+
+ const AlphaArguments &operator+=(int index) {
+ number += index;
+ assert(number >= 0);
+ return *this;
+ }
+
+ const AlphaArguments &operator-=(int index) {
+ number -= index;
+ assert(number >= 0);
+ return *this;
+ }
+
+ AlphaArguments operator[](int index) {
+ return AlphaArguments(xc, index);
+ }
+
+ template <class T>
+ operator T() {
+ assert(sizeof(T) <= sizeof(uint64_t));
+ T data = static_cast<T>(getArg());
+ return data;
+ }
+
+ template <class T>
+ operator T *() {
+ T *buf = (T *)data->alloc(sizeof(T));
+ CopyData(xc, buf, getArg(), sizeof(T));
+ return buf;
+ }
+
+ operator char *() {
+ char *buf = data->alloc(2048);
+ CopyStringOut(xc, buf, getArg(), 2048);
+ return buf;
+ }
+};
+
+}; // namespace AlphaISA
+
+#endif // __ARCH_ALPHA_ARGUMENTS_HH__
diff --git a/src/arch/alpha/ecoff_machdep.h b/src/arch/alpha/ecoff_machdep.h
new file mode 100644
index 000000000..9341b8ff7
--- /dev/null
+++ b/src/arch/alpha/ecoff_machdep.h
@@ -0,0 +1,73 @@
+/*
+ * Taken from NetBSD arch/alpha/ecoff_machdep.h
+ */
+
+/* $NetBSD: ecoff_machdep.h,v 1.5 1999/04/27 02:32:33 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994 Adam Glass
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Adam Glass.
+ * 4. The name of the Author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Adam Glass ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Adam Glass BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+//
+// Define COFF/ECOFF integer type sizes
+//
+typedef int16_t coff_short;
+typedef uint16_t coff_ushort;
+typedef int32_t coff_int;
+typedef uint32_t coff_uint;
+typedef int64_t coff_long;
+typedef uint64_t coff_ulong;
+typedef uint64_t coff_addr;
+
+#define ECOFF_LDPGSZ 4096
+
+#define ECOFF_PAD \
+ coff_ushort bldrev; /* XXX */
+
+#define ECOFF_MACHDEP \
+ coff_uint gprmask; \
+ coff_uint fprmask; \
+ coff_ulong gp_value
+
+#define ECOFF_MAGIC_ALPHA 0603
+#define ECOFF_MAGIC_NETBSD_ALPHA 0605
+#define ECOFF_BADMAG(ep) \
+ ((ep)->f.f_magic != ECOFF_MAGIC_ALPHA && \
+ (ep)->f.f_magic != ECOFF_MAGIC_NETBSD_ALPHA)
+
+#define ECOFF_FLAG_EXEC 0002
+#define ECOFF_SEGMENT_ALIGNMENT(ep) \
+ (((ep)->f.f_flags & ECOFF_FLAG_EXEC) == 0 ? 8 : 16)
+
+#define ECOFF_FLAG_OBJECT_TYPE_MASK 0x3000
+#define ECOFF_OBJECT_TYPE_NO_SHARED 0x1000
+#define ECOFF_OBJECT_TYPE_SHARABLE 0x2000
+#define ECOFF_OBJECT_TYPE_CALL_SHARED 0x3000
+
diff --git a/src/arch/alpha/ev5.cc b/src/arch/alpha/ev5.cc
new file mode 100644
index 000000000..12f7659e6
--- /dev/null
+++ b/src/arch/alpha/ev5.cc
@@ -0,0 +1,577 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "arch/alpha/tlb.hh"
+#include "arch/alpha/isa_traits.hh"
+#include "arch/alpha/osfpal.hh"
+#include "base/kgdb.h"
+#include "base/remote_gdb.hh"
+#include "base/stats/events.hh"
+#include "config/full_system.hh"
+#include "cpu/base.hh"
+#include "cpu/cpu_exec_context.hh"
+#include "cpu/exec_context.hh"
+#include "kern/kernel_stats.hh"
+#include "sim/debug.hh"
+#include "sim/sim_events.hh"
+
+#if FULL_SYSTEM
+
+using namespace EV5;
+
+////////////////////////////////////////////////////////////////////////
+//
+// Machine dependent functions
+//
+void
+AlphaISA::initCPU(ExecContext *xc, int cpuId)
+{
+ initIPRs(xc, cpuId);
+
+ xc->setIntReg(16, cpuId);
+ xc->setIntReg(0, cpuId);
+
+ xc->setPC(xc->readMiscReg(IPR_PAL_BASE) + (new ResetFault)->vect());
+ xc->setNextPC(xc->readPC() + sizeof(MachInst));
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+//
+//
+void
+AlphaISA::initIPRs(ExecContext *xc, int cpuId)
+{
+ for (int i = 0; i < NumInternalProcRegs; ++i) {
+ xc->setMiscReg(i, 0);
+ }
+
+ xc->setMiscReg(IPR_PAL_BASE, PalBase);
+ xc->setMiscReg(IPR_MCSR, 0x6);
+ xc->setMiscReg(IPR_PALtemp16, cpuId);
+}
+
+
+template <class CPU>
+void
+AlphaISA::processInterrupts(CPU *cpu)
+{
+ //Check if there are any outstanding interrupts
+ //Handle the interrupts
+ int ipl = 0;
+ int summary = 0;
+
+ cpu->checkInterrupts = false;
+
+ if (cpu->readMiscReg(IPR_ASTRR))
+ panic("asynchronous traps not implemented\n");
+
+ if (cpu->readMiscReg(IPR_SIRR)) {
+ for (int i = INTLEVEL_SOFTWARE_MIN;
+ i < INTLEVEL_SOFTWARE_MAX; i++) {
+ if (cpu->readMiscReg(IPR_SIRR) & (ULL(1) << i)) {
+ // See table 4-19 of the 21164 hardware reference
+ ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1;
+ summary |= (ULL(1) << i);
+ }
+ }
+ }
+
+ uint64_t interrupts = cpu->intr_status();
+
+ if (interrupts) {
+ for (int i = INTLEVEL_EXTERNAL_MIN;
+ i < INTLEVEL_EXTERNAL_MAX; i++) {
+ if (interrupts & (ULL(1) << i)) {
+ // See table 4-19 of the 21164 hardware reference
+ ipl = i;
+ summary |= (ULL(1) << i);
+ }
+ }
+ }
+
+ if (ipl && ipl > cpu->readMiscReg(IPR_IPLR)) {
+ cpu->setMiscReg(IPR_ISR, summary);
+ cpu->setMiscReg(IPR_INTID, ipl);
+ cpu->trap(new InterruptFault);
+ DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n",
+ cpu->readMiscReg(IPR_IPLR), ipl, summary);
+ }
+
+}
+
+template <class CPU>
+void
+AlphaISA::zeroRegisters(CPU *cpu)
+{
+ // Insure ISA semantics
+ // (no longer very clean due to the change in setIntReg() in the
+ // cpu model. Consider changing later.)
+ cpu->cpuXC->setIntReg(ZeroReg, 0);
+ cpu->cpuXC->setFloatReg(ZeroReg, 0.0);
+}
+
+Fault
+CPUExecContext::hwrei()
+{
+ if (!inPalMode())
+ return new UnimplementedOpcodeFault;
+
+ setNextPC(readMiscReg(AlphaISA::IPR_EXC_ADDR));
+
+ if (!misspeculating()) {
+ cpu->kernelStats->hwrei();
+
+ cpu->checkInterrupts = true;
+ }
+
+ // FIXME: XXX check for interrupts? XXX
+ return NoFault;
+}
+
+int
+AlphaISA::MiscRegFile::getInstAsid()
+{
+ return EV5::ITB_ASN_ASN(ipr[IPR_ITB_ASN]);
+}
+
+int
+AlphaISA::MiscRegFile::getDataAsid()
+{
+ return EV5::DTB_ASN_ASN(ipr[IPR_DTB_ASN]);
+}
+
+AlphaISA::MiscReg
+AlphaISA::MiscRegFile::readIpr(int idx, Fault &fault, ExecContext *xc)
+{
+ uint64_t retval = 0; // return value, default 0
+
+ switch (idx) {
+ case AlphaISA::IPR_PALtemp0:
+ case AlphaISA::IPR_PALtemp1:
+ case AlphaISA::IPR_PALtemp2:
+ case AlphaISA::IPR_PALtemp3:
+ case AlphaISA::IPR_PALtemp4:
+ case AlphaISA::IPR_PALtemp5:
+ case AlphaISA::IPR_PALtemp6:
+ case AlphaISA::IPR_PALtemp7:
+ case AlphaISA::IPR_PALtemp8:
+ case AlphaISA::IPR_PALtemp9:
+ case AlphaISA::IPR_PALtemp10:
+ case AlphaISA::IPR_PALtemp11:
+ case AlphaISA::IPR_PALtemp12:
+ case AlphaISA::IPR_PALtemp13:
+ case AlphaISA::IPR_PALtemp14:
+ case AlphaISA::IPR_PALtemp15:
+ case AlphaISA::IPR_PALtemp16:
+ case AlphaISA::IPR_PALtemp17:
+ case AlphaISA::IPR_PALtemp18:
+ case AlphaISA::IPR_PALtemp19:
+ case AlphaISA::IPR_PALtemp20:
+ case AlphaISA::IPR_PALtemp21:
+ case AlphaISA::IPR_PALtemp22:
+ case AlphaISA::IPR_PALtemp23:
+ case AlphaISA::IPR_PAL_BASE:
+
+ case AlphaISA::IPR_IVPTBR:
+ case AlphaISA::IPR_DC_MODE:
+ case AlphaISA::IPR_MAF_MODE:
+ case AlphaISA::IPR_ISR:
+ case AlphaISA::IPR_EXC_ADDR:
+ case AlphaISA::IPR_IC_PERR_STAT:
+ case AlphaISA::IPR_DC_PERR_STAT:
+ case AlphaISA::IPR_MCSR:
+ case AlphaISA::IPR_ASTRR:
+ case AlphaISA::IPR_ASTER:
+ case AlphaISA::IPR_SIRR:
+ case AlphaISA::IPR_ICSR:
+ case AlphaISA::IPR_ICM:
+ case AlphaISA::IPR_DTB_CM:
+ case AlphaISA::IPR_IPLR:
+ case AlphaISA::IPR_INTID:
+ case AlphaISA::IPR_PMCTR:
+ // no side-effect
+ retval = ipr[idx];
+ break;
+
+ case AlphaISA::IPR_CC:
+ retval |= ipr[idx] & ULL(0xffffffff00000000);
+ retval |= xc->getCpuPtr()->curCycle() & ULL(0x00000000ffffffff);
+ break;
+
+ case AlphaISA::IPR_VA:
+ retval = ipr[idx];
+ break;
+
+ case AlphaISA::IPR_VA_FORM:
+ case AlphaISA::IPR_MM_STAT:
+ case AlphaISA::IPR_IFAULT_VA_FORM:
+ case AlphaISA::IPR_EXC_MASK:
+ case AlphaISA::IPR_EXC_SUM:
+ retval = ipr[idx];
+ break;
+
+ case AlphaISA::IPR_DTB_PTE:
+ {
+ AlphaISA::PTE &pte = xc->getDTBPtr()->index(!xc->misspeculating());
+
+ retval |= ((u_int64_t)pte.ppn & ULL(0x7ffffff)) << 32;
+ retval |= ((u_int64_t)pte.xre & ULL(0xf)) << 8;
+ retval |= ((u_int64_t)pte.xwe & ULL(0xf)) << 12;
+ retval |= ((u_int64_t)pte.fonr & ULL(0x1)) << 1;
+ retval |= ((u_int64_t)pte.fonw & ULL(0x1))<< 2;
+ retval |= ((u_int64_t)pte.asma & ULL(0x1)) << 4;
+ retval |= ((u_int64_t)pte.asn & ULL(0x7f)) << 57;
+ }
+ break;
+
+ // write only registers
+ case AlphaISA::IPR_HWINT_CLR:
+ case AlphaISA::IPR_SL_XMIT:
+ case AlphaISA::IPR_DC_FLUSH:
+ case AlphaISA::IPR_IC_FLUSH:
+ case AlphaISA::IPR_ALT_MODE:
+ case AlphaISA::IPR_DTB_IA:
+ case AlphaISA::IPR_DTB_IAP:
+ case AlphaISA::IPR_ITB_IA:
+ case AlphaISA::IPR_ITB_IAP:
+ fault = new UnimplementedOpcodeFault;
+ break;
+
+ default:
+ // invalid IPR
+ fault = new UnimplementedOpcodeFault;
+ break;
+ }
+
+ return retval;
+}
+
+#ifdef DEBUG
+// Cause the simulator to break when changing to the following IPL
+int break_ipl = -1;
+#endif
+
+Fault
+AlphaISA::MiscRegFile::setIpr(int idx, uint64_t val, ExecContext *xc)
+{
+ uint64_t old;
+
+ if (xc->misspeculating())
+ return NoFault;
+
+ switch (idx) {
+ case AlphaISA::IPR_PALtemp0:
+ case AlphaISA::IPR_PALtemp1:
+ case AlphaISA::IPR_PALtemp2:
+ case AlphaISA::IPR_PALtemp3:
+ case AlphaISA::IPR_PALtemp4:
+ case AlphaISA::IPR_PALtemp5:
+ case AlphaISA::IPR_PALtemp6:
+ case AlphaISA::IPR_PALtemp7:
+ case AlphaISA::IPR_PALtemp8:
+ case AlphaISA::IPR_PALtemp9:
+ case AlphaISA::IPR_PALtemp10:
+ case AlphaISA::IPR_PALtemp11:
+ case AlphaISA::IPR_PALtemp12:
+ case AlphaISA::IPR_PALtemp13:
+ case AlphaISA::IPR_PALtemp14:
+ case AlphaISA::IPR_PALtemp15:
+ case AlphaISA::IPR_PALtemp16:
+ case AlphaISA::IPR_PALtemp17:
+ case AlphaISA::IPR_PALtemp18:
+ case AlphaISA::IPR_PALtemp19:
+ case AlphaISA::IPR_PALtemp20:
+ case AlphaISA::IPR_PALtemp21:
+ case AlphaISA::IPR_PALtemp22:
+ case AlphaISA::IPR_PAL_BASE:
+ case AlphaISA::IPR_IC_PERR_STAT:
+ case AlphaISA::IPR_DC_PERR_STAT:
+ case AlphaISA::IPR_PMCTR:
+ // write entire quad w/ no side-effect
+ ipr[idx] = val;
+ break;
+
+ case AlphaISA::IPR_CC_CTL:
+ // This IPR resets the cycle counter. We assume this only
+ // happens once... let's verify that.
+ assert(ipr[idx] == 0);
+ ipr[idx] = 1;
+ break;
+
+ case AlphaISA::IPR_CC:
+ // This IPR only writes the upper 64 bits. It's ok to write
+ // all 64 here since we mask out the lower 32 in rpcc (see
+ // isa_desc).
+ ipr[idx] = val;
+ break;
+
+ case AlphaISA::IPR_PALtemp23:
+ // write entire quad w/ no side-effect
+ old = ipr[idx];
+ ipr[idx] = val;
+ xc->getCpuPtr()->kernelStats->context(old, val, xc);
+ break;
+
+ case AlphaISA::IPR_DTB_PTE:
+ // write entire quad w/ no side-effect, tag is forthcoming
+ ipr[idx] = val;
+ break;
+
+ case AlphaISA::IPR_EXC_ADDR:
+ // second least significant bit in PC is always zero
+ ipr[idx] = val & ~2;
+ break;
+
+ case AlphaISA::IPR_ASTRR:
+ case AlphaISA::IPR_ASTER:
+ // only write least significant four bits - privilege mask
+ ipr[idx] = val & 0xf;
+ break;
+
+ case AlphaISA::IPR_IPLR:
+#ifdef DEBUG
+ if (break_ipl != -1 && break_ipl == (val & 0x1f))
+ debug_break();
+#endif
+
+ // only write least significant five bits - interrupt level
+ ipr[idx] = val & 0x1f;
+ xc->getCpuPtr()->kernelStats->swpipl(ipr[idx]);
+ break;
+
+ case AlphaISA::IPR_DTB_CM:
+ if (val & 0x18)
+ xc->getCpuPtr()->kernelStats->mode(Kernel::user, xc);
+ else
+ xc->getCpuPtr()->kernelStats->mode(Kernel::kernel, xc);
+
+ case AlphaISA::IPR_ICM:
+ // only write two mode bits - processor mode
+ ipr[idx] = val & 0x18;
+ break;
+
+ case AlphaISA::IPR_ALT_MODE:
+ // only write two mode bits - processor mode
+ ipr[idx] = val & 0x18;
+ break;
+
+ case AlphaISA::IPR_MCSR:
+ // more here after optimization...
+ ipr[idx] = val;
+ break;
+
+ case AlphaISA::IPR_SIRR:
+ // only write software interrupt mask
+ ipr[idx] = val & 0x7fff0;
+ break;
+
+ case AlphaISA::IPR_ICSR:
+ ipr[idx] = val & ULL(0xffffff0300);
+ break;
+
+ case AlphaISA::IPR_IVPTBR:
+ case AlphaISA::IPR_MVPTBR:
+ ipr[idx] = val & ULL(0xffffffffc0000000);
+ break;
+
+ case AlphaISA::IPR_DC_TEST_CTL:
+ ipr[idx] = val & 0x1ffb;
+ break;
+
+ case AlphaISA::IPR_DC_MODE:
+ case AlphaISA::IPR_MAF_MODE:
+ ipr[idx] = val & 0x3f;
+ break;
+
+ case AlphaISA::IPR_ITB_ASN:
+ ipr[idx] = val & 0x7f0;
+ break;
+
+ case AlphaISA::IPR_DTB_ASN:
+ ipr[idx] = val & ULL(0xfe00000000000000);
+ break;
+
+ case AlphaISA::IPR_EXC_SUM:
+ case AlphaISA::IPR_EXC_MASK:
+ // any write to this register clears it
+ ipr[idx] = 0;
+ break;
+
+ case AlphaISA::IPR_INTID:
+ case AlphaISA::IPR_SL_RCV:
+ case AlphaISA::IPR_MM_STAT:
+ case AlphaISA::IPR_ITB_PTE_TEMP:
+ case AlphaISA::IPR_DTB_PTE_TEMP:
+ // read-only registers
+ return new UnimplementedOpcodeFault;
+
+ case AlphaISA::IPR_HWINT_CLR:
+ case AlphaISA::IPR_SL_XMIT:
+ case AlphaISA::IPR_DC_FLUSH:
+ case AlphaISA::IPR_IC_FLUSH:
+ // the following are write only
+ ipr[idx] = val;
+ break;
+
+ case AlphaISA::IPR_DTB_IA:
+ // really a control write
+ ipr[idx] = 0;
+
+ xc->getDTBPtr()->flushAll();
+ break;
+
+ case AlphaISA::IPR_DTB_IAP:
+ // really a control write
+ ipr[idx] = 0;
+
+ xc->getDTBPtr()->flushProcesses();
+ break;
+
+ case AlphaISA::IPR_DTB_IS:
+ // really a control write
+ ipr[idx] = val;
+
+ xc->getDTBPtr()->flushAddr(val,
+ DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN]));
+ break;
+
+ case AlphaISA::IPR_DTB_TAG: {
+ struct AlphaISA::PTE pte;
+
+ // FIXME: granularity hints NYI...
+ if (DTB_PTE_GH(ipr[AlphaISA::IPR_DTB_PTE]) != 0)
+ panic("PTE GH field != 0");
+
+ // write entire quad
+ ipr[idx] = val;
+
+ // construct PTE for new entry
+ pte.ppn = DTB_PTE_PPN(ipr[AlphaISA::IPR_DTB_PTE]);
+ pte.xre = DTB_PTE_XRE(ipr[AlphaISA::IPR_DTB_PTE]);
+ pte.xwe = DTB_PTE_XWE(ipr[AlphaISA::IPR_DTB_PTE]);
+ pte.fonr = DTB_PTE_FONR(ipr[AlphaISA::IPR_DTB_PTE]);
+ pte.fonw = DTB_PTE_FONW(ipr[AlphaISA::IPR_DTB_PTE]);
+ pte.asma = DTB_PTE_ASMA(ipr[AlphaISA::IPR_DTB_PTE]);
+ pte.asn = DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN]);
+
+ // insert new TAG/PTE value into data TLB
+ xc->getDTBPtr()->insert(val, pte);
+ }
+ break;
+
+ case AlphaISA::IPR_ITB_PTE: {
+ struct AlphaISA::PTE pte;
+
+ // FIXME: granularity hints NYI...
+ if (ITB_PTE_GH(val) != 0)
+ panic("PTE GH field != 0");
+
+ // write entire quad
+ ipr[idx] = val;
+
+ // construct PTE for new entry
+ pte.ppn = ITB_PTE_PPN(val);
+ pte.xre = ITB_PTE_XRE(val);
+ pte.xwe = 0;
+ pte.fonr = ITB_PTE_FONR(val);
+ pte.fonw = ITB_PTE_FONW(val);
+ pte.asma = ITB_PTE_ASMA(val);
+ pte.asn = ITB_ASN_ASN(ipr[AlphaISA::IPR_ITB_ASN]);
+
+ // insert new TAG/PTE value into data TLB
+ xc->getITBPtr()->insert(ipr[AlphaISA::IPR_ITB_TAG], pte);
+ }
+ break;
+
+ case AlphaISA::IPR_ITB_IA:
+ // really a control write
+ ipr[idx] = 0;
+
+ xc->getITBPtr()->flushAll();
+ break;
+
+ case AlphaISA::IPR_ITB_IAP:
+ // really a control write
+ ipr[idx] = 0;
+
+ xc->getITBPtr()->flushProcesses();
+ break;
+
+ case AlphaISA::IPR_ITB_IS:
+ // really a control write
+ ipr[idx] = val;
+
+ xc->getITBPtr()->flushAddr(val,
+ ITB_ASN_ASN(ipr[AlphaISA::IPR_ITB_ASN]));
+ break;
+
+ default:
+ // invalid IPR
+ return new UnimplementedOpcodeFault;
+ }
+
+ // no error...
+ return NoFault;
+}
+
+void
+AlphaISA::copyIprs(ExecContext *src, ExecContext *dest)
+{
+ for (int i = IPR_Base_DepTag; i < NumInternalProcRegs; ++i) {
+ dest->setMiscReg(i, src->readMiscReg(i));
+ }
+}
+
+/**
+ * Check for special simulator handling of specific PAL calls.
+ * If return value is false, actual PAL call will be suppressed.
+ */
+bool
+CPUExecContext::simPalCheck(int palFunc)
+{
+ cpu->kernelStats->callpal(palFunc, proxy);
+
+ switch (palFunc) {
+ case PAL::halt:
+ halt();
+ if (--System::numSystemsRunning == 0)
+ new SimExitEvent("all cpus halted");
+ break;
+
+ case PAL::bpt:
+ case PAL::bugchk:
+ if (system->breakpoint())
+ return false;
+ break;
+ }
+
+ return true;
+}
+
+#endif // FULL_SYSTEM
diff --git a/src/arch/alpha/ev5.hh b/src/arch/alpha/ev5.hh
new file mode 100644
index 000000000..7c8465cfb
--- /dev/null
+++ b/src/arch/alpha/ev5.hh
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ARCH_ALPHA_EV5_HH__
+#define __ARCH_ALPHA_EV5_HH__
+
+#include "config/alpha_tlaser.hh"
+#include "arch/alpha/isa_traits.hh"
+
+namespace EV5 {
+
+//It seems like a safe assumption EV5 only applies to alpha
+using namespace AlphaISA;
+
+#if ALPHA_TLASER
+const uint64_t AsnMask = ULL(0x7f);
+#else
+const uint64_t AsnMask = ULL(0xff);
+#endif
+
+const int VAddrImplBits = 43;
+const Addr VAddrImplMask = (ULL(1) << VAddrImplBits) - 1;
+const Addr VAddrUnImplMask = ~VAddrImplMask;
+inline Addr VAddrImpl(Addr a) { return a & VAddrImplMask; }
+inline Addr VAddrVPN(Addr a) { return a >> AlphaISA::PageShift; }
+inline Addr VAddrOffset(Addr a) { return a & AlphaISA::PageOffset; }
+inline Addr VAddrSpaceEV5(Addr a) { return a >> 41 & 0x3; }
+inline Addr VAddrSpaceEV6(Addr a) { return a >> 41 & 0x7f; }
+
+#if ALPHA_TLASER
+inline bool PAddrIprSpace(Addr a) { return a >= ULL(0xFFFFF00000); }
+const int PAddrImplBits = 40;
+#else
+inline bool PAddrIprSpace(Addr a) { return a >= ULL(0xFFFFFF00000); }
+const int PAddrImplBits = 44; // for Tsunami
+#endif
+const Addr PAddrImplMask = (ULL(1) << PAddrImplBits) - 1;
+const Addr PAddrUncachedBit39 = ULL(0x8000000000);
+const Addr PAddrUncachedBit40 = ULL(0x10000000000);
+const Addr PAddrUncachedBit43 = ULL(0x80000000000);
+const Addr PAddrUncachedMask = ULL(0x807ffffffff); // Clear PA<42:35>
+inline Addr Phys2K0Seg(Addr addr)
+{
+#if !ALPHA_TLASER
+ if (addr & PAddrUncachedBit43) {
+ addr &= PAddrUncachedMask;
+ addr |= PAddrUncachedBit40;
+ }
+#endif
+ return addr | AlphaISA::K0SegBase;
+}
+
+inline int DTB_ASN_ASN(uint64_t reg) { return reg >> 57 & AsnMask; }
+inline Addr DTB_PTE_PPN(uint64_t reg)
+{ return reg >> 32 & (ULL(1) << PAddrImplBits - AlphaISA::PageShift) - 1; }
+inline int DTB_PTE_XRE(uint64_t reg) { return reg >> 8 & 0xf; }
+inline int DTB_PTE_XWE(uint64_t reg) { return reg >> 12 & 0xf; }
+inline int DTB_PTE_FONR(uint64_t reg) { return reg >> 1 & 0x1; }
+inline int DTB_PTE_FONW(uint64_t reg) { return reg >> 2 & 0x1; }
+inline int DTB_PTE_GH(uint64_t reg) { return reg >> 5 & 0x3; }
+inline int DTB_PTE_ASMA(uint64_t reg) { return reg >> 4 & 0x1; }
+
+inline int ITB_ASN_ASN(uint64_t reg) { return reg >> 4 & AsnMask; }
+inline Addr ITB_PTE_PPN(uint64_t reg)
+{ return reg >> 32 & (ULL(1) << PAddrImplBits - AlphaISA::PageShift) - 1; }
+inline int ITB_PTE_XRE(uint64_t reg) { return reg >> 8 & 0xf; }
+inline bool ITB_PTE_FONR(uint64_t reg) { return reg >> 1 & 0x1; }
+inline bool ITB_PTE_FONW(uint64_t reg) { return reg >> 2 & 0x1; }
+inline int ITB_PTE_GH(uint64_t reg) { return reg >> 5 & 0x3; }
+inline bool ITB_PTE_ASMA(uint64_t reg) { return reg >> 4 & 0x1; }
+
+inline uint64_t MCSR_SP(uint64_t reg) { return reg >> 1 & 0x3; }
+
+inline bool ICSR_SDE(uint64_t reg) { return reg >> 30 & 0x1; }
+inline int ICSR_SPE(uint64_t reg) { return reg >> 28 & 0x3; }
+inline bool ICSR_FPE(uint64_t reg) { return reg >> 26 & 0x1; }
+
+inline uint64_t ALT_MODE_AM(uint64_t reg) { return reg >> 3 & 0x3; }
+inline uint64_t DTB_CM_CM(uint64_t reg) { return reg >> 3 & 0x3; }
+inline uint64_t ICM_CM(uint64_t reg) { return reg >> 3 & 0x3; }
+
+const uint64_t MM_STAT_BAD_VA_MASK = ULL(0x0020);
+const uint64_t MM_STAT_DTB_MISS_MASK = ULL(0x0010);
+const uint64_t MM_STAT_FONW_MASK = ULL(0x0008);
+const uint64_t MM_STAT_FONR_MASK = ULL(0x0004);
+const uint64_t MM_STAT_ACV_MASK = ULL(0x0002);
+const uint64_t MM_STAT_WR_MASK = ULL(0x0001);
+inline int Opcode(AlphaISA::MachInst inst) { return inst >> 26 & 0x3f; }
+inline int Ra(AlphaISA::MachInst inst) { return inst >> 21 & 0x1f; }
+
+const Addr PalBase = 0x4000;
+const Addr PalMax = 0x10000;
+
+/* namespace EV5 */ }
+
+#endif // __ARCH_ALPHA_EV5_HH__
diff --git a/src/arch/alpha/faults.cc b/src/arch/alpha/faults.cc
new file mode 100644
index 000000000..0083aa9f3
--- /dev/null
+++ b/src/arch/alpha/faults.cc
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "arch/alpha/faults.hh"
+#include "cpu/exec_context.hh"
+#include "cpu/base.hh"
+#include "base/trace.hh"
+#if FULL_SYSTEM
+#include "arch/alpha/ev5.hh"
+#endif
+
+namespace AlphaISA
+{
+
+FaultName MachineCheckFault::_name = "mchk";
+FaultVect MachineCheckFault::_vect = 0x0401;
+FaultStat MachineCheckFault::_count;
+
+FaultName AlignmentFault::_name = "unalign";
+FaultVect AlignmentFault::_vect = 0x0301;
+FaultStat AlignmentFault::_count;
+
+FaultName ResetFault::_name = "reset";
+FaultVect ResetFault::_vect = 0x0001;
+FaultStat ResetFault::_count;
+
+FaultName ArithmeticFault::_name = "arith";
+FaultVect ArithmeticFault::_vect = 0x0501;
+FaultStat ArithmeticFault::_count;
+
+FaultName InterruptFault::_name = "interrupt";
+FaultVect InterruptFault::_vect = 0x0101;
+FaultStat InterruptFault::_count;
+
+FaultName NDtbMissFault::_name = "dtb_miss_single";
+FaultVect NDtbMissFault::_vect = 0x0201;
+FaultStat NDtbMissFault::_count;
+
+FaultName PDtbMissFault::_name = "dtb_miss_double";
+FaultVect PDtbMissFault::_vect = 0x0281;
+FaultStat PDtbMissFault::_count;
+
+FaultName DtbPageFault::_name = "dfault";
+FaultVect DtbPageFault::_vect = 0x0381;
+FaultStat DtbPageFault::_count;
+
+FaultName DtbAcvFault::_name = "dfault";
+FaultVect DtbAcvFault::_vect = 0x0381;
+FaultStat DtbAcvFault::_count;
+
+FaultName DtbAlignmentFault::_name = "unalign";
+FaultVect DtbAlignmentFault::_vect = 0x0301;
+FaultStat DtbAlignmentFault::_count;
+
+FaultName ItbMissFault::_name = "itbmiss";
+FaultVect ItbMissFault::_vect = 0x0181;
+FaultStat ItbMissFault::_count;
+
+FaultName ItbPageFault::_name = "itbmiss";
+FaultVect ItbPageFault::_vect = 0x0181;
+FaultStat ItbPageFault::_count;
+
+FaultName ItbAcvFault::_name = "iaccvio";
+FaultVect ItbAcvFault::_vect = 0x0081;
+FaultStat ItbAcvFault::_count;
+
+FaultName UnimplementedOpcodeFault::_name = "opdec";
+FaultVect UnimplementedOpcodeFault::_vect = 0x0481;
+FaultStat UnimplementedOpcodeFault::_count;
+
+FaultName FloatEnableFault::_name = "fen";
+FaultVect FloatEnableFault::_vect = 0x0581;
+FaultStat FloatEnableFault::_count;
+
+FaultName PalFault::_name = "pal";
+FaultVect PalFault::_vect = 0x2001;
+FaultStat PalFault::_count;
+
+FaultName IntegerOverflowFault::_name = "intover";
+FaultVect IntegerOverflowFault::_vect = 0x0501;
+FaultStat IntegerOverflowFault::_count;
+
+#if FULL_SYSTEM
+
+void AlphaFault::invoke(ExecContext * xc)
+{
+ FaultBase::invoke(xc);
+ countStat()++;
+
+ // exception restart address
+ if (setRestartAddress() || !xc->inPalMode())
+ xc->setMiscReg(AlphaISA::IPR_EXC_ADDR, xc->readPC());
+
+ if (skipFaultingInstruction()) {
+ // traps... skip faulting instruction.
+ xc->setMiscReg(AlphaISA::IPR_EXC_ADDR,
+ xc->readMiscReg(AlphaISA::IPR_EXC_ADDR) + 4);
+ }
+
+ xc->setPC(xc->readMiscReg(AlphaISA::IPR_PAL_BASE) + vect());
+ xc->setNextPC(xc->readPC() + sizeof(MachInst));
+}
+
+void ArithmeticFault::invoke(ExecContext * xc)
+{
+ FaultBase::invoke(xc);
+ panic("Arithmetic traps are unimplemented!");
+}
+
+void DtbFault::invoke(ExecContext * xc)
+{
+ // Set fault address and flags. Even though we're modeling an
+ // EV5, we use the EV6 technique of not latching fault registers
+ // on VPTE loads (instead of locking the registers until IPR_VA is
+ // read, like the EV5). The EV6 approach is cleaner and seems to
+ // work with EV5 PAL code, but not the other way around.
+ if (!xc->misspeculating()
+ && !(reqFlags & VPTE) && !(reqFlags & NO_FAULT)) {
+ // set VA register with faulting address
+ xc->setMiscReg(AlphaISA::IPR_VA, vaddr);
+
+ // set MM_STAT register flags
+ xc->setMiscReg(AlphaISA::IPR_MM_STAT,
+ (((EV5::Opcode(xc->getInst()) & 0x3f) << 11)
+ | ((EV5::Ra(xc->getInst()) & 0x1f) << 6)
+ | (flags & 0x3f)));
+
+ // set VA_FORM register with faulting formatted address
+ xc->setMiscReg(AlphaISA::IPR_VA_FORM,
+ xc->readMiscReg(AlphaISA::IPR_MVPTBR) | (vaddr.vpn() << 3));
+ }
+
+ AlphaFault::invoke(xc);
+}
+
+void ItbFault::invoke(ExecContext * xc)
+{
+ if (!xc->misspeculating()) {
+ xc->setMiscReg(AlphaISA::IPR_ITB_TAG, pc);
+ xc->setMiscReg(AlphaISA::IPR_IFAULT_VA_FORM,
+ xc->readMiscReg(AlphaISA::IPR_IVPTBR) |
+ (AlphaISA::VAddr(pc).vpn() << 3));
+ }
+
+ AlphaFault::invoke(xc);
+}
+
+#endif
+
+} // namespace AlphaISA
+
diff --git a/src/arch/alpha/faults.hh b/src/arch/alpha/faults.hh
new file mode 100644
index 000000000..e8ccc6b79
--- /dev/null
+++ b/src/arch/alpha/faults.hh
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ALPHA_FAULTS_HH__
+#define __ALPHA_FAULTS_HH__
+
+#include "arch/alpha/isa_traits.hh"
+#include "sim/faults.hh"
+
+// The design of the "name" and "vect" functions is in sim/faults.hh
+
+namespace AlphaISA
+{
+
+typedef const Addr FaultVect;
+
+class AlphaFault : public FaultBase
+{
+ protected:
+ virtual bool skipFaultingInstruction() {return false;}
+ virtual bool setRestartAddress() {return true;}
+ public:
+#if FULL_SYSTEM
+ void invoke(ExecContext * xc);
+#endif
+ virtual FaultVect vect() = 0;
+ virtual FaultStat & countStat() = 0;
+};
+
+class MachineCheckFault : public AlphaFault
+{
+ private:
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+ bool isMachineCheckFault() {return true;}
+};
+
+class AlignmentFault : public AlphaFault
+{
+ private:
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+ bool isAlignmentFault() {return true;}
+};
+
+static inline Fault genMachineCheckFault()
+{
+ return new MachineCheckFault;
+}
+
+static inline Fault genAlignmentFault()
+{
+ return new AlignmentFault;
+}
+
+class ResetFault : public AlphaFault
+{
+ private:
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+};
+
+class ArithmeticFault : public AlphaFault
+{
+ protected:
+ bool skipFaultingInstruction() {return true;}
+ private:
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+#if FULL_SYSTEM
+ void invoke(ExecContext * xc);
+#endif
+};
+
+class InterruptFault : public AlphaFault
+{
+ protected:
+ bool setRestartAddress() {return false;}
+ private:
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+};
+
+class DtbFault : public AlphaFault
+{
+#if FULL_SYSTEM
+ private:
+ AlphaISA::VAddr vaddr;
+ uint32_t reqFlags;
+ uint64_t flags;
+ public:
+ DtbFault(AlphaISA::VAddr _vaddr, uint32_t _reqFlags, uint64_t _flags)
+ : vaddr(_vaddr), reqFlags(_reqFlags), flags(_flags)
+ { }
+#endif
+ FaultName name() = 0;
+ FaultVect vect() = 0;
+ FaultStat & countStat() = 0;
+#if FULL_SYSTEM
+ void invoke(ExecContext * xc);
+#endif
+};
+
+class NDtbMissFault : public DtbFault
+{
+ private:
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+#if FULL_SYSTEM
+ NDtbMissFault(AlphaISA::VAddr vaddr, uint32_t reqFlags, uint64_t flags)
+ : DtbFault(vaddr, reqFlags, flags)
+ { }
+#endif
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+};
+
+class PDtbMissFault : public DtbFault
+{
+ private:
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+#if FULL_SYSTEM
+ PDtbMissFault(AlphaISA::VAddr vaddr, uint32_t reqFlags, uint64_t flags)
+ : DtbFault(vaddr, reqFlags, flags)
+ { }
+#endif
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+};
+
+class DtbPageFault : public DtbFault
+{
+ private:
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+#if FULL_SYSTEM
+ DtbPageFault(AlphaISA::VAddr vaddr, uint32_t reqFlags, uint64_t flags)
+ : DtbFault(vaddr, reqFlags, flags)
+ { }
+#endif
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+};
+
+class DtbAcvFault : public DtbFault
+{
+ private:
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+#if FULL_SYSTEM
+ DtbAcvFault(AlphaISA::VAddr vaddr, uint32_t reqFlags, uint64_t flags)
+ : DtbFault(vaddr, reqFlags, flags)
+ { }
+#endif
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+};
+
+class DtbAlignmentFault : public DtbFault
+{
+ private:
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+#if FULL_SYSTEM
+ DtbAlignmentFault(AlphaISA::VAddr vaddr, uint32_t reqFlags, uint64_t flags)
+ : DtbFault(vaddr, reqFlags, flags)
+ { }
+#endif
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+};
+
+class ItbFault : public AlphaFault
+{
+ private:
+ Addr pc;
+ public:
+ ItbFault(Addr _pc)
+ : pc(_pc)
+ { }
+ FaultName name() = 0;
+ FaultVect vect() = 0;
+ FaultStat & countStat() = 0;
+#if FULL_SYSTEM
+ void invoke(ExecContext * xc);
+#endif
+};
+
+class ItbMissFault : public ItbFault
+{
+ private:
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+ ItbMissFault(Addr pc)
+ : ItbFault(pc)
+ { }
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+};
+
+class ItbPageFault : public ItbFault
+{
+ private:
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+ ItbPageFault(Addr pc)
+ : ItbFault(pc)
+ { }
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+};
+
+class ItbAcvFault : public ItbFault
+{
+ private:
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+ ItbAcvFault(Addr pc)
+ : ItbFault(pc)
+ { }
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+};
+
+class UnimplementedOpcodeFault : public AlphaFault
+{
+ private:
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+};
+
+class FloatEnableFault : public AlphaFault
+{
+ private:
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+};
+
+class PalFault : public AlphaFault
+{
+ protected:
+ bool skipFaultingInstruction() {return true;}
+ private:
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+};
+
+class IntegerOverflowFault : public AlphaFault
+{
+ private:
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+};
+
+} // AlphaISA namespace
+
+#endif // __FAULTS_HH__
diff --git a/src/arch/alpha/freebsd/system.cc b/src/arch/alpha/freebsd/system.cc
new file mode 100644
index 000000000..3e50fb9a5
--- /dev/null
+++ b/src/arch/alpha/freebsd/system.cc
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * Modifications for the FreeBSD kernel.
+ * Based on kern/linux/linux_system.cc.
+ *
+ */
+
+#include "arch/alpha/system.hh"
+#include "arch/alpha/freebsd/system.hh"
+#include "base/loader/symtab.hh"
+#include "cpu/exec_context.hh"
+#include "mem/physical.hh"
+#include "mem/port.hh"
+#include "arch/isa_traits.hh"
+#include "sim/builder.hh"
+#include "sim/byteswap.hh"
+#include "arch/vtophys.hh"
+
+#define TIMER_FREQUENCY 1193180
+
+using namespace std;
+using namespace AlphaISA;
+
+FreebsdAlphaSystem::FreebsdAlphaSystem(Params *p)
+ : AlphaSystem(p)
+{
+ /**
+ * Any time DELAY is called just skip the function.
+ * Shouldn't we actually emulate the delay?
+ */
+ skipDelayEvent = addKernelFuncEvent<SkipFuncEvent>("DELAY");
+ skipCalibrateClocks =
+ addKernelFuncEvent<SkipCalibrateClocksEvent>("calibrate_clocks");
+}
+
+
+FreebsdAlphaSystem::~FreebsdAlphaSystem()
+{
+ delete skipDelayEvent;
+ delete skipCalibrateClocks;
+}
+
+
+void
+FreebsdAlphaSystem::doCalibrateClocks(ExecContext *xc)
+{
+ Addr ppc_vaddr = 0;
+ Addr timer_vaddr = 0;
+
+ ppc_vaddr = (Addr)xc->readIntReg(ArgumentReg1);
+ timer_vaddr = (Addr)xc->readIntReg(ArgumentReg2);
+
+ virtPort.write(ppc_vaddr, (uint32_t)Clock::Frequency);
+ virtPort.write(timer_vaddr, (uint32_t)TIMER_FREQUENCY);
+}
+
+
+void
+FreebsdAlphaSystem::SkipCalibrateClocksEvent::process(ExecContext *xc)
+{
+ SkipFuncEvent::process(xc);
+ ((FreebsdAlphaSystem *)xc->getSystemPtr())->doCalibrateClocks(xc);
+}
+
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(FreebsdAlphaSystem)
+
+ Param<Tick> boot_cpu_frequency;
+ SimObjectParam<PhysicalMemory *> physmem;
+
+ Param<string> kernel;
+ Param<string> console;
+ Param<string> pal;
+
+ Param<string> boot_osflags;
+ Param<string> readfile;
+ Param<unsigned int> init_param;
+
+ Param<uint64_t> system_type;
+ Param<uint64_t> system_rev;
+
+ Param<bool> bin;
+ VectorParam<string> binned_fns;
+ Param<bool> bin_int;
+
+END_DECLARE_SIM_OBJECT_PARAMS(FreebsdAlphaSystem)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(FreebsdAlphaSystem)
+
+ INIT_PARAM(boot_cpu_frequency, "Frequency of the boot CPU"),
+ INIT_PARAM(physmem, "phsyical memory"),
+ INIT_PARAM(kernel, "file that contains the kernel code"),
+ INIT_PARAM(console, "file that contains the console code"),
+ INIT_PARAM(pal, "file that contains palcode"),
+ INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot",
+ "a"),
+ INIT_PARAM_DFLT(readfile, "file to read startup script from", ""),
+ INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0),
+ INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 34),
+ INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10),
+ INIT_PARAM_DFLT(bin, "is this system to be binned", false),
+ INIT_PARAM(binned_fns, "functions to be broken down and binned"),
+ INIT_PARAM_DFLT(bin_int, "is interrupt code binned seperately?", true)
+
+END_INIT_SIM_OBJECT_PARAMS(FreebsdAlphaSystem)
+
+CREATE_SIM_OBJECT(FreebsdAlphaSystem)
+{
+ AlphaSystem::Params *p = new AlphaSystem::Params;
+ p->name = getInstanceName();
+ p->boot_cpu_frequency = boot_cpu_frequency;
+ p->physmem = physmem;
+ p->kernel_path = kernel;
+ p->console_path = console;
+ p->palcode = pal;
+ p->boot_osflags = boot_osflags;
+ p->init_param = init_param;
+ p->readfile = readfile;
+ p->system_type = system_type;
+ p->system_rev = system_rev;
+ p->bin = bin;
+ p->binned_fns = binned_fns;
+ p->bin_int = bin_int;
+ return new FreebsdAlphaSystem(p);
+}
+
+REGISTER_SIM_OBJECT("FreebsdAlphaSystem", FreebsdAlphaSystem)
+
diff --git a/src/arch/alpha/freebsd/system.hh b/src/arch/alpha/freebsd/system.hh
new file mode 100644
index 000000000..5d996955e
--- /dev/null
+++ b/src/arch/alpha/freebsd/system.hh
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __KERN_FREEBSD_FREEBSD_SYSTEM_HH__
+#define __KERN_FREEBSD_FREEBSD_SYSTEM_HH__
+
+#include "kern/system_events.hh"
+
+class FreebsdAlphaSystem : public AlphaSystem
+{
+ private:
+ class SkipCalibrateClocksEvent : public SkipFuncEvent
+ {
+ public:
+ SkipCalibrateClocksEvent(PCEventQueue *q, const std::string &desc,
+ Addr addr)
+ : SkipFuncEvent(q, desc, addr) {}
+ virtual void process(ExecContext *xc);
+ };
+
+ SkipFuncEvent *skipDelayEvent;
+ SkipCalibrateClocksEvent *skipCalibrateClocks;
+
+ public:
+ FreebsdAlphaSystem(Params *p);
+ ~FreebsdAlphaSystem();
+ void doCalibrateClocks(ExecContext *xc);
+
+};
+
+#endif // __KERN_FREEBSD_FREEBSD_SYSTEM_HH__
diff --git a/src/arch/alpha/isa/branch.isa b/src/arch/alpha/isa/branch.isa
new file mode 100644
index 000000000..b528df938
--- /dev/null
+++ b/src/arch/alpha/isa/branch.isa
@@ -0,0 +1,259 @@
+// -*- mode:c++ -*-
+
+// Copyright (c) 2003-2005 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+output header {{
+
+ /**
+ * Base class for instructions whose disassembly is not purely a
+ * function of the machine instruction (i.e., it depends on the
+ * PC). This class overrides the disassemble() method to check
+ * the PC and symbol table values before re-using a cached
+ * disassembly string. This is necessary for branches and jumps,
+ * where the disassembly string includes the target address (which
+ * may depend on the PC and/or symbol table).
+ */
+ class PCDependentDisassembly : public AlphaStaticInst
+ {
+ protected:
+ /// Cached program counter from last disassembly
+ mutable Addr cachedPC;
+ /// Cached symbol table pointer from last disassembly
+ mutable const SymbolTable *cachedSymtab;
+
+ /// Constructor
+ PCDependentDisassembly(const char *mnem, ExtMachInst _machInst,
+ OpClass __opClass)
+ : AlphaStaticInst(mnem, _machInst, __opClass),
+ cachedPC(0), cachedSymtab(0)
+ {
+ }
+
+ const std::string &
+ disassemble(Addr pc, const SymbolTable *symtab) const;
+ };
+
+ /**
+ * Base class for branches (PC-relative control transfers),
+ * conditional or unconditional.
+ */
+ class Branch : public PCDependentDisassembly
+ {
+ protected:
+ /// Displacement to target address (signed).
+ int32_t disp;
+
+ /// Constructor.
+ Branch(const char *mnem, ExtMachInst _machInst, OpClass __opClass)
+ : PCDependentDisassembly(mnem, _machInst, __opClass),
+ disp(BRDISP << 2)
+ {
+ }
+
+ Addr branchTarget(Addr branchPC) const;
+
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+
+ /**
+ * Base class for jumps (register-indirect control transfers). In
+ * the Alpha ISA, these are always unconditional.
+ */
+ class Jump : public PCDependentDisassembly
+ {
+ protected:
+
+ /// Displacement to target address (signed).
+ int32_t disp;
+
+ public:
+ /// Constructor
+ Jump(const char *mnem, ExtMachInst _machInst, OpClass __opClass)
+ : PCDependentDisassembly(mnem, _machInst, __opClass),
+ disp(BRDISP)
+ {
+ }
+
+ Addr branchTarget(ExecContext *xc) const;
+
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+}};
+
+output decoder {{
+ Addr
+ Branch::branchTarget(Addr branchPC) const
+ {
+ return branchPC + 4 + disp;
+ }
+
+ Addr
+ Jump::branchTarget(ExecContext *xc) const
+ {
+ Addr NPC = xc->readPC() + 4;
+ uint64_t Rb = xc->readIntReg(_srcRegIdx[0]);
+ return (Rb & ~3) | (NPC & 1);
+ }
+
+ const std::string &
+ PCDependentDisassembly::disassemble(Addr pc,
+ const SymbolTable *symtab) const
+ {
+ if (!cachedDisassembly ||
+ pc != cachedPC || symtab != cachedSymtab)
+ {
+ if (cachedDisassembly)
+ delete cachedDisassembly;
+
+ cachedDisassembly =
+ new std::string(generateDisassembly(pc, symtab));
+ cachedPC = pc;
+ cachedSymtab = symtab;
+ }
+
+ return *cachedDisassembly;
+ }
+
+ std::string
+ Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+ std::stringstream ss;
+
+ ccprintf(ss, "%-10s ", mnemonic);
+
+ // There's only one register arg (RA), but it could be
+ // either a source (the condition for conditional
+ // branches) or a destination (the link reg for
+ // unconditional branches)
+ if (_numSrcRegs > 0) {
+ printReg(ss, _srcRegIdx[0]);
+ ss << ",";
+ }
+ else if (_numDestRegs > 0) {
+ printReg(ss, _destRegIdx[0]);
+ ss << ",";
+ }
+
+#ifdef SS_COMPATIBLE_DISASSEMBLY
+ if (_numSrcRegs == 0 && _numDestRegs == 0) {
+ printReg(ss, 31);
+ ss << ",";
+ }
+#endif
+
+ Addr target = pc + 4 + disp;
+
+ std::string str;
+ if (symtab && symtab->findSymbol(target, str))
+ ss << str;
+ else
+ ccprintf(ss, "0x%x", target);
+
+ return ss.str();
+ }
+
+ std::string
+ Jump::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+ std::stringstream ss;
+
+ ccprintf(ss, "%-10s ", mnemonic);
+
+#ifdef SS_COMPATIBLE_DISASSEMBLY
+ if (_numDestRegs == 0) {
+ printReg(ss, 31);
+ ss << ",";
+ }
+#endif
+
+ if (_numDestRegs > 0) {
+ printReg(ss, _destRegIdx[0]);
+ ss << ",";
+ }
+
+ ccprintf(ss, "(r%d)", RB);
+
+ return ss.str();
+ }
+}};
+
+def template JumpOrBranchDecode {{
+ return (RA == 31)
+ ? (StaticInst *)new %(class_name)s(machInst)
+ : (StaticInst *)new %(class_name)sAndLink(machInst);
+}};
+
+def format CondBranch(code) {{
+ code = 'bool cond;\n' + code + '\nif (cond) NPC = NPC + disp;\n';
+ iop = InstObjParams(name, Name, 'Branch', CodeBlock(code),
+ ('IsDirectControl', 'IsCondControl'))
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
+}};
+
+let {{
+def UncondCtrlBase(name, Name, base_class, npc_expr, flags):
+ # Declare basic control transfer w/o link (i.e. link reg is R31)
+ nolink_code = 'NPC = %s;\n' % npc_expr
+ nolink_iop = InstObjParams(name, Name, base_class,
+ CodeBlock(nolink_code), flags)
+ header_output = BasicDeclare.subst(nolink_iop)
+ decoder_output = BasicConstructor.subst(nolink_iop)
+ exec_output = BasicExecute.subst(nolink_iop)
+
+ # Generate declaration of '*AndLink' version, append to decls
+ link_code = 'Ra = NPC & ~3;\n' + nolink_code
+ link_iop = InstObjParams(name, Name + 'AndLink', base_class,
+ CodeBlock(link_code), flags)
+ header_output += BasicDeclare.subst(link_iop)
+ decoder_output += BasicConstructor.subst(link_iop)
+ exec_output += BasicExecute.subst(link_iop)
+
+ # need to use link_iop for the decode template since it is expecting
+ # the shorter version of class_name (w/o "AndLink")
+
+ return (header_output, decoder_output,
+ JumpOrBranchDecode.subst(nolink_iop), exec_output)
+}};
+
+def format UncondBranch(*flags) {{
+ flags += ('IsUncondControl', 'IsDirectControl')
+ (header_output, decoder_output, decode_block, exec_output) = \
+ UncondCtrlBase(name, Name, 'Branch', 'NPC + disp', flags)
+}};
+
+def format Jump(*flags) {{
+ flags += ('IsUncondControl', 'IsIndirectControl')
+ (header_output, decoder_output, decode_block, exec_output) = \
+ UncondCtrlBase(name, Name, 'Jump', '(Rb & ~3) | (NPC & 1)', flags)
+}};
+
+
diff --git a/src/arch/alpha/isa/decoder.isa b/src/arch/alpha/isa/decoder.isa
new file mode 100644
index 000000000..1adcfb948
--- /dev/null
+++ b/src/arch/alpha/isa/decoder.isa
@@ -0,0 +1,819 @@
+// -*- mode:c++ -*-
+
+// Copyright (c) 2003-2006 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+decode OPCODE default Unknown::unknown() {
+
+ format LoadAddress {
+ 0x08: lda({{ Ra = Rb + disp; }});
+ 0x09: ldah({{ Ra = Rb + (disp << 16); }});
+ }
+
+ format LoadOrNop {
+ 0x0a: ldbu({{ Ra.uq = Mem.ub; }});
+ 0x0c: ldwu({{ Ra.uq = Mem.uw; }});
+ 0x0b: ldq_u({{ Ra = Mem.uq; }}, ea_code = {{ EA = (Rb + disp) & ~7; }});
+ 0x23: ldt({{ Fa = Mem.df; }});
+ 0x2a: ldl_l({{ Ra.sl = Mem.sl; }}, mem_flags = LOCKED);
+ 0x2b: ldq_l({{ Ra.uq = Mem.uq; }}, mem_flags = LOCKED);
+ 0x20: MiscPrefetch::copy_load({{ EA = Ra; }},
+ {{ fault = xc->copySrcTranslate(EA); }},
+ inst_flags = [IsMemRef, IsLoad, IsCopy]);
+ }
+
+ format LoadOrPrefetch {
+ 0x28: ldl({{ Ra.sl = Mem.sl; }});
+ 0x29: ldq({{ Ra.uq = Mem.uq; }}, pf_flags = EVICT_NEXT);
+ // IsFloating flag on lds gets the prefetch to disassemble
+ // using f31 instead of r31... funcitonally it's unnecessary
+ 0x22: lds({{ Fa.uq = s_to_t(Mem.ul); }},
+ pf_flags = PF_EXCLUSIVE, inst_flags = IsFloating);
+ }
+
+ format Store {
+ 0x0e: stb({{ Mem.ub = Ra<7:0>; }});
+ 0x0d: stw({{ Mem.uw = Ra<15:0>; }});
+ 0x2c: stl({{ Mem.ul = Ra<31:0>; }});
+ 0x2d: stq({{ Mem.uq = Ra.uq; }});
+ 0x0f: stq_u({{ Mem.uq = Ra.uq; }}, {{ EA = (Rb + disp) & ~7; }});
+ 0x26: sts({{ Mem.ul = t_to_s(Fa.uq); }});
+ 0x27: stt({{ Mem.df = Fa; }});
+ 0x24: MiscPrefetch::copy_store({{ EA = Rb; }},
+ {{ fault = xc->copy(EA); }},
+ inst_flags = [IsMemRef, IsStore, IsCopy]);
+ }
+
+ format StoreCond {
+ 0x2e: stl_c({{ Mem.ul = Ra<31:0>; }},
+ {{
+ uint64_t tmp = write_result;
+ // see stq_c
+ Ra = (tmp == 0 || tmp == 1) ? tmp : Ra;
+ }}, mem_flags = LOCKED);
+ 0x2f: stq_c({{ Mem.uq = Ra; }},
+ {{
+ uint64_t tmp = write_result;
+ // If the write operation returns 0 or 1, then
+ // this was a conventional store conditional,
+ // and the value indicates the success/failure
+ // of the operation. If another value is
+ // returned, then this was a Turbolaser
+ // mailbox access, and we don't update the
+ // result register at all.
+ Ra = (tmp == 0 || tmp == 1) ? tmp : Ra;
+ }}, mem_flags = LOCKED);
+ }
+
+ format IntegerOperate {
+
+ 0x10: decode INTFUNC { // integer arithmetic operations
+
+ 0x00: addl({{ Rc.sl = Ra.sl + Rb_or_imm.sl; }});
+ 0x40: addlv({{
+ uint32_t tmp = Ra.sl + Rb_or_imm.sl;
+ // signed overflow occurs when operands have same sign
+ // and sign of result does not match.
+ if (Ra.sl<31:> == Rb_or_imm.sl<31:> && tmp<31:> != Ra.sl<31:>)
+ fault = new IntegerOverflowFault;
+ Rc.sl = tmp;
+ }});
+ 0x02: s4addl({{ Rc.sl = (Ra.sl << 2) + Rb_or_imm.sl; }});
+ 0x12: s8addl({{ Rc.sl = (Ra.sl << 3) + Rb_or_imm.sl; }});
+
+ 0x20: addq({{ Rc = Ra + Rb_or_imm; }});
+ 0x60: addqv({{
+ uint64_t tmp = Ra + Rb_or_imm;
+ // signed overflow occurs when operands have same sign
+ // and sign of result does not match.
+ if (Ra<63:> == Rb_or_imm<63:> && tmp<63:> != Ra<63:>)
+ fault = new IntegerOverflowFault;
+ Rc = tmp;
+ }});
+ 0x22: s4addq({{ Rc = (Ra << 2) + Rb_or_imm; }});
+ 0x32: s8addq({{ Rc = (Ra << 3) + Rb_or_imm; }});
+
+ 0x09: subl({{ Rc.sl = Ra.sl - Rb_or_imm.sl; }});
+ 0x49: sublv({{
+ uint32_t tmp = Ra.sl - Rb_or_imm.sl;
+ // signed overflow detection is same as for add,
+ // except we need to look at the *complemented*
+ // sign bit of the subtrahend (Rb), i.e., if the initial
+ // signs are the *same* then no overflow can occur
+ if (Ra.sl<31:> != Rb_or_imm.sl<31:> && tmp<31:> != Ra.sl<31:>)
+ fault = new IntegerOverflowFault;
+ Rc.sl = tmp;
+ }});
+ 0x0b: s4subl({{ Rc.sl = (Ra.sl << 2) - Rb_or_imm.sl; }});
+ 0x1b: s8subl({{ Rc.sl = (Ra.sl << 3) - Rb_or_imm.sl; }});
+
+ 0x29: subq({{ Rc = Ra - Rb_or_imm; }});
+ 0x69: subqv({{
+ uint64_t tmp = Ra - Rb_or_imm;
+ // signed overflow detection is same as for add,
+ // except we need to look at the *complemented*
+ // sign bit of the subtrahend (Rb), i.e., if the initial
+ // signs are the *same* then no overflow can occur
+ if (Ra<63:> != Rb_or_imm<63:> && tmp<63:> != Ra<63:>)
+ fault = new IntegerOverflowFault;
+ Rc = tmp;
+ }});
+ 0x2b: s4subq({{ Rc = (Ra << 2) - Rb_or_imm; }});
+ 0x3b: s8subq({{ Rc = (Ra << 3) - Rb_or_imm; }});
+
+ 0x2d: cmpeq({{ Rc = (Ra == Rb_or_imm); }});
+ 0x6d: cmple({{ Rc = (Ra.sq <= Rb_or_imm.sq); }});
+ 0x4d: cmplt({{ Rc = (Ra.sq < Rb_or_imm.sq); }});
+ 0x3d: cmpule({{ Rc = (Ra.uq <= Rb_or_imm.uq); }});
+ 0x1d: cmpult({{ Rc = (Ra.uq < Rb_or_imm.uq); }});
+
+ 0x0f: cmpbge({{
+ int hi = 7;
+ int lo = 0;
+ uint64_t tmp = 0;
+ for (int i = 0; i < 8; ++i) {
+ tmp |= (Ra.uq<hi:lo> >= Rb_or_imm.uq<hi:lo>) << i;
+ hi += 8;
+ lo += 8;
+ }
+ Rc = tmp;
+ }});
+ }
+
+ 0x11: decode INTFUNC { // integer logical operations
+
+ 0x00: and({{ Rc = Ra & Rb_or_imm; }});
+ 0x08: bic({{ Rc = Ra & ~Rb_or_imm; }});
+ 0x20: bis({{ Rc = Ra | Rb_or_imm; }});
+ 0x28: ornot({{ Rc = Ra | ~Rb_or_imm; }});
+ 0x40: xor({{ Rc = Ra ^ Rb_or_imm; }});
+ 0x48: eqv({{ Rc = Ra ^ ~Rb_or_imm; }});
+
+ // conditional moves
+ 0x14: cmovlbs({{ Rc = ((Ra & 1) == 1) ? Rb_or_imm : Rc; }});
+ 0x16: cmovlbc({{ Rc = ((Ra & 1) == 0) ? Rb_or_imm : Rc; }});
+ 0x24: cmoveq({{ Rc = (Ra == 0) ? Rb_or_imm : Rc; }});
+ 0x26: cmovne({{ Rc = (Ra != 0) ? Rb_or_imm : Rc; }});
+ 0x44: cmovlt({{ Rc = (Ra.sq < 0) ? Rb_or_imm : Rc; }});
+ 0x46: cmovge({{ Rc = (Ra.sq >= 0) ? Rb_or_imm : Rc; }});
+ 0x64: cmovle({{ Rc = (Ra.sq <= 0) ? Rb_or_imm : Rc; }});
+ 0x66: cmovgt({{ Rc = (Ra.sq > 0) ? Rb_or_imm : Rc; }});
+
+ // For AMASK, RA must be R31.
+ 0x61: decode RA {
+ 31: amask({{ Rc = Rb_or_imm & ~ULL(0x17); }});
+ }
+
+ // For IMPLVER, RA must be R31 and the B operand
+ // must be the immediate value 1.
+ 0x6c: decode RA {
+ 31: decode IMM {
+ 1: decode INTIMM {
+ // return EV5 for FULL_SYSTEM and EV6 otherwise
+ 1: implver({{
+#if FULL_SYSTEM
+ Rc = 1;
+#else
+ Rc = 2;
+#endif
+ }});
+ }
+ }
+ }
+
+#if FULL_SYSTEM
+ // The mysterious 11.25...
+ 0x25: WarnUnimpl::eleven25();
+#endif
+ }
+
+ 0x12: decode INTFUNC {
+ 0x39: sll({{ Rc = Ra << Rb_or_imm<5:0>; }});
+ 0x34: srl({{ Rc = Ra.uq >> Rb_or_imm<5:0>; }});
+ 0x3c: sra({{ Rc = Ra.sq >> Rb_or_imm<5:0>; }});
+
+ 0x02: mskbl({{ Rc = Ra & ~(mask( 8) << (Rb_or_imm<2:0> * 8)); }});
+ 0x12: mskwl({{ Rc = Ra & ~(mask(16) << (Rb_or_imm<2:0> * 8)); }});
+ 0x22: mskll({{ Rc = Ra & ~(mask(32) << (Rb_or_imm<2:0> * 8)); }});
+ 0x32: mskql({{ Rc = Ra & ~(mask(64) << (Rb_or_imm<2:0> * 8)); }});
+
+ 0x52: mskwh({{
+ int bv = Rb_or_imm<2:0>;
+ Rc = bv ? (Ra & ~(mask(16) >> (64 - 8 * bv))) : Ra;
+ }});
+ 0x62: msklh({{
+ int bv = Rb_or_imm<2:0>;
+ Rc = bv ? (Ra & ~(mask(32) >> (64 - 8 * bv))) : Ra;
+ }});
+ 0x72: mskqh({{
+ int bv = Rb_or_imm<2:0>;
+ Rc = bv ? (Ra & ~(mask(64) >> (64 - 8 * bv))) : Ra;
+ }});
+
+ 0x06: extbl({{ Rc = (Ra.uq >> (Rb_or_imm<2:0> * 8))< 7:0>; }});
+ 0x16: extwl({{ Rc = (Ra.uq >> (Rb_or_imm<2:0> * 8))<15:0>; }});
+ 0x26: extll({{ Rc = (Ra.uq >> (Rb_or_imm<2:0> * 8))<31:0>; }});
+ 0x36: extql({{ Rc = (Ra.uq >> (Rb_or_imm<2:0> * 8)); }});
+
+ 0x5a: extwh({{
+ Rc = (Ra << (64 - (Rb_or_imm<2:0> * 8))<5:0>)<15:0>; }});
+ 0x6a: extlh({{
+ Rc = (Ra << (64 - (Rb_or_imm<2:0> * 8))<5:0>)<31:0>; }});
+ 0x7a: extqh({{
+ Rc = (Ra << (64 - (Rb_or_imm<2:0> * 8))<5:0>); }});
+
+ 0x0b: insbl({{ Rc = Ra< 7:0> << (Rb_or_imm<2:0> * 8); }});
+ 0x1b: inswl({{ Rc = Ra<15:0> << (Rb_or_imm<2:0> * 8); }});
+ 0x2b: insll({{ Rc = Ra<31:0> << (Rb_or_imm<2:0> * 8); }});
+ 0x3b: insql({{ Rc = Ra << (Rb_or_imm<2:0> * 8); }});
+
+ 0x57: inswh({{
+ int bv = Rb_or_imm<2:0>;
+ Rc = bv ? (Ra.uq<15:0> >> (64 - 8 * bv)) : 0;
+ }});
+ 0x67: inslh({{
+ int bv = Rb_or_imm<2:0>;
+ Rc = bv ? (Ra.uq<31:0> >> (64 - 8 * bv)) : 0;
+ }});
+ 0x77: insqh({{
+ int bv = Rb_or_imm<2:0>;
+ Rc = bv ? (Ra.uq >> (64 - 8 * bv)) : 0;
+ }});
+
+ 0x30: zap({{
+ uint64_t zapmask = 0;
+ for (int i = 0; i < 8; ++i) {
+ if (Rb_or_imm<i:>)
+ zapmask |= (mask(8) << (i * 8));
+ }
+ Rc = Ra & ~zapmask;
+ }});
+ 0x31: zapnot({{
+ uint64_t zapmask = 0;
+ for (int i = 0; i < 8; ++i) {
+ if (!Rb_or_imm<i:>)
+ zapmask |= (mask(8) << (i * 8));
+ }
+ Rc = Ra & ~zapmask;
+ }});
+ }
+
+ 0x13: decode INTFUNC { // integer multiplies
+ 0x00: mull({{ Rc.sl = Ra.sl * Rb_or_imm.sl; }}, IntMultOp);
+ 0x20: mulq({{ Rc = Ra * Rb_or_imm; }}, IntMultOp);
+ 0x30: umulh({{
+ uint64_t hi, lo;
+ mul128(Ra, Rb_or_imm, hi, lo);
+ Rc = hi;
+ }}, IntMultOp);
+ 0x40: mullv({{
+ // 32-bit multiply with trap on overflow
+ int64_t Rax = Ra.sl; // sign extended version of Ra.sl
+ int64_t Rbx = Rb_or_imm.sl;
+ int64_t tmp = Rax * Rbx;
+ // To avoid overflow, all the upper 32 bits must match
+ // the sign bit of the lower 32. We code this as
+ // checking the upper 33 bits for all 0s or all 1s.
+ uint64_t sign_bits = tmp<63:31>;
+ if (sign_bits != 0 && sign_bits != mask(33))
+ fault = new IntegerOverflowFault;
+ Rc.sl = tmp<31:0>;
+ }}, IntMultOp);
+ 0x60: mulqv({{
+ // 64-bit multiply with trap on overflow
+ uint64_t hi, lo;
+ mul128(Ra, Rb_or_imm, hi, lo);
+ // all the upper 64 bits must match the sign bit of
+ // the lower 64
+ if (!((hi == 0 && lo<63:> == 0) ||
+ (hi == mask(64) && lo<63:> == 1)))
+ fault = new IntegerOverflowFault;
+ Rc = lo;
+ }}, IntMultOp);
+ }
+
+ 0x1c: decode INTFUNC {
+ 0x00: decode RA { 31: sextb({{ Rc.sb = Rb_or_imm< 7:0>; }}); }
+ 0x01: decode RA { 31: sextw({{ Rc.sw = Rb_or_imm<15:0>; }}); }
+ 0x32: ctlz({{
+ uint64_t count = 0;
+ uint64_t temp = Rb;
+ if (temp<63:32>) temp >>= 32; else count += 32;
+ if (temp<31:16>) temp >>= 16; else count += 16;
+ if (temp<15:8>) temp >>= 8; else count += 8;
+ if (temp<7:4>) temp >>= 4; else count += 4;
+ if (temp<3:2>) temp >>= 2; else count += 2;
+ if (temp<1:1>) temp >>= 1; else count += 1;
+ if ((temp<0:0>) != 0x1) count += 1;
+ Rc = count;
+ }}, IntAluOp);
+
+ 0x33: cttz({{
+ uint64_t count = 0;
+ uint64_t temp = Rb;
+ if (!(temp<31:0>)) { temp >>= 32; count += 32; }
+ if (!(temp<15:0>)) { temp >>= 16; count += 16; }
+ if (!(temp<7:0>)) { temp >>= 8; count += 8; }
+ if (!(temp<3:0>)) { temp >>= 4; count += 4; }
+ if (!(temp<1:0>)) { temp >>= 2; count += 2; }
+ if (!(temp<0:0> & ULL(0x1))) count += 1;
+ Rc = count;
+ }}, IntAluOp);
+
+ format FailUnimpl {
+ 0x30: ctpop();
+ 0x31: perr();
+ 0x34: unpkbw();
+ 0x35: unpkbl();
+ 0x36: pkwb();
+ 0x37: pklb();
+ 0x38: minsb8();
+ 0x39: minsw4();
+ 0x3a: minub8();
+ 0x3b: minuw4();
+ 0x3c: maxub8();
+ 0x3d: maxuw4();
+ 0x3e: maxsb8();
+ 0x3f: maxsw4();
+ }
+
+ format BasicOperateWithNopCheck {
+ 0x70: decode RB {
+ 31: ftoit({{ Rc = Fa.uq; }}, FloatCvtOp);
+ }
+ 0x78: decode RB {
+ 31: ftois({{ Rc.sl = t_to_s(Fa.uq); }},
+ FloatCvtOp);
+ }
+ }
+ }
+ }
+
+ // Conditional branches.
+ format CondBranch {
+ 0x39: beq({{ cond = (Ra == 0); }});
+ 0x3d: bne({{ cond = (Ra != 0); }});
+ 0x3e: bge({{ cond = (Ra.sq >= 0); }});
+ 0x3f: bgt({{ cond = (Ra.sq > 0); }});
+ 0x3b: ble({{ cond = (Ra.sq <= 0); }});
+ 0x3a: blt({{ cond = (Ra.sq < 0); }});
+ 0x38: blbc({{ cond = ((Ra & 1) == 0); }});
+ 0x3c: blbs({{ cond = ((Ra & 1) == 1); }});
+
+ 0x31: fbeq({{ cond = (Fa == 0); }});
+ 0x35: fbne({{ cond = (Fa != 0); }});
+ 0x36: fbge({{ cond = (Fa >= 0); }});
+ 0x37: fbgt({{ cond = (Fa > 0); }});
+ 0x33: fble({{ cond = (Fa <= 0); }});
+ 0x32: fblt({{ cond = (Fa < 0); }});
+ }
+
+ // unconditional branches
+ format UncondBranch {
+ 0x30: br();
+ 0x34: bsr(IsCall);
+ }
+
+ // indirect branches
+ 0x1a: decode JMPFUNC {
+ format Jump {
+ 0: jmp();
+ 1: jsr(IsCall);
+ 2: ret(IsReturn);
+ 3: jsr_coroutine(IsCall, IsReturn);
+ }
+ }
+
+ // Square root and integer-to-FP moves
+ 0x14: decode FP_SHORTFUNC {
+ // Integer to FP register moves must have RB == 31
+ 0x4: decode RB {
+ 31: decode FP_FULLFUNC {
+ format BasicOperateWithNopCheck {
+ 0x004: itofs({{ Fc.uq = s_to_t(Ra.ul); }}, FloatCvtOp);
+ 0x024: itoft({{ Fc.uq = Ra.uq; }}, FloatCvtOp);
+ 0x014: FailUnimpl::itoff(); // VAX-format conversion
+ }
+ }
+ }
+
+ // Square root instructions must have FA == 31
+ 0xb: decode FA {
+ 31: decode FP_TYPEFUNC {
+ format FloatingPointOperate {
+#if SS_COMPATIBLE_FP
+ 0x0b: sqrts({{
+ if (Fb < 0.0)
+ fault = new ArithmeticFault;
+ Fc = sqrt(Fb);
+ }}, FloatSqrtOp);
+#else
+ 0x0b: sqrts({{
+ if (Fb.sf < 0.0)
+ fault = new ArithmeticFault;
+ Fc.sf = sqrt(Fb.sf);
+ }}, FloatSqrtOp);
+#endif
+ 0x2b: sqrtt({{
+ if (Fb < 0.0)
+ fault = new ArithmeticFault;
+ Fc = sqrt(Fb);
+ }}, FloatSqrtOp);
+ }
+ }
+ }
+
+ // VAX-format sqrtf and sqrtg are not implemented
+ 0xa: FailUnimpl::sqrtfg();
+ }
+
+ // IEEE floating point
+ 0x16: decode FP_SHORTFUNC_TOP2 {
+ // The top two bits of the short function code break this
+ // space into four groups: binary ops, compares, reserved, and
+ // conversions. See Table 4-12 of AHB. There are different
+ // special cases in these different groups, so we decode on
+ // these top two bits first just to select a decode strategy.
+ // Most of these instructions may have various trapping and
+ // rounding mode flags set; these are decoded in the
+ // FloatingPointDecode template used by the
+ // FloatingPointOperate format.
+
+ // add/sub/mul/div: just decode on the short function code
+ // and source type. All valid trapping and rounding modes apply.
+ 0: decode FP_TRAPMODE {
+ // check for valid trapping modes here
+ 0,1,5,7: decode FP_TYPEFUNC {
+ format FloatingPointOperate {
+#if SS_COMPATIBLE_FP
+ 0x00: adds({{ Fc = Fa + Fb; }});
+ 0x01: subs({{ Fc = Fa - Fb; }});
+ 0x02: muls({{ Fc = Fa * Fb; }}, FloatMultOp);
+ 0x03: divs({{ Fc = Fa / Fb; }}, FloatDivOp);
+#else
+ 0x00: adds({{ Fc.sf = Fa.sf + Fb.sf; }});
+ 0x01: subs({{ Fc.sf = Fa.sf - Fb.sf; }});
+ 0x02: muls({{ Fc.sf = Fa.sf * Fb.sf; }}, FloatMultOp);
+ 0x03: divs({{ Fc.sf = Fa.sf / Fb.sf; }}, FloatDivOp);
+#endif
+
+ 0x20: addt({{ Fc = Fa + Fb; }});
+ 0x21: subt({{ Fc = Fa - Fb; }});
+ 0x22: mult({{ Fc = Fa * Fb; }}, FloatMultOp);
+ 0x23: divt({{ Fc = Fa / Fb; }}, FloatDivOp);
+ }
+ }
+ }
+
+ // Floating-point compare instructions must have the default
+ // rounding mode, and may use the default trapping mode or
+ // /SU. Both trapping modes are treated the same by M5; the
+ // only difference on the real hardware (as far a I can tell)
+ // is that without /SU you'd get an imprecise trap if you
+ // tried to compare a NaN with something else (instead of an
+ // "unordered" result).
+ 1: decode FP_FULLFUNC {
+ format BasicOperateWithNopCheck {
+ 0x0a5, 0x5a5: cmpteq({{ Fc = (Fa == Fb) ? 2.0 : 0.0; }},
+ FloatCmpOp);
+ 0x0a7, 0x5a7: cmptle({{ Fc = (Fa <= Fb) ? 2.0 : 0.0; }},
+ FloatCmpOp);
+ 0x0a6, 0x5a6: cmptlt({{ Fc = (Fa < Fb) ? 2.0 : 0.0; }},
+ FloatCmpOp);
+ 0x0a4, 0x5a4: cmptun({{ // unordered
+ Fc = (!(Fa < Fb) && !(Fa == Fb) && !(Fa > Fb)) ? 2.0 : 0.0;
+ }}, FloatCmpOp);
+ }
+ }
+
+ // The FP-to-integer and integer-to-FP conversion insts
+ // require that FA be 31.
+ 3: decode FA {
+ 31: decode FP_TYPEFUNC {
+ format FloatingPointOperate {
+ 0x2f: decode FP_ROUNDMODE {
+ format FPFixedRounding {
+ // "chopped" i.e. round toward zero
+ 0: cvttq({{ Fc.sq = (int64_t)trunc(Fb); }},
+ Chopped);
+ // round to minus infinity
+ 1: cvttq({{ Fc.sq = (int64_t)floor(Fb); }},
+ MinusInfinity);
+ }
+ default: cvttq({{ Fc.sq = (int64_t)nearbyint(Fb); }});
+ }
+
+ // The cvtts opcode is overloaded to be cvtst if the trap
+ // mode is 2 or 6 (which are not valid otherwise)
+ 0x2c: decode FP_FULLFUNC {
+ format BasicOperateWithNopCheck {
+ // trap on denorm version "cvtst/s" is
+ // simulated same as cvtst
+ 0x2ac, 0x6ac: cvtst({{ Fc = Fb.sf; }});
+ }
+ default: cvtts({{ Fc.sf = Fb; }});
+ }
+
+ // The trapping mode for integer-to-FP conversions
+ // must be /SUI or nothing; /U and /SU are not
+ // allowed. The full set of rounding modes are
+ // supported though.
+ 0x3c: decode FP_TRAPMODE {
+ 0,7: cvtqs({{ Fc.sf = Fb.sq; }});
+ }
+ 0x3e: decode FP_TRAPMODE {
+ 0,7: cvtqt({{ Fc = Fb.sq; }});
+ }
+ }
+ }
+ }
+ }
+
+ // misc FP operate
+ 0x17: decode FP_FULLFUNC {
+ format BasicOperateWithNopCheck {
+ 0x010: cvtlq({{
+ Fc.sl = (Fb.uq<63:62> << 30) | Fb.uq<58:29>;
+ }});
+ 0x030: cvtql({{
+ Fc.uq = (Fb.uq<31:30> << 62) | (Fb.uq<29:0> << 29);
+ }});
+
+ // We treat the precise & imprecise trapping versions of
+ // cvtql identically.
+ 0x130, 0x530: cvtqlv({{
+ // To avoid overflow, all the upper 32 bits must match
+ // the sign bit of the lower 32. We code this as
+ // checking the upper 33 bits for all 0s or all 1s.
+ uint64_t sign_bits = Fb.uq<63:31>;
+ if (sign_bits != 0 && sign_bits != mask(33))
+ fault = new IntegerOverflowFault;
+ Fc.uq = (Fb.uq<31:30> << 62) | (Fb.uq<29:0> << 29);
+ }});
+
+ 0x020: cpys({{ // copy sign
+ Fc.uq = (Fa.uq<63:> << 63) | Fb.uq<62:0>;
+ }});
+ 0x021: cpysn({{ // copy sign negated
+ Fc.uq = (~Fa.uq<63:> << 63) | Fb.uq<62:0>;
+ }});
+ 0x022: cpyse({{ // copy sign and exponent
+ Fc.uq = (Fa.uq<63:52> << 52) | Fb.uq<51:0>;
+ }});
+
+ 0x02a: fcmoveq({{ Fc = (Fa == 0) ? Fb : Fc; }});
+ 0x02b: fcmovne({{ Fc = (Fa != 0) ? Fb : Fc; }});
+ 0x02c: fcmovlt({{ Fc = (Fa < 0) ? Fb : Fc; }});
+ 0x02d: fcmovge({{ Fc = (Fa >= 0) ? Fb : Fc; }});
+ 0x02e: fcmovle({{ Fc = (Fa <= 0) ? Fb : Fc; }});
+ 0x02f: fcmovgt({{ Fc = (Fa > 0) ? Fb : Fc; }});
+
+ 0x024: mt_fpcr({{ FPCR = Fa.uq; }});
+ 0x025: mf_fpcr({{ Fa.uq = FPCR; }});
+ }
+ }
+
+ // miscellaneous mem-format ops
+ 0x18: decode MEMFUNC {
+ format WarnUnimpl {
+ 0x8000: fetch();
+ 0xa000: fetch_m();
+ 0xe800: ecb();
+ }
+
+ format MiscPrefetch {
+ 0xf800: wh64({{ EA = Rb & ~ULL(63); }},
+ {{ xc->writeHint(EA, 64, memAccessFlags); }},
+ mem_flags = NO_FAULT,
+ inst_flags = [IsMemRef, IsDataPrefetch,
+ IsStore, MemWriteOp]);
+ }
+
+ format BasicOperate {
+ 0xc000: rpcc({{
+#if FULL_SYSTEM
+ /* Rb is a fake dependency so here is a fun way to get
+ * the parser to understand that.
+ */
+ Ra = xc->readMiscRegWithEffect(AlphaISA::IPR_CC, fault) + (Rb & 0);
+
+#else
+ Ra = curTick;
+#endif
+ }});
+
+ // All of the barrier instructions below do nothing in
+ // their execute() methods (hence the empty code blocks).
+ // All of their functionality is hard-coded in the
+ // pipeline based on the flags IsSerializing,
+ // IsMemBarrier, and IsWriteBarrier. In the current
+ // detailed CPU model, the execute() function only gets
+ // called at fetch, so there's no way to generate pipeline
+ // behavior at any other stage. Once we go to an
+ // exec-in-exec CPU model we should be able to get rid of
+ // these flags and implement this behavior via the
+ // execute() methods.
+
+ // trapb is just a barrier on integer traps, where excb is
+ // a barrier on integer and FP traps. "EXCB is thus a
+ // superset of TRAPB." (Alpha ARM, Sec 4.11.4) We treat
+ // them the same though.
+ 0x0000: trapb({{ }}, IsSerializing, No_OpClass);
+ 0x0400: excb({{ }}, IsSerializing, No_OpClass);
+ 0x4000: mb({{ }}, IsMemBarrier, MemReadOp);
+ 0x4400: wmb({{ }}, IsWriteBarrier, MemWriteOp);
+ }
+
+#if FULL_SYSTEM
+ format BasicOperate {
+ 0xe000: rc({{
+ Ra = xc->readIntrFlag();
+ xc->setIntrFlag(0);
+ }}, IsNonSpeculative);
+ 0xf000: rs({{
+ Ra = xc->readIntrFlag();
+ xc->setIntrFlag(1);
+ }}, IsNonSpeculative);
+ }
+#else
+ format FailUnimpl {
+ 0xe000: rc();
+ 0xf000: rs();
+ }
+#endif
+ }
+
+#if FULL_SYSTEM
+ 0x00: CallPal::call_pal({{
+ if (!palValid ||
+ (palPriv
+ && xc->readMiscRegWithEffect(AlphaISA::IPR_ICM, fault) != AlphaISA::mode_kernel)) {
+ // invalid pal function code, or attempt to do privileged
+ // PAL call in non-kernel mode
+ fault = new UnimplementedOpcodeFault;
+ }
+ else {
+ // check to see if simulator wants to do something special
+ // on this PAL call (including maybe suppress it)
+ bool dopal = xc->simPalCheck(palFunc);
+
+ if (dopal) {
+ xc->setMiscRegWithEffect(AlphaISA::IPR_EXC_ADDR, NPC);
+ NPC = xc->readMiscRegWithEffect(AlphaISA::IPR_PAL_BASE, fault) + palOffset;
+ }
+ }
+ }}, IsNonSpeculative);
+#else
+ 0x00: decode PALFUNC {
+ format EmulatedCallPal {
+ 0x00: halt ({{
+ SimExit(curTick, "halt instruction encountered");
+ }}, IsNonSpeculative);
+ 0x83: callsys({{
+ xc->syscall(R0);
+ }}, IsNonSpeculative);
+ // Read uniq reg into ABI return value register (r0)
+ 0x9e: rduniq({{ R0 = Runiq; }});
+ // Write uniq reg with value from ABI arg register (r16)
+ 0x9f: wruniq({{ Runiq = R16; }});
+ }
+ }
+#endif
+
+#if FULL_SYSTEM
+ 0x1b: decode PALMODE {
+ 0: OpcdecFault::hw_st_quad();
+ 1: decode HW_LDST_QUAD {
+ format HwLoad {
+ 0: hw_ld({{ EA = (Rb + disp) & ~3; }}, {{ Ra = Mem.ul; }}, L);
+ 1: hw_ld({{ EA = (Rb + disp) & ~7; }}, {{ Ra = Mem.uq; }}, Q);
+ }
+ }
+ }
+
+ 0x1f: decode PALMODE {
+ 0: OpcdecFault::hw_st_cond();
+ format HwStore {
+ 1: decode HW_LDST_COND {
+ 0: decode HW_LDST_QUAD {
+ 0: hw_st({{ EA = (Rb + disp) & ~3; }},
+ {{ Mem.ul = Ra<31:0>; }}, L);
+ 1: hw_st({{ EA = (Rb + disp) & ~7; }},
+ {{ Mem.uq = Ra.uq; }}, Q);
+ }
+
+ 1: FailUnimpl::hw_st_cond();
+ }
+ }
+ }
+
+ 0x19: decode PALMODE {
+ 0: OpcdecFault::hw_mfpr();
+ format HwMoveIPR {
+ 1: hw_mfpr({{
+ Ra = xc->readMiscRegWithEffect(ipr_index, fault);
+ }});
+ }
+ }
+
+ 0x1d: decode PALMODE {
+ 0: OpcdecFault::hw_mtpr();
+ format HwMoveIPR {
+ 1: hw_mtpr({{
+ xc->setMiscRegWithEffect(ipr_index, Ra);
+ if (traceData) { traceData->setData(Ra); }
+ }});
+ }
+ }
+
+ format BasicOperate {
+ 0x1e: decode PALMODE {
+ 0: OpcdecFault::hw_rei();
+ 1:hw_rei({{ xc->hwrei(); }}, IsSerializing);
+ }
+
+ // M5 special opcodes use the reserved 0x01 opcode space
+ 0x01: decode M5FUNC {
+ 0x00: arm({{
+ AlphaPseudo::arm(xc->xcBase());
+ }}, IsNonSpeculative);
+ 0x01: quiesce({{
+ AlphaPseudo::quiesce(xc->xcBase());
+ }}, IsNonSpeculative);
+ 0x02: quiesceNs({{
+ AlphaPseudo::quiesceNs(xc->xcBase(), R16);
+ }}, IsNonSpeculative);
+ 0x03: quiesceCycles({{
+ AlphaPseudo::quiesceCycles(xc->xcBase(), R16);
+ }}, IsNonSpeculative);
+ 0x04: quiesceTime({{
+ R0 = AlphaPseudo::quiesceTime(xc->xcBase());
+ }}, IsNonSpeculative);
+ 0x10: ivlb({{
+ AlphaPseudo::ivlb(xc->xcBase());
+ }}, No_OpClass, IsNonSpeculative);
+ 0x11: ivle({{
+ AlphaPseudo::ivle(xc->xcBase());
+ }}, No_OpClass, IsNonSpeculative);
+ 0x20: m5exit_old({{
+ AlphaPseudo::m5exit_old(xc->xcBase());
+ }}, No_OpClass, IsNonSpeculative);
+ 0x21: m5exit({{
+ AlphaPseudo::m5exit(xc->xcBase(), R16);
+ }}, No_OpClass, IsNonSpeculative);
+ 0x30: initparam({{ Ra = xc->xcBase()->getCpuPtr()->system->init_param; }});
+ 0x40: resetstats({{
+ AlphaPseudo::resetstats(xc->xcBase(), R16, R17);
+ }}, IsNonSpeculative);
+ 0x41: dumpstats({{
+ AlphaPseudo::dumpstats(xc->xcBase(), R16, R17);
+ }}, IsNonSpeculative);
+ 0x42: dumpresetstats({{
+ AlphaPseudo::dumpresetstats(xc->xcBase(), R16, R17);
+ }}, IsNonSpeculative);
+ 0x43: m5checkpoint({{
+ AlphaPseudo::m5checkpoint(xc->xcBase(), R16, R17);
+ }}, IsNonSpeculative);
+ 0x50: m5readfile({{
+ R0 = AlphaPseudo::readfile(xc->xcBase(), R16, R17, R18);
+ }}, IsNonSpeculative);
+ 0x51: m5break({{
+ AlphaPseudo::debugbreak(xc->xcBase());
+ }}, IsNonSpeculative);
+ 0x52: m5switchcpu({{
+ AlphaPseudo::switchcpu(xc->xcBase());
+ }}, IsNonSpeculative);
+ 0x53: m5addsymbol({{
+ AlphaPseudo::addsymbol(xc->xcBase(), R16, R17);
+ }}, IsNonSpeculative);
+ 0x54: m5panic({{
+ panic("M5 panic instruction called at pc=%#x.", xc->readPC());
+ }}, IsNonSpeculative);
+
+ }
+ }
+#endif
+}
diff --git a/src/arch/alpha/isa/fp.isa b/src/arch/alpha/isa/fp.isa
new file mode 100644
index 000000000..f34c13c42
--- /dev/null
+++ b/src/arch/alpha/isa/fp.isa
@@ -0,0 +1,301 @@
+// -*- mode:c++ -*-
+
+// Copyright (c) 2003-2005 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+output exec {{
+ /// Check "FP enabled" machine status bit. Called when executing any FP
+ /// instruction in full-system mode.
+ /// @retval Full-system mode: NoFault if FP is enabled, FenFault
+ /// if not. Non-full-system mode: always returns NoFault.
+#if FULL_SYSTEM
+ inline Fault checkFpEnableFault(%(CPU_exec_context)s *xc)
+ {
+ Fault fault = NoFault; // dummy... this ipr access should not fault
+ if (!EV5::ICSR_FPE(xc->readMiscRegWithEffect(AlphaISA::IPR_ICSR, fault))) {
+ fault = new FloatEnableFault;
+ }
+ return fault;
+ }
+#else
+ inline Fault checkFpEnableFault(%(CPU_exec_context)s *xc)
+ {
+ return NoFault;
+ }
+#endif
+}};
+
+output header {{
+ /**
+ * Base class for general floating-point instructions. Includes
+ * support for various Alpha rounding and trapping modes. Only FP
+ * instructions that require this support are derived from this
+ * class; the rest derive directly from AlphaStaticInst.
+ */
+ class AlphaFP : public AlphaStaticInst
+ {
+ public:
+ /// Alpha FP rounding modes.
+ enum RoundingMode {
+ Chopped = 0, ///< round toward zero
+ Minus_Infinity = 1, ///< round toward minus infinity
+ Normal = 2, ///< round to nearest (default)
+ Dynamic = 3, ///< use FPCR setting (in instruction)
+ Plus_Infinity = 3 ///< round to plus inifinity (in FPCR)
+ };
+
+ /// Alpha FP trapping modes.
+ /// For instructions that produce integer results, the
+ /// "Underflow Enable" modes really mean "Overflow Enable", and
+ /// the assembly modifier is V rather than U.
+ enum TrappingMode {
+ /// default: nothing enabled
+ Imprecise = 0, ///< no modifier
+ /// underflow/overflow traps enabled, inexact disabled
+ Underflow_Imprecise = 1, ///< /U or /V
+ Underflow_Precise = 5, ///< /SU or /SV
+ /// underflow/overflow and inexact traps enabled
+ Underflow_Inexact_Precise = 7 ///< /SUI or /SVI
+ };
+
+ protected:
+ /// Map Alpha rounding mode to C99 constants from <fenv.h>.
+ static const int alphaToC99RoundingMode[];
+
+ /// Map enum RoundingMode values to disassembly suffixes.
+ static const char *roundingModeSuffix[];
+ /// Map enum TrappingMode values to FP disassembly suffixes.
+ static const char *fpTrappingModeSuffix[];
+ /// Map enum TrappingMode values to integer disassembly suffixes.
+ static const char *intTrappingModeSuffix[];
+
+ /// This instruction's rounding mode.
+ RoundingMode roundingMode;
+ /// This instruction's trapping mode.
+ TrappingMode trappingMode;
+
+ /// Have we warned about this instruction's unsupported
+ /// rounding mode (if applicable)?
+ mutable bool warnedOnRounding;
+
+ /// Have we warned about this instruction's unsupported
+ /// trapping mode (if applicable)?
+ mutable bool warnedOnTrapping;
+
+ /// Constructor
+ AlphaFP(const char *mnem, ExtMachInst _machInst, OpClass __opClass)
+ : AlphaStaticInst(mnem, _machInst, __opClass),
+ roundingMode((enum RoundingMode)FP_ROUNDMODE),
+ trappingMode((enum TrappingMode)FP_TRAPMODE),
+ warnedOnRounding(false),
+ warnedOnTrapping(false)
+ {
+ }
+
+ int getC99RoundingMode(uint64_t fpcr_val) const;
+
+ // This differs from the AlphaStaticInst version only in
+ // printing suffixes for non-default rounding & trapping modes.
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+
+}};
+
+
+output decoder {{
+ int
+ AlphaFP::getC99RoundingMode(uint64_t fpcr_val) const
+ {
+ if (roundingMode == Dynamic) {
+ return alphaToC99RoundingMode[bits(fpcr_val, 59, 58)];
+ }
+ else {
+ return alphaToC99RoundingMode[roundingMode];
+ }
+ }
+
+ std::string
+ AlphaFP::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+ std::string mnem_str(mnemonic);
+
+#ifndef SS_COMPATIBLE_DISASSEMBLY
+ std::string suffix("");
+ suffix += ((_destRegIdx[0] >= FP_Base_DepTag)
+ ? fpTrappingModeSuffix[trappingMode]
+ : intTrappingModeSuffix[trappingMode]);
+ suffix += roundingModeSuffix[roundingMode];
+
+ if (suffix != "") {
+ mnem_str = csprintf("%s/%s", mnemonic, suffix);
+ }
+#endif
+
+ std::stringstream ss;
+ ccprintf(ss, "%-10s ", mnem_str.c_str());
+
+ // just print the first two source regs... if there's
+ // a third one, it's a read-modify-write dest (Rc),
+ // e.g. for CMOVxx
+ if (_numSrcRegs > 0) {
+ printReg(ss, _srcRegIdx[0]);
+ }
+ if (_numSrcRegs > 1) {
+ ss << ",";
+ printReg(ss, _srcRegIdx[1]);
+ }
+
+ // just print the first dest... if there's a second one,
+ // it's generally implicit
+ if (_numDestRegs > 0) {
+ if (_numSrcRegs > 0)
+ ss << ",";
+ printReg(ss, _destRegIdx[0]);
+ }
+
+ return ss.str();
+ }
+
+ const int AlphaFP::alphaToC99RoundingMode[] = {
+ FE_TOWARDZERO, // Chopped
+ FE_DOWNWARD, // Minus_Infinity
+ FE_TONEAREST, // Normal
+ FE_UPWARD // Dynamic in inst, Plus_Infinity in FPCR
+ };
+
+ const char *AlphaFP::roundingModeSuffix[] = { "c", "m", "", "d" };
+ // mark invalid trapping modes, but don't fail on them, because
+ // you could decode anything on a misspeculated path
+ const char *AlphaFP::fpTrappingModeSuffix[] =
+ { "", "u", "INVTM2", "INVTM3", "INVTM4", "su", "INVTM6", "sui" };
+ const char *AlphaFP::intTrappingModeSuffix[] =
+ { "", "v", "INVTM2", "INVTM3", "INVTM4", "sv", "INVTM6", "svi" };
+}};
+
+// FP instruction class execute method template. Handles non-standard
+// rounding modes.
+def template FloatingPointExecute {{
+ Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ if (trappingMode != Imprecise && !warnedOnTrapping) {
+ warn("%s: non-standard trapping mode not supported",
+ generateDisassembly(0, NULL));
+ warnedOnTrapping = true;
+ }
+
+ Fault fault = NoFault;
+
+ %(fp_enable_check)s;
+ %(op_decl)s;
+ %(op_rd)s;
+#if USE_FENV
+ if (roundingMode == Normal) {
+ %(code)s;
+ } else {
+ fesetround(getC99RoundingMode(
+ xc->readMiscReg(AlphaISA::Fpcr_DepTag)));
+ %(code)s;
+ fesetround(FE_TONEAREST);
+ }
+#else
+ if (roundingMode != Normal && !warnedOnRounding) {
+ warn("%s: non-standard rounding mode not supported",
+ generateDisassembly(0, NULL));
+ warnedOnRounding = true;
+ }
+ %(code)s;
+#endif
+
+ if (fault == NoFault) {
+ %(op_wb)s;
+ }
+
+ return fault;
+ }
+}};
+
+// FP instruction class execute method template where no dynamic
+// rounding mode control is needed. Like BasicExecute, but includes
+// check & warning for non-standard trapping mode.
+def template FPFixedRoundingExecute {{
+ Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ if (trappingMode != Imprecise && !warnedOnTrapping) {
+ warn("%s: non-standard trapping mode not supported",
+ generateDisassembly(0, NULL));
+ warnedOnTrapping = true;
+ }
+
+ Fault fault = NoFault;
+
+ %(fp_enable_check)s;
+ %(op_decl)s;
+ %(op_rd)s;
+ %(code)s;
+
+ if (fault == NoFault) {
+ %(op_wb)s;
+ }
+
+ return fault;
+ }
+}};
+
+def template FloatingPointDecode {{
+ {
+ AlphaStaticInst *i = new %(class_name)s(machInst);
+ if (FC == 31) {
+ i = makeNop(i);
+ }
+ return i;
+ }
+}};
+
+// General format for floating-point operate instructions:
+// - Checks trapping and rounding mode flags. Trapping modes
+// currently unimplemented (will fail).
+// - Generates NOP if FC == 31.
+def format FloatingPointOperate(code, *opt_args) {{
+ iop = InstObjParams(name, Name, 'AlphaFP', CodeBlock(code), opt_args)
+ decode_block = FloatingPointDecode.subst(iop)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ exec_output = FloatingPointExecute.subst(iop)
+}};
+
+// Special format for cvttq where rounding mode is pre-decoded
+def format FPFixedRounding(code, class_suffix, *opt_args) {{
+ Name += class_suffix
+ iop = InstObjParams(name, Name, 'AlphaFP', CodeBlock(code), opt_args)
+ decode_block = FloatingPointDecode.subst(iop)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ exec_output = FPFixedRoundingExecute.subst(iop)
+}};
+
diff --git a/src/arch/alpha/isa/int.isa b/src/arch/alpha/isa/int.isa
new file mode 100644
index 000000000..17ecc1a51
--- /dev/null
+++ b/src/arch/alpha/isa/int.isa
@@ -0,0 +1,128 @@
+// -*- mode:c++ -*-
+
+// Copyright (c) 2003-2005 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+output header {{
+ /**
+ * Base class for integer immediate instructions.
+ */
+ class IntegerImm : public AlphaStaticInst
+ {
+ protected:
+ /// Immediate operand value (unsigned 8-bit int).
+ uint8_t imm;
+
+ /// Constructor
+ IntegerImm(const char *mnem, ExtMachInst _machInst, OpClass __opClass)
+ : AlphaStaticInst(mnem, _machInst, __opClass), imm(INTIMM)
+ {
+ }
+
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+}};
+
+output decoder {{
+ std::string
+ IntegerImm::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+ std::stringstream ss;
+
+ ccprintf(ss, "%-10s ", mnemonic);
+
+ // just print the first source reg... if there's
+ // a second one, it's a read-modify-write dest (Rc),
+ // e.g. for CMOVxx
+ if (_numSrcRegs > 0) {
+ printReg(ss, _srcRegIdx[0]);
+ ss << ",";
+ }
+
+ ss << (int)imm;
+
+ if (_numDestRegs > 0) {
+ ss << ",";
+ printReg(ss, _destRegIdx[0]);
+ }
+
+ return ss.str();
+ }
+}};
+
+
+def template RegOrImmDecode {{
+ {
+ AlphaStaticInst *i =
+ (IMM) ? (AlphaStaticInst *)new %(class_name)sImm(machInst)
+ : (AlphaStaticInst *)new %(class_name)s(machInst);
+ if (RC == 31) {
+ i = makeNop(i);
+ }
+ return i;
+ }
+}};
+
+// Primary format for integer operate instructions:
+// - Generates both reg-reg and reg-imm versions if Rb_or_imm is used.
+// - Generates NOP if RC == 31.
+def format IntegerOperate(code, *opt_flags) {{
+ # If the code block contains 'Rb_or_imm', we define two instructions,
+ # one using 'Rb' and one using 'imm', and have the decoder select
+ # the right one.
+ uses_imm = (code.find('Rb_or_imm') != -1)
+ if uses_imm:
+ orig_code = code
+ # base code is reg version:
+ # rewrite by substituting 'Rb' for 'Rb_or_imm'
+ code = re.sub(r'Rb_or_imm', 'Rb', orig_code)
+ # generate immediate version by substituting 'imm'
+ # note that imm takes no extenstion, so we extend
+ # the regexp to replace any extension as well
+ imm_code = re.sub(r'Rb_or_imm(\.\w+)?', 'imm', orig_code)
+
+ # generate declaration for register version
+ cblk = CodeBlock(code)
+ iop = InstObjParams(name, Name, 'AlphaStaticInst', cblk, opt_flags)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ exec_output = BasicExecute.subst(iop)
+
+ if uses_imm:
+ # append declaration for imm version
+ imm_cblk = CodeBlock(imm_code)
+ imm_iop = InstObjParams(name, Name + 'Imm', 'IntegerImm', imm_cblk,
+ opt_flags)
+ header_output += BasicDeclare.subst(imm_iop)
+ decoder_output += BasicConstructor.subst(imm_iop)
+ exec_output += BasicExecute.subst(imm_iop)
+ # decode checks IMM bit to pick correct version
+ decode_block = RegOrImmDecode.subst(iop)
+ else:
+ # no imm version: just check for nop
+ decode_block = OperateNopCheckDecode.subst(iop)
+}};
diff --git a/src/arch/alpha/isa/main.isa b/src/arch/alpha/isa/main.isa
new file mode 100644
index 000000000..03a8e1ff5
--- /dev/null
+++ b/src/arch/alpha/isa/main.isa
@@ -0,0 +1,449 @@
+// -*- mode:c++ -*-
+
+// Copyright (c) 2003-2005 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+output header {{
+#include <sstream>
+#include <iostream>
+#include <iomanip>
+
+#include "config/ss_compatible_fp.hh"
+#include "cpu/static_inst.hh"
+#include "arch/alpha/faults.hh"
+#include "mem/request.hh" // some constructors use MemReq flags
+}};
+
+output decoder {{
+#include "base/cprintf.hh"
+#include "base/fenv.hh"
+#include "base/loader/symtab.hh"
+#include "config/ss_compatible_fp.hh"
+#include "cpu/exec_context.hh" // for Jump::branchTarget()
+
+#include <math.h>
+
+using namespace AlphaISA;
+}};
+
+output exec {{
+#include <math.h>
+
+#if FULL_SYSTEM
+#include "sim/pseudo_inst.hh"
+#endif
+#include "base/fenv.hh"
+#include "config/ss_compatible_fp.hh"
+#include "cpu/base.hh"
+#include "cpu/exetrace.hh"
+#include "sim/sim_exit.hh"
+#include "mem/packet_impl.hh"
+
+using namespace AlphaISA;
+}};
+
+////////////////////////////////////////////////////////////////////
+//
+// Namespace statement. Everything below this line will be in the
+// AlphaISAInst namespace.
+//
+
+
+namespace AlphaISA;
+
+////////////////////////////////////////////////////////////////////
+//
+// Bitfield definitions.
+//
+
+// Universal (format-independent) fields
+def bitfield PALMODE <32:32>;
+def bitfield OPCODE <31:26>;
+def bitfield RA <25:21>;
+def bitfield RB <20:16>;
+
+// Memory format
+def signed bitfield MEMDISP <15: 0>; // displacement
+def bitfield MEMFUNC <15: 0>; // function code (same field, unsigned)
+
+// Memory-format jumps
+def bitfield JMPFUNC <15:14>; // function code (disp<15:14>)
+def bitfield JMPHINT <13: 0>; // tgt Icache idx hint (disp<13:0>)
+
+// Branch format
+def signed bitfield BRDISP <20: 0>; // displacement
+
+// Integer operate format(s>;
+def bitfield INTIMM <20:13>; // integer immediate (literal)
+def bitfield IMM <12:12>; // immediate flag
+def bitfield INTFUNC <11: 5>; // function code
+def bitfield RC < 4: 0>; // dest reg
+
+// Floating-point operate format
+def bitfield FA <25:21>;
+def bitfield FB <20:16>;
+def bitfield FP_FULLFUNC <15: 5>; // complete function code
+ def bitfield FP_TRAPMODE <15:13>; // trapping mode
+ def bitfield FP_ROUNDMODE <12:11>; // rounding mode
+ def bitfield FP_TYPEFUNC <10: 5>; // type+func: handiest for decoding
+ def bitfield FP_SRCTYPE <10: 9>; // source reg type
+ def bitfield FP_SHORTFUNC < 8: 5>; // short function code
+ def bitfield FP_SHORTFUNC_TOP2 <8:7>; // top 2 bits of short func code
+def bitfield FC < 4: 0>; // dest reg
+
+// PALcode format
+def bitfield PALFUNC <25: 0>; // function code
+
+// EV5 PAL instructions:
+// HW_LD/HW_ST
+def bitfield HW_LDST_PHYS <15>; // address is physical
+def bitfield HW_LDST_ALT <14>; // use ALT_MODE IPR
+def bitfield HW_LDST_WRTCK <13>; // HW_LD only: fault if no write acc
+def bitfield HW_LDST_QUAD <12>; // size: 0=32b, 1=64b
+def bitfield HW_LDST_VPTE <11>; // HW_LD only: is PTE fetch
+def bitfield HW_LDST_LOCK <10>; // HW_LD only: is load locked
+def bitfield HW_LDST_COND <10>; // HW_ST only: is store conditional
+def signed bitfield HW_LDST_DISP <9:0>; // signed displacement
+
+// HW_REI
+def bitfield HW_REI_TYP <15:14>; // type: stalling vs. non-stallingk
+def bitfield HW_REI_MBZ <13: 0>; // must be zero
+
+// HW_MTPR/MW_MFPR
+def bitfield HW_IPR_IDX <15:0>; // IPR index
+
+// M5 instructions
+def bitfield M5FUNC <7:0>;
+
+def operand_types {{
+ 'sb' : ('signed int', 8),
+ 'ub' : ('unsigned int', 8),
+ 'sw' : ('signed int', 16),
+ 'uw' : ('unsigned int', 16),
+ 'sl' : ('signed int', 32),
+ 'ul' : ('unsigned int', 32),
+ 'sq' : ('signed int', 64),
+ 'uq' : ('unsigned int', 64),
+ 'sf' : ('float', 32),
+ 'df' : ('float', 64)
+}};
+
+def operands {{
+ # Int regs default to unsigned, but code should not count on this.
+ # For clarity, descriptions that depend on unsigned behavior should
+ # explicitly specify '.uq'.
+ 'Ra': ('IntReg', 'uq', 'PALMODE ? AlphaISA::reg_redir[RA] : RA',
+ 'IsInteger', 1),
+ 'Rb': ('IntReg', 'uq', 'PALMODE ? AlphaISA::reg_redir[RB] : RB',
+ 'IsInteger', 2),
+ 'Rc': ('IntReg', 'uq', 'PALMODE ? AlphaISA::reg_redir[RC] : RC',
+ 'IsInteger', 3),
+ 'Fa': ('FloatReg', 'df', 'FA', 'IsFloating', 1),
+ 'Fb': ('FloatReg', 'df', 'FB', 'IsFloating', 2),
+ 'Fc': ('FloatReg', 'df', 'FC', 'IsFloating', 3),
+ 'Mem': ('Mem', 'uq', None, ('IsMemRef', 'IsLoad', 'IsStore'), 4),
+ 'NPC': ('NPC', 'uq', None, ( None, None, 'IsControl' ), 4),
+ 'Runiq': ('ControlReg', 'uq', 'TheISA::Uniq_DepTag', None, 1),
+ 'FPCR': (' ControlReg', 'uq', 'TheISA::Fpcr_DepTag', None, 1),
+ # The next two are hacks for non-full-system call-pal emulation
+ 'R0': ('IntReg', 'uq', '0', None, 1),
+ 'R16': ('IntReg', 'uq', '16', None, 1),
+ 'R17': ('IntReg', 'uq', '17', None, 1),
+ 'R18': ('IntReg', 'uq', '18', None, 1)
+}};
+
+////////////////////////////////////////////////////////////////////
+//
+// Basic instruction classes/templates/formats etc.
+//
+
+output header {{
+// uncomment the following to get SimpleScalar-compatible disassembly
+// (useful for diffing output traces).
+// #define SS_COMPATIBLE_DISASSEMBLY
+
+ /**
+ * Base class for all Alpha static instructions.
+ */
+ class AlphaStaticInst : public StaticInst
+ {
+ protected:
+
+ /// Make AlphaISA register dependence tags directly visible in
+ /// this class and derived classes. Maybe these should really
+ /// live here and not in the AlphaISA namespace.
+ enum DependenceTags {
+ FP_Base_DepTag = AlphaISA::FP_Base_DepTag,
+ Fpcr_DepTag = AlphaISA::Fpcr_DepTag,
+ Uniq_DepTag = AlphaISA::Uniq_DepTag,
+ Lock_Flag_DepTag = AlphaISA::Lock_Flag_DepTag,
+ Lock_Addr_DepTag = AlphaISA::Lock_Addr_DepTag,
+ IPR_Base_DepTag = AlphaISA::IPR_Base_DepTag
+ };
+
+ /// Constructor.
+ AlphaStaticInst(const char *mnem, ExtMachInst _machInst,
+ OpClass __opClass)
+ : StaticInst(mnem, _machInst, __opClass)
+ {
+ }
+
+ /// Print a register name for disassembly given the unique
+ /// dependence tag number (FP or int).
+ void printReg(std::ostream &os, int reg) const;
+
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+}};
+
+output decoder {{
+ void
+ AlphaStaticInst::printReg(std::ostream &os, int reg) const
+ {
+ if (reg < FP_Base_DepTag) {
+ ccprintf(os, "r%d", reg);
+ }
+ else {
+ ccprintf(os, "f%d", reg - FP_Base_DepTag);
+ }
+ }
+
+ std::string
+ AlphaStaticInst::generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+ {
+ std::stringstream ss;
+
+ ccprintf(ss, "%-10s ", mnemonic);
+
+ // just print the first two source regs... if there's
+ // a third one, it's a read-modify-write dest (Rc),
+ // e.g. for CMOVxx
+ if (_numSrcRegs > 0) {
+ printReg(ss, _srcRegIdx[0]);
+ }
+ if (_numSrcRegs > 1) {
+ ss << ",";
+ printReg(ss, _srcRegIdx[1]);
+ }
+
+ // just print the first dest... if there's a second one,
+ // it's generally implicit
+ if (_numDestRegs > 0) {
+ if (_numSrcRegs > 0)
+ ss << ",";
+ printReg(ss, _destRegIdx[0]);
+ }
+
+ return ss.str();
+ }
+}};
+
+// Declarations for execute() methods.
+def template BasicExecDeclare {{
+ Fault execute(%(CPU_exec_context)s *, Trace::InstRecord *) const;
+}};
+
+// Basic instruction class declaration template.
+def template BasicDeclare {{
+ /**
+ * Static instruction class for "%(mnemonic)s".
+ */
+ class %(class_name)s : public %(base_class)s
+ {
+ public:
+ /// Constructor.
+ %(class_name)s(ExtMachInst machInst);
+
+ %(BasicExecDeclare)s
+ };
+}};
+
+// Basic instruction class constructor template.
+def template BasicConstructor {{
+ inline %(class_name)s::%(class_name)s(ExtMachInst machInst)
+ : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s)
+ {
+ %(constructor)s;
+ }
+}};
+
+// Basic instruction class execute method template.
+def template BasicExecute {{
+ Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ Fault fault = NoFault;
+
+ %(fp_enable_check)s;
+ %(op_decl)s;
+ %(op_rd)s;
+ %(code)s;
+
+ if (fault == NoFault) {
+ %(op_wb)s;
+ }
+
+ return fault;
+ }
+}};
+
+// Basic decode template.
+def template BasicDecode {{
+ return new %(class_name)s(machInst);
+}};
+
+// Basic decode template, passing mnemonic in as string arg to constructor.
+def template BasicDecodeWithMnemonic {{
+ return new %(class_name)s("%(mnemonic)s", machInst);
+}};
+
+// The most basic instruction format... used only for a few misc. insts
+def format BasicOperate(code, *flags) {{
+ iop = InstObjParams(name, Name, 'AlphaStaticInst', CodeBlock(code), flags)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
+}};
+
+
+
+////////////////////////////////////////////////////////////////////
+//
+// Nop
+//
+
+output header {{
+ /**
+ * Static instruction class for no-ops. This is a leaf class.
+ */
+ class Nop : public AlphaStaticInst
+ {
+ /// Disassembly of original instruction.
+ const std::string originalDisassembly;
+
+ public:
+ /// Constructor
+ Nop(const std::string _originalDisassembly, ExtMachInst _machInst)
+ : AlphaStaticInst("nop", _machInst, No_OpClass),
+ originalDisassembly(_originalDisassembly)
+ {
+ flags[IsNop] = true;
+ }
+
+ ~Nop() { }
+
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+
+ %(BasicExecDeclare)s
+ };
+
+ /// Helper function for decoding nops. Substitute Nop object
+ /// for original inst passed in as arg (and delete latter).
+ static inline
+ AlphaStaticInst *
+ makeNop(AlphaStaticInst *inst)
+ {
+ AlphaStaticInst *nop = new Nop(inst->disassemble(0), inst->machInst);
+ delete inst;
+ return nop;
+ }
+}};
+
+output decoder {{
+ std::string Nop::generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+ {
+#ifdef SS_COMPATIBLE_DISASSEMBLY
+ return originalDisassembly;
+#else
+ return csprintf("%-10s (%s)", "nop", originalDisassembly);
+#endif
+ }
+}};
+
+output exec {{
+ Fault
+ Nop::execute(%(CPU_exec_context)s *, Trace::InstRecord *) const
+ {
+ return NoFault;
+ }
+}};
+
+// integer & FP operate instructions use Rc as dest, so check for
+// Rc == 31 to detect nops
+def template OperateNopCheckDecode {{
+ {
+ AlphaStaticInst *i = new %(class_name)s(machInst);
+ if (RC == 31) {
+ i = makeNop(i);
+ }
+ return i;
+ }
+}};
+
+// Like BasicOperate format, but generates NOP if RC/FC == 31
+def format BasicOperateWithNopCheck(code, *opt_args) {{
+ iop = InstObjParams(name, Name, 'AlphaStaticInst', CodeBlock(code),
+ opt_args)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = OperateNopCheckDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
+}};
+
+// Integer instruction templates, formats, etc.
+##include "int.isa"
+
+// Floating-point instruction templates, formats, etc.
+##include "fp.isa"
+
+// Memory instruction templates, formats, etc.
+##include "mem.isa"
+
+// Branch/jump instruction templates, formats, etc.
+##include "branch.isa"
+
+// PAL instruction templates, formats, etc.
+##include "pal.isa"
+
+// Opcdec fault instruction templates, formats, etc.
+##include "opcdec.isa"
+
+// Unimplemented instruction templates, formats, etc.
+##include "unimp.isa"
+
+// Unknown instruction templates, formats, etc.
+##include "unknown.isa"
+
+// Execution utility functions
+##include "util.isa"
+
+// The actual decoder
+##include "decoder.isa"
diff --git a/src/arch/alpha/isa/mem.isa b/src/arch/alpha/isa/mem.isa
new file mode 100644
index 000000000..98c7ba979
--- /dev/null
+++ b/src/arch/alpha/isa/mem.isa
@@ -0,0 +1,729 @@
+// -*- mode:c++ -*-
+
+// Copyright (c) 2003-2005 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+output header {{
+ /**
+ * Base class for general Alpha memory-format instructions.
+ */
+ class Memory : public AlphaStaticInst
+ {
+ protected:
+
+ /// Memory request flags. See mem_req_base.hh.
+ unsigned memAccessFlags;
+ /// Pointer to EAComp object.
+ const StaticInstPtr eaCompPtr;
+ /// Pointer to MemAcc object.
+ const StaticInstPtr memAccPtr;
+
+ /// Constructor
+ Memory(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
+ StaticInstPtr _eaCompPtr = nullStaticInstPtr,
+ StaticInstPtr _memAccPtr = nullStaticInstPtr)
+ : AlphaStaticInst(mnem, _machInst, __opClass),
+ memAccessFlags(0), eaCompPtr(_eaCompPtr), memAccPtr(_memAccPtr)
+ {
+ }
+
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+
+ public:
+
+ const StaticInstPtr &eaCompInst() const { return eaCompPtr; }
+ const StaticInstPtr &memAccInst() const { return memAccPtr; }
+ };
+
+ /**
+ * Base class for memory-format instructions using a 32-bit
+ * displacement (i.e. most of them).
+ */
+ class MemoryDisp32 : public Memory
+ {
+ protected:
+ /// Displacement for EA calculation (signed).
+ int32_t disp;
+
+ /// Constructor.
+ MemoryDisp32(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
+ StaticInstPtr _eaCompPtr = nullStaticInstPtr,
+ StaticInstPtr _memAccPtr = nullStaticInstPtr)
+ : Memory(mnem, _machInst, __opClass, _eaCompPtr, _memAccPtr),
+ disp(MEMDISP)
+ {
+ }
+ };
+
+
+ /**
+ * Base class for a few miscellaneous memory-format insts
+ * that don't interpret the disp field: wh64, fetch, fetch_m, ecb.
+ * None of these instructions has a destination register either.
+ */
+ class MemoryNoDisp : public Memory
+ {
+ protected:
+ /// Constructor
+ MemoryNoDisp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
+ StaticInstPtr _eaCompPtr = nullStaticInstPtr,
+ StaticInstPtr _memAccPtr = nullStaticInstPtr)
+ : Memory(mnem, _machInst, __opClass, _eaCompPtr, _memAccPtr)
+ {
+ }
+
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+}};
+
+
+output decoder {{
+ std::string
+ Memory::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+ return csprintf("%-10s %c%d,%d(r%d)", mnemonic,
+ flags[IsFloating] ? 'f' : 'r', RA, MEMDISP, RB);
+ }
+
+ std::string
+ MemoryNoDisp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+ return csprintf("%-10s (r%d)", mnemonic, RB);
+ }
+}};
+
+def format LoadAddress(code) {{
+ iop = InstObjParams(name, Name, 'MemoryDisp32', CodeBlock(code))
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
+}};
+
+
+def template LoadStoreDeclare {{
+ /**
+ * Static instruction class for "%(mnemonic)s".
+ */
+ class %(class_name)s : public %(base_class)s
+ {
+ protected:
+
+ /**
+ * "Fake" effective address computation class for "%(mnemonic)s".
+ */
+ class EAComp : public %(base_class)s
+ {
+ public:
+ /// Constructor
+ EAComp(ExtMachInst machInst);
+
+ %(BasicExecDeclare)s
+ };
+
+ /**
+ * "Fake" memory access instruction class for "%(mnemonic)s".
+ */
+ class MemAcc : public %(base_class)s
+ {
+ public:
+ /// Constructor
+ MemAcc(ExtMachInst machInst);
+
+ %(BasicExecDeclare)s
+ };
+
+ public:
+
+ /// Constructor.
+ %(class_name)s(ExtMachInst machInst);
+
+ %(BasicExecDeclare)s
+
+ %(InitiateAccDeclare)s
+
+ %(CompleteAccDeclare)s
+ };
+}};
+
+
+def template InitiateAccDeclare {{
+ Fault initiateAcc(%(CPU_exec_context)s *, Trace::InstRecord *) const;
+}};
+
+
+def template CompleteAccDeclare {{
+ Fault completeAcc(Packet *, %(CPU_exec_context)s *,
+ Trace::InstRecord *) const;
+}};
+
+
+def template LoadStoreConstructor {{
+ /** TODO: change op_class to AddrGenOp or something (requires
+ * creating new member of OpClass enum in op_class.hh, updating
+ * config files, etc.). */
+ inline %(class_name)s::EAComp::EAComp(ExtMachInst machInst)
+ : %(base_class)s("%(mnemonic)s (EAComp)", machInst, IntAluOp)
+ {
+ %(ea_constructor)s;
+ }
+
+ inline %(class_name)s::MemAcc::MemAcc(ExtMachInst machInst)
+ : %(base_class)s("%(mnemonic)s (MemAcc)", machInst, %(op_class)s)
+ {
+ %(memacc_constructor)s;
+ }
+
+ inline %(class_name)s::%(class_name)s(ExtMachInst machInst)
+ : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s,
+ new EAComp(machInst), new MemAcc(machInst))
+ {
+ %(constructor)s;
+ }
+}};
+
+
+def template EACompExecute {{
+ Fault
+ %(class_name)s::EAComp::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ Addr EA;
+ Fault fault = NoFault;
+
+ %(fp_enable_check)s;
+ %(op_decl)s;
+ %(op_rd)s;
+ %(code)s;
+
+ if (fault == NoFault) {
+ %(op_wb)s;
+ xc->setEA(EA);
+ }
+
+ return fault;
+ }
+}};
+
+def template LoadMemAccExecute {{
+ Fault
+ %(class_name)s::MemAcc::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ Addr EA;
+ Fault fault = NoFault;
+
+ %(fp_enable_check)s;
+ %(op_decl)s;
+ %(op_rd)s;
+ EA = xc->getEA();
+
+ if (fault == NoFault) {
+ fault = xc->read(EA, (uint%(mem_acc_size)d_t&)Mem, memAccessFlags);
+ %(code)s;
+ }
+
+ if (fault == NoFault) {
+ %(op_wb)s;
+ }
+
+ return fault;
+ }
+}};
+
+
+def template LoadExecute {{
+ Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ Addr EA;
+ Fault fault = NoFault;
+
+ %(fp_enable_check)s;
+ %(op_decl)s;
+ %(op_rd)s;
+ %(ea_code)s;
+
+ if (fault == NoFault) {
+ fault = xc->read(EA, (uint%(mem_acc_size)d_t&)Mem, memAccessFlags);
+ %(memacc_code)s;
+ }
+
+ if (fault == NoFault) {
+ %(op_wb)s;
+ }
+
+ return fault;
+ }
+}};
+
+
+def template LoadInitiateAcc {{
+ Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ Addr EA;
+ Fault fault = NoFault;
+
+ %(fp_enable_check)s;
+ %(op_src_decl)s;
+ %(op_rd)s;
+ %(ea_code)s;
+
+ if (fault == NoFault) {
+ fault = xc->read(EA, (uint%(mem_acc_size)d_t &)Mem, memAccessFlags);
+ }
+
+ return fault;
+ }
+}};
+
+
+def template LoadCompleteAcc {{
+ Fault %(class_name)s::completeAcc(Packet *pkt,
+ %(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ Fault fault = NoFault;
+
+ %(fp_enable_check)s;
+ %(op_decl)s;
+
+ Mem = pkt->get<typeof(Mem)>();
+
+ if (fault == NoFault) {
+ %(memacc_code)s;
+ }
+
+ if (fault == NoFault) {
+ %(op_wb)s;
+ }
+
+ return fault;
+ }
+}};
+
+
+def template StoreMemAccExecute {{
+ Fault
+ %(class_name)s::MemAcc::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ Addr EA;
+ Fault fault = NoFault;
+ uint64_t write_result = 0;
+
+ %(fp_enable_check)s;
+ %(op_decl)s;
+ %(op_rd)s;
+ EA = xc->getEA();
+
+ if (fault == NoFault) {
+ %(code)s;
+ }
+
+ if (fault == NoFault) {
+ fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA,
+ memAccessFlags, &write_result);
+ if (traceData) { traceData->setData(Mem); }
+ }
+
+ if (fault == NoFault) {
+ %(postacc_code)s;
+ }
+
+ if (fault == NoFault) {
+ %(op_wb)s;
+ }
+
+ return fault;
+ }
+}};
+
+
+def template StoreExecute {{
+ Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ Addr EA;
+ Fault fault = NoFault;
+ uint64_t write_result = 0;
+
+ %(fp_enable_check)s;
+ %(op_decl)s;
+ %(op_rd)s;
+ %(ea_code)s;
+
+ if (fault == NoFault) {
+ %(memacc_code)s;
+ }
+
+ if (fault == NoFault) {
+ fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA,
+ memAccessFlags, &write_result);
+ if (traceData) { traceData->setData(Mem); }
+ }
+
+ if (fault == NoFault) {
+ %(postacc_code)s;
+ }
+
+ if (fault == NoFault) {
+ %(op_wb)s;
+ }
+
+ return fault;
+ }
+}};
+
+def template StoreInitiateAcc {{
+ Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ Addr EA;
+ Fault fault = NoFault;
+
+ %(fp_enable_check)s;
+ %(op_decl)s;
+ %(op_rd)s;
+ %(ea_code)s;
+
+ if (fault == NoFault) {
+ %(memacc_code)s;
+ }
+
+ if (fault == NoFault) {
+ fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA,
+ memAccessFlags, NULL);
+ if (traceData) { traceData->setData(Mem); }
+ }
+
+ return fault;
+ }
+}};
+
+
+def template StoreCompleteAcc {{
+ Fault %(class_name)s::completeAcc(Packet *pkt,
+ %(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ Fault fault = NoFault;
+
+ %(fp_enable_check)s;
+ %(op_dest_decl)s;
+
+ if (fault == NoFault) {
+ %(postacc_code)s;
+ }
+
+ if (fault == NoFault) {
+ %(op_wb)s;
+ }
+
+ return fault;
+ }
+}};
+
+
+def template StoreCondCompleteAcc {{
+ Fault %(class_name)s::completeAcc(Packet *pkt,
+ %(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ Fault fault = NoFault;
+
+ %(fp_enable_check)s;
+ %(op_dest_decl)s;
+
+ uint64_t write_result = pkt->req->getScResult();
+
+ if (fault == NoFault) {
+ %(postacc_code)s;
+ }
+
+ if (fault == NoFault) {
+ %(op_wb)s;
+ }
+
+ return fault;
+ }
+}};
+
+
+def template MiscMemAccExecute {{
+ Fault %(class_name)s::MemAcc::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ Addr EA;
+ Fault fault = NoFault;
+
+ %(fp_enable_check)s;
+ %(op_decl)s;
+ %(op_rd)s;
+ EA = xc->getEA();
+
+ if (fault == NoFault) {
+ %(code)s;
+ }
+
+ return NoFault;
+ }
+}};
+
+def template MiscExecute {{
+ Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ Addr EA;
+ Fault fault = NoFault;
+
+ %(fp_enable_check)s;
+ %(op_decl)s;
+ %(op_rd)s;
+ %(ea_code)s;
+
+ if (fault == NoFault) {
+ %(memacc_code)s;
+ }
+
+ return NoFault;
+ }
+}};
+
+def template MiscInitiateAcc {{
+ Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ panic("Misc instruction does not support split access method!");
+ return NoFault;
+ }
+}};
+
+
+def template MiscCompleteAcc {{
+ Fault %(class_name)s::completeAcc(Packet *pkt,
+ %(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ panic("Misc instruction does not support split access method!");
+
+ return NoFault;
+ }
+}};
+
+// load instructions use Ra as dest, so check for
+// Ra == 31 to detect nops
+def template LoadNopCheckDecode {{
+ {
+ AlphaStaticInst *i = new %(class_name)s(machInst);
+ if (RA == 31) {
+ i = makeNop(i);
+ }
+ return i;
+ }
+}};
+
+
+// for some load instructions, Ra == 31 indicates a prefetch (not a nop)
+def template LoadPrefetchCheckDecode {{
+ {
+ if (RA != 31) {
+ return new %(class_name)s(machInst);
+ }
+ else {
+ return new %(class_name)sPrefetch(machInst);
+ }
+ }
+}};
+
+
+let {{
+def LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
+ postacc_code = '', base_class = 'MemoryDisp32',
+ decode_template = BasicDecode, exec_template_base = ''):
+ # Make sure flags are in lists (convert to lists if not).
+ mem_flags = makeList(mem_flags)
+ inst_flags = makeList(inst_flags)
+
+ # add hook to get effective addresses into execution trace output.
+ ea_code += '\nif (traceData) { traceData->setAddr(EA); }\n'
+
+ # generate code block objects
+ ea_cblk = CodeBlock(ea_code)
+ memacc_cblk = CodeBlock(memacc_code)
+ postacc_cblk = CodeBlock(postacc_code)
+
+ # Some CPU models execute the memory operation as an atomic unit,
+ # while others want to separate them into an effective address
+ # computation and a memory access operation. As a result, we need
+ # to generate three StaticInst objects. Note that the latter two
+ # are nested inside the larger "atomic" one.
+
+ # generate InstObjParams for EAComp object
+ ea_iop = InstObjParams(name, Name, base_class, ea_cblk, inst_flags)
+
+ # generate InstObjParams for MemAcc object
+ memacc_iop = InstObjParams(name, Name, base_class, memacc_cblk, inst_flags)
+ # in the split execution model, the MemAcc portion is responsible
+ # for the post-access code.
+ memacc_iop.postacc_code = postacc_cblk.code
+
+ # generate InstObjParams for InitiateAcc, CompleteAcc object
+ # The code used depends on the template being used
+ if (exec_template_base == 'Load'):
+ initiateacc_cblk = CodeBlock(ea_code + memacc_code)
+ completeacc_cblk = CodeBlock(memacc_code + postacc_code)
+ elif (exec_template_base.startswith('Store')):
+ initiateacc_cblk = CodeBlock(ea_code + memacc_code)
+ completeacc_cblk = CodeBlock(postacc_code)
+ else:
+ initiateacc_cblk = ''
+ completeacc_cblk = ''
+
+ initiateacc_iop = InstObjParams(name, Name, base_class, initiateacc_cblk,
+ inst_flags)
+
+ completeacc_iop = InstObjParams(name, Name, base_class, completeacc_cblk,
+ inst_flags)
+
+ if (exec_template_base == 'Load'):
+ initiateacc_iop.ea_code = ea_cblk.code
+ initiateacc_iop.memacc_code = memacc_cblk.code
+ completeacc_iop.memacc_code = memacc_cblk.code
+ completeacc_iop.postacc_code = postacc_cblk.code
+ elif (exec_template_base.startswith('Store')):
+ initiateacc_iop.ea_code = ea_cblk.code
+ initiateacc_iop.memacc_code = memacc_cblk.code
+ completeacc_iop.postacc_code = postacc_cblk.code
+
+ # generate InstObjParams for unified execution
+ cblk = CodeBlock(ea_code + memacc_code + postacc_code)
+ iop = InstObjParams(name, Name, base_class, cblk, inst_flags)
+
+ iop.ea_constructor = ea_cblk.constructor
+ iop.ea_code = ea_cblk.code
+ iop.memacc_constructor = memacc_cblk.constructor
+ iop.memacc_code = memacc_cblk.code
+ iop.postacc_code = postacc_cblk.code
+
+ if mem_flags:
+ s = '\n\tmemAccessFlags = ' + string.join(mem_flags, '|') + ';'
+ iop.constructor += s
+ memacc_iop.constructor += s
+
+ # select templates
+
+ # define aliases... most StoreCond templates are the same as the
+ # corresponding Store templates (only CompleteAcc is different).
+ StoreCondMemAccExecute = StoreMemAccExecute
+ StoreCondExecute = StoreExecute
+ StoreCondInitiateAcc = StoreInitiateAcc
+
+ memAccExecTemplate = eval(exec_template_base + 'MemAccExecute')
+ fullExecTemplate = eval(exec_template_base + 'Execute')
+ initiateAccTemplate = eval(exec_template_base + 'InitiateAcc')
+ completeAccTemplate = eval(exec_template_base + 'CompleteAcc')
+
+ # (header_output, decoder_output, decode_block, exec_output)
+ return (LoadStoreDeclare.subst(iop), LoadStoreConstructor.subst(iop),
+ decode_template.subst(iop),
+ EACompExecute.subst(ea_iop)
+ + memAccExecTemplate.subst(memacc_iop)
+ + fullExecTemplate.subst(iop)
+ + initiateAccTemplate.subst(initiateacc_iop)
+ + completeAccTemplate.subst(completeacc_iop))
+}};
+
+
+def format LoadOrNop(memacc_code, ea_code = {{ EA = Rb + disp; }},
+ mem_flags = [], inst_flags = []) {{
+ (header_output, decoder_output, decode_block, exec_output) = \
+ LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
+ decode_template = LoadNopCheckDecode,
+ exec_template_base = 'Load')
+}};
+
+
+// Note that the flags passed in apply only to the prefetch version
+def format LoadOrPrefetch(memacc_code, ea_code = {{ EA = Rb + disp; }},
+ mem_flags = [], pf_flags = [], inst_flags = []) {{
+ # declare the load instruction object and generate the decode block
+ (header_output, decoder_output, decode_block, exec_output) = \
+ LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
+ decode_template = LoadPrefetchCheckDecode,
+ exec_template_base = 'Load')
+
+ # Declare the prefetch instruction object.
+
+ # Make sure flag args are lists so we can mess with them.
+ mem_flags = makeList(mem_flags)
+ pf_flags = makeList(pf_flags)
+ inst_flags = makeList(inst_flags)
+
+ pf_mem_flags = mem_flags + pf_flags + ['NO_FAULT']
+ pf_inst_flags = inst_flags + ['IsMemRef', 'IsLoad',
+ 'IsDataPrefetch', 'MemReadOp']
+
+ (pf_header_output, pf_decoder_output, _, pf_exec_output) = \
+ LoadStoreBase(name, Name + 'Prefetch', ea_code,
+ 'xc->prefetch(EA, memAccessFlags);',
+ pf_mem_flags, pf_inst_flags, exec_template_base = 'Misc')
+
+ header_output += pf_header_output
+ decoder_output += pf_decoder_output
+ exec_output += pf_exec_output
+}};
+
+
+def format Store(memacc_code, ea_code = {{ EA = Rb + disp; }},
+ mem_flags = [], inst_flags = []) {{
+ (header_output, decoder_output, decode_block, exec_output) = \
+ LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
+ exec_template_base = 'Store')
+}};
+
+
+def format StoreCond(memacc_code, postacc_code,
+ ea_code = {{ EA = Rb + disp; }},
+ mem_flags = [], inst_flags = []) {{
+ (header_output, decoder_output, decode_block, exec_output) = \
+ LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
+ postacc_code, exec_template_base = 'StoreCond')
+}};
+
+
+// Use 'MemoryNoDisp' as base: for wh64, fetch, ecb
+def format MiscPrefetch(ea_code, memacc_code,
+ mem_flags = [], inst_flags = []) {{
+ (header_output, decoder_output, decode_block, exec_output) = \
+ LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
+ base_class = 'MemoryNoDisp', exec_template_base = 'Misc')
+}};
+
+
diff --git a/src/arch/alpha/isa/opcdec.isa b/src/arch/alpha/isa/opcdec.isa
new file mode 100644
index 000000000..bb2f91e5c
--- /dev/null
+++ b/src/arch/alpha/isa/opcdec.isa
@@ -0,0 +1,72 @@
+// -*- mode:c++ -*-
+
+// Copyright (c) 2003-2005 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+output header {{
+ /**
+ * Static instruction class for instructions that cause an OPCDEC fault
+ * when executed. This is currently only for PAL mode instructions
+ * executed in non-PAL mode.
+ */
+ class OpcdecFault : public AlphaStaticInst
+ {
+ public:
+ /// Constructor
+ OpcdecFault(ExtMachInst _machInst)
+ : AlphaStaticInst("opcdec fault", _machInst, No_OpClass)
+ {
+ }
+
+ %(BasicExecDeclare)s
+
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+}};
+
+output decoder {{
+ std::string
+ OpcdecFault::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+ return csprintf("%-10s (inst 0x%x, opcode 0x%x)",
+ " OPCDEC fault", machInst, OPCODE);
+ }
+}};
+
+output exec {{
+ Fault
+ OpcdecFault::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ return new UnimplementedOpcodeFault;
+ }
+}};
+
+def format OpcdecFault() {{
+ decode_block = 'return new OpcdecFault(machInst);\n'
+}};
+
diff --git a/src/arch/alpha/isa/pal.isa b/src/arch/alpha/isa/pal.isa
new file mode 100644
index 000000000..e07bea5a8
--- /dev/null
+++ b/src/arch/alpha/isa/pal.isa
@@ -0,0 +1,271 @@
+// -*- mode:c++ -*-
+
+// Copyright (c) 2003-2005 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+output header {{
+ /**
+ * Base class for emulated call_pal calls (used only in
+ * non-full-system mode).
+ */
+ class EmulatedCallPal : public AlphaStaticInst
+ {
+ protected:
+
+ /// Constructor.
+ EmulatedCallPal(const char *mnem, ExtMachInst _machInst,
+ OpClass __opClass)
+ : AlphaStaticInst(mnem, _machInst, __opClass)
+ {
+ }
+
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+}};
+
+output decoder {{
+ std::string
+ EmulatedCallPal::generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+ {
+#ifdef SS_COMPATIBLE_DISASSEMBLY
+ return csprintf("%s %s", "call_pal", mnemonic);
+#else
+ return csprintf("%-10s %s", "call_pal", mnemonic);
+#endif
+ }
+}};
+
+def format EmulatedCallPal(code, *flags) {{
+ iop = InstObjParams(name, Name, 'EmulatedCallPal', CodeBlock(code), flags)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
+}};
+
+output header {{
+ /**
+ * Base class for full-system-mode call_pal instructions.
+ * Probably could turn this into a leaf class and get rid of the
+ * parser template.
+ */
+ class CallPalBase : public AlphaStaticInst
+ {
+ protected:
+ int palFunc; ///< Function code part of instruction
+ int palOffset; ///< Target PC, offset from IPR_PAL_BASE
+ bool palValid; ///< is the function code valid?
+ bool palPriv; ///< is this call privileged?
+
+ /// Constructor.
+ CallPalBase(const char *mnem, ExtMachInst _machInst,
+ OpClass __opClass);
+
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+}};
+
+output decoder {{
+ inline
+ CallPalBase::CallPalBase(const char *mnem, ExtMachInst _machInst,
+ OpClass __opClass)
+ : AlphaStaticInst(mnem, _machInst, __opClass),
+ palFunc(PALFUNC)
+ {
+ // From the 21164 HRM (paraphrased):
+ // Bit 7 of the function code (mask 0x80) indicates
+ // whether the call is privileged (bit 7 == 0) or
+ // unprivileged (bit 7 == 1). The privileged call table
+ // starts at 0x2000, the unprivielged call table starts at
+ // 0x3000. Bits 5-0 (mask 0x3f) are used to calculate the
+ // offset.
+ const int palPrivMask = 0x80;
+ const int palOffsetMask = 0x3f;
+
+ // Pal call is invalid unless all other bits are 0
+ palValid = ((machInst & ~(palPrivMask | palOffsetMask)) == 0);
+ palPriv = ((machInst & palPrivMask) == 0);
+ int shortPalFunc = (machInst & palOffsetMask);
+ // Add 1 to base to set pal-mode bit
+ palOffset = (palPriv ? 0x2001 : 0x3001) + (shortPalFunc << 6);
+ }
+
+ std::string
+ CallPalBase::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+ return csprintf("%-10s %#x", "call_pal", palFunc);
+ }
+}};
+
+def format CallPal(code, *flags) {{
+ iop = InstObjParams(name, Name, 'CallPalBase', CodeBlock(code), flags)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
+}};
+
+////////////////////////////////////////////////////////////////////
+//
+// hw_ld, hw_st
+//
+
+output header {{
+ /**
+ * Base class for hw_ld and hw_st.
+ */
+ class HwLoadStore : public Memory
+ {
+ protected:
+
+ /// Displacement for EA calculation (signed).
+ int16_t disp;
+
+ /// Constructor
+ HwLoadStore(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
+ StaticInstPtr _eaCompPtr = nullStaticInstPtr,
+ StaticInstPtr _memAccPtr = nullStaticInstPtr);
+
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+}};
+
+
+output decoder {{
+ inline
+ HwLoadStore::HwLoadStore(const char *mnem, ExtMachInst _machInst,
+ OpClass __opClass,
+ StaticInstPtr _eaCompPtr,
+ StaticInstPtr _memAccPtr)
+ : Memory(mnem, _machInst, __opClass, _eaCompPtr, _memAccPtr),
+ disp(HW_LDST_DISP)
+ {
+ memAccessFlags = 0;
+ if (HW_LDST_PHYS) memAccessFlags |= PHYSICAL;
+ if (HW_LDST_ALT) memAccessFlags |= ALTMODE;
+ if (HW_LDST_VPTE) memAccessFlags |= VPTE;
+ if (HW_LDST_LOCK) memAccessFlags |= LOCKED;
+ }
+
+ std::string
+ HwLoadStore::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+#ifdef SS_COMPATIBLE_DISASSEMBLY
+ return csprintf("%-10s r%d,%d(r%d)", mnemonic, RA, disp, RB);
+#else
+ // HW_LDST_LOCK and HW_LDST_COND are the same bit.
+ const char *lock_str =
+ (HW_LDST_LOCK) ? (flags[IsLoad] ? ",LOCK" : ",COND") : "";
+
+ return csprintf("%-10s r%d,%d(r%d)%s%s%s%s%s",
+ mnemonic, RA, disp, RB,
+ HW_LDST_PHYS ? ",PHYS" : "",
+ HW_LDST_ALT ? ",ALT" : "",
+ HW_LDST_QUAD ? ",QUAD" : "",
+ HW_LDST_VPTE ? ",VPTE" : "",
+ lock_str);
+#endif
+ }
+}};
+
+def format HwLoad(ea_code, memacc_code, class_ext, *flags) {{
+ (header_output, decoder_output, decode_block, exec_output) = \
+ LoadStoreBase(name, Name + class_ext, ea_code, memacc_code,
+ mem_flags = [], inst_flags = flags,
+ base_class = 'HwLoadStore', exec_template_base = 'Load')
+}};
+
+
+def format HwStore(ea_code, memacc_code, class_ext, *flags) {{
+ (header_output, decoder_output, decode_block, exec_output) = \
+ LoadStoreBase(name, Name + class_ext, ea_code, memacc_code,
+ mem_flags = [], inst_flags = flags,
+ base_class = 'HwLoadStore', exec_template_base = 'Store')
+}};
+
+
+def format HwStoreCond(ea_code, memacc_code, postacc_code, class_ext,
+ *flags) {{
+ (header_output, decoder_output, decode_block, exec_output) = \
+ LoadStoreBase(name, Name + class_ext, ea_code, memacc_code,
+ postacc_code, mem_flags = [], inst_flags = flags,
+ base_class = 'HwLoadStore')
+}};
+
+
+output header {{
+ /**
+ * Base class for hw_mfpr and hw_mtpr.
+ */
+ class HwMoveIPR : public AlphaStaticInst
+ {
+ protected:
+ /// Index of internal processor register.
+ int ipr_index;
+
+ /// Constructor
+ HwMoveIPR(const char *mnem, ExtMachInst _machInst, OpClass __opClass)
+ : AlphaStaticInst(mnem, _machInst, __opClass),
+ ipr_index(HW_IPR_IDX)
+ {
+ }
+
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+}};
+
+output decoder {{
+ std::string
+ HwMoveIPR::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+ if (_numSrcRegs > 0) {
+ // must be mtpr
+ return csprintf("%-10s r%d,IPR(%#x)",
+ mnemonic, RA, ipr_index);
+ }
+ else {
+ // must be mfpr
+ return csprintf("%-10s IPR(%#x),r%d",
+ mnemonic, ipr_index, RA);
+ }
+ }
+}};
+
+def format HwMoveIPR(code) {{
+ iop = InstObjParams(name, Name, 'HwMoveIPR', CodeBlock(code),
+ ['IprAccessOp'])
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
+}};
+
+
diff --git a/src/arch/alpha/isa/unimp.isa b/src/arch/alpha/isa/unimp.isa
new file mode 100644
index 000000000..392522801
--- /dev/null
+++ b/src/arch/alpha/isa/unimp.isa
@@ -0,0 +1,165 @@
+// -*- mode:c++ -*-
+
+// Copyright (c) 2003-2005 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+output header {{
+ /**
+ * Static instruction class for unimplemented instructions that
+ * cause simulator termination. Note that these are recognized
+ * (legal) instructions that the simulator does not support; the
+ * 'Unknown' class is used for unrecognized/illegal instructions.
+ * This is a leaf class.
+ */
+ class FailUnimplemented : public AlphaStaticInst
+ {
+ public:
+ /// Constructor
+ FailUnimplemented(const char *_mnemonic, ExtMachInst _machInst)
+ : AlphaStaticInst(_mnemonic, _machInst, No_OpClass)
+ {
+ // don't call execute() (which panics) if we're on a
+ // speculative path
+ flags[IsNonSpeculative] = true;
+ }
+
+ %(BasicExecDeclare)s
+
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+
+ /**
+ * Base class for unimplemented instructions that cause a warning
+ * to be printed (but do not terminate simulation). This
+ * implementation is a little screwy in that it will print a
+ * warning for each instance of a particular unimplemented machine
+ * instruction, not just for each unimplemented opcode. Should
+ * probably make the 'warned' flag a static member of the derived
+ * class.
+ */
+ class WarnUnimplemented : public AlphaStaticInst
+ {
+ private:
+ /// Have we warned on this instruction yet?
+ mutable bool warned;
+
+ public:
+ /// Constructor
+ WarnUnimplemented(const char *_mnemonic, ExtMachInst _machInst)
+ : AlphaStaticInst(_mnemonic, _machInst, No_OpClass), warned(false)
+ {
+ // don't call execute() (which panics) if we're on a
+ // speculative path
+ flags[IsNonSpeculative] = true;
+ }
+
+ %(BasicExecDeclare)s
+
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+}};
+
+output decoder {{
+ std::string
+ FailUnimplemented::generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+ {
+ return csprintf("%-10s (unimplemented)", mnemonic);
+ }
+
+ std::string
+ WarnUnimplemented::generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+ {
+#ifdef SS_COMPATIBLE_DISASSEMBLY
+ return csprintf("%-10s", mnemonic);
+#else
+ return csprintf("%-10s (unimplemented)", mnemonic);
+#endif
+ }
+}};
+
+output exec {{
+ Fault
+ FailUnimplemented::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ panic("attempt to execute unimplemented instruction '%s' "
+ "(inst 0x%08x, opcode 0x%x)", mnemonic, machInst, OPCODE);
+ return new UnimplementedOpcodeFault;
+ }
+
+ Fault
+ WarnUnimplemented::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ if (!warned) {
+ warn("instruction '%s' unimplemented\n", mnemonic);
+ warned = true;
+ }
+
+ return NoFault;
+ }
+}};
+
+
+def format FailUnimpl() {{
+ iop = InstObjParams(name, 'FailUnimplemented')
+ decode_block = BasicDecodeWithMnemonic.subst(iop)
+}};
+
+def format WarnUnimpl() {{
+ iop = InstObjParams(name, 'WarnUnimplemented')
+ decode_block = BasicDecodeWithMnemonic.subst(iop)
+}};
+
+output header {{
+ /**
+ * Static instruction class for unknown (illegal) instructions.
+ * These cause simulator termination if they are executed in a
+ * non-speculative mode. This is a leaf class.
+ */
+ class Unknown : public AlphaStaticInst
+ {
+ public:
+ /// Constructor
+ Unknown(ExtMachInst _machInst)
+ : AlphaStaticInst("unknown", _machInst, No_OpClass)
+ {
+ // don't call execute() (which panics) if we're on a
+ // speculative path
+ flags[IsNonSpeculative] = true;
+ }
+
+ %(BasicExecDeclare)s
+
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+}};
+
diff --git a/src/arch/alpha/isa/unknown.isa b/src/arch/alpha/isa/unknown.isa
new file mode 100644
index 000000000..47d166255
--- /dev/null
+++ b/src/arch/alpha/isa/unknown.isa
@@ -0,0 +1,52 @@
+// -*- mode:c++ -*-
+
+// Copyright (c) 2003-2005 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+output decoder {{
+ std::string
+ Unknown::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+ return csprintf("%-10s (inst 0x%x, opcode 0x%x)",
+ "unknown", machInst, OPCODE);
+ }
+}};
+
+output exec {{
+ Fault
+ Unknown::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ panic("attempt to execute unknown instruction "
+ "(inst 0x%08x, opcode 0x%x)", machInst, OPCODE);
+ return new UnimplementedOpcodeFault;
+ }
+}};
+
+def format Unknown() {{
+ decode_block = 'return new Unknown(machInst);\n'
+}};
+
diff --git a/src/arch/alpha/isa/util.isa b/src/arch/alpha/isa/util.isa
new file mode 100644
index 000000000..9fbbf6636
--- /dev/null
+++ b/src/arch/alpha/isa/util.isa
@@ -0,0 +1,112 @@
+// -*- mode:c++ -*-
+
+// Copyright (c) 2003-2005 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+output exec {{
+
+ /// Return opa + opb, summing carry into third arg.
+ inline uint64_t
+ addc(uint64_t opa, uint64_t opb, int &carry)
+ {
+ uint64_t res = opa + opb;
+ if (res < opa || res < opb)
+ ++carry;
+ return res;
+ }
+
+ /// Multiply two 64-bit values (opa * opb), returning the 128-bit
+ /// product in res_hi and res_lo.
+ inline void
+ mul128(uint64_t opa, uint64_t opb, uint64_t &res_hi, uint64_t &res_lo)
+ {
+ // do a 64x64 --> 128 multiply using four 32x32 --> 64 multiplies
+ uint64_t opa_hi = opa<63:32>;
+ uint64_t opa_lo = opa<31:0>;
+ uint64_t opb_hi = opb<63:32>;
+ uint64_t opb_lo = opb<31:0>;
+
+ res_lo = opa_lo * opb_lo;
+
+ // The middle partial products logically belong in bit
+ // positions 95 to 32. Thus the lower 32 bits of each product
+ // sum into the upper 32 bits of the low result, while the
+ // upper 32 sum into the low 32 bits of the upper result.
+ uint64_t partial1 = opa_hi * opb_lo;
+ uint64_t partial2 = opa_lo * opb_hi;
+
+ uint64_t partial1_lo = partial1<31:0> << 32;
+ uint64_t partial1_hi = partial1<63:32>;
+ uint64_t partial2_lo = partial2<31:0> << 32;
+ uint64_t partial2_hi = partial2<63:32>;
+
+ // Add partial1_lo and partial2_lo to res_lo, keeping track
+ // of any carries out
+ int carry_out = 0;
+ res_lo = addc(partial1_lo, res_lo, carry_out);
+ res_lo = addc(partial2_lo, res_lo, carry_out);
+
+ // Now calculate the high 64 bits...
+ res_hi = (opa_hi * opb_hi) + partial1_hi + partial2_hi + carry_out;
+ }
+
+ /// Map 8-bit S-floating exponent to 11-bit T-floating exponent.
+ /// See Table 2-2 of Alpha AHB.
+ inline int
+ map_s(int old_exp)
+ {
+ int hibit = old_exp<7:>;
+ int lobits = old_exp<6:0>;
+
+ if (hibit == 1) {
+ return (lobits == 0x7f) ? 0x7ff : (0x400 | lobits);
+ }
+ else {
+ return (lobits == 0) ? 0 : (0x380 | lobits);
+ }
+ }
+
+ /// Convert a 32-bit S-floating value to the equivalent 64-bit
+ /// representation to be stored in an FP reg.
+ inline uint64_t
+ s_to_t(uint32_t s_val)
+ {
+ uint64_t tmp = s_val;
+ return (tmp<31:> << 63 // sign bit
+ | (uint64_t)map_s(tmp<30:23>) << 52 // exponent
+ | tmp<22:0> << 29); // fraction
+ }
+
+ /// Convert a 64-bit T-floating value to the equivalent 32-bit
+ /// S-floating representation to be stored in memory.
+ inline int32_t
+ t_to_s(uint64_t t_val)
+ {
+ return (t_val<63:62> << 30 // sign bit & hi exp bit
+ | t_val<58:29>); // rest of exp & fraction
+ }
+}};
+
diff --git a/src/arch/alpha/isa_traits.hh b/src/arch/alpha/isa_traits.hh
new file mode 100644
index 000000000..65c72115b
--- /dev/null
+++ b/src/arch/alpha/isa_traits.hh
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ARCH_ALPHA_ISA_TRAITS_HH__
+#define __ARCH_ALPHA_ISA_TRAITS_HH__
+
+namespace LittleEndianGuest {}
+
+#include "arch/alpha/types.hh"
+#include "arch/alpha/constants.hh"
+#include "arch/alpha/regfile.hh"
+#include "config/full_system.hh"
+#include "sim/host.hh"
+
+class StaticInstPtr;
+
+#if !FULL_SYSTEM
+class SyscallReturn {
+ public:
+ template <class T>
+ SyscallReturn(T v, bool s)
+ {
+ retval = (uint64_t)v;
+ success = s;
+ }
+
+ template <class T>
+ SyscallReturn(T v)
+ {
+ success = (v >= 0);
+ retval = (uint64_t)v;
+ }
+
+ ~SyscallReturn() {}
+
+ SyscallReturn& operator=(const SyscallReturn& s) {
+ retval = s.retval;
+ success = s.success;
+ return *this;
+ }
+
+ bool successful() { return success; }
+ uint64_t value() { return retval; }
+
+
+ private:
+ uint64_t retval;
+ bool success;
+};
+
+#endif
+
+#if FULL_SYSTEM
+#include "arch/alpha/isa_fullsys_traits.hh"
+#endif
+
+
+namespace AlphaISA
+{
+
+using namespace LittleEndianGuest;
+
+// redirected register map, really only used for the full system case.
+extern const int reg_redir[NumIntRegs];
+
+ StaticInstPtr decodeInst(ExtMachInst);
+
+#if !FULL_SYSTEM
+ static inline void setSyscallReturn(SyscallReturn return_value, RegFile *regs)
+ {
+ // check for error condition. Alpha syscall convention is to
+ // indicate success/failure in reg a3 (r19) and put the
+ // return value itself in the standard return value reg (v0).
+ if (return_value.successful()) {
+ // no error
+ regs->setIntReg(SyscallSuccessReg, 0);
+ regs->setIntReg(ReturnValueReg, return_value.value());
+ } else {
+ // got an error, return details
+ regs->setIntReg(SyscallSuccessReg, (IntReg)-1);
+ regs->setIntReg(ReturnValueReg, -return_value.value());
+ }
+ }
+#endif
+};
+
+#endif // __ARCH_ALPHA_ISA_TRAITS_HH__
diff --git a/src/arch/alpha/linux/aligned.hh b/src/arch/alpha/linux/aligned.hh
new file mode 100644
index 000000000..cabecb283
--- /dev/null
+++ b/src/arch/alpha/linux/aligned.hh
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2004 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ARCH_ALPHA_LINUX_ALIGNED_HH__
+#define __ARCH_ALPHA_LINUX_ALIGNED_HH__
+
+
+/* GCC 3.3.X has a bug in which attributes+typedefs don't work. 3.2.X is fine
+ * as in 3.4.X, but the bug is marked will not fix in 3.3.X so here is
+ * the work around.
+ */
+#if (__GNUC__ == 3 && __GNUC_MINOR__ != 3) || __GNUC__ > 3
+typedef uint64_t uint64_ta __attribute__ ((aligned (8))) ;
+typedef int64_t int64_ta __attribute__ ((aligned (8))) ;
+typedef Addr Addr_a __attribute__ ((aligned (8))) ;
+#else
+#define uint64_ta uint64_t __attribute__ ((aligned (8)))
+#define int64_ta int64_t __attribute__ ((aligned (8)))
+#define Addr_a Addr __attribute__ ((aligned (8)))
+#endif /* __GNUC__ __GNUC_MINOR__ */
+
+#endif /* __ARCH_ALPHA_LINUX_ALIGNED_HH__ */
diff --git a/src/arch/alpha/linux/hwrpb.hh b/src/arch/alpha/linux/hwrpb.hh
new file mode 100644
index 000000000..869ce026b
--- /dev/null
+++ b/src/arch/alpha/linux/hwrpb.hh
@@ -0,0 +1,42 @@
+/*
+ * Copyright 1990 Hewlett-Packard Development Company, L.P.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __ARCH_ALPHA_LINUX_HWRPB_HH__
+#define __ARCH_ALPHA_LINUX_HWRPB_HH__
+
+#include "arch/alpha/linux/aligned.hh"
+
+namespace Linux {
+ struct pcb_struct {
+ uint64_ta rpb_ksp;
+ uint64_ta rpb_usp;
+ uint64_ta rpb_ptbr;
+ uint32_t rpb_cc;
+ uint32_t rpb_psn;
+ uint64_ta rpb_unique;
+ uint64_ta rpb_fen;
+ uint64_ta res1, res2;
+ };
+}
+#endif // __ARCH_ALPHA_LINUX_HWRPB_HH__
diff --git a/src/arch/alpha/linux/linux.cc b/src/arch/alpha/linux/linux.cc
new file mode 100644
index 000000000..f123ae1fe
--- /dev/null
+++ b/src/arch/alpha/linux/linux.cc
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "arch/alpha/linux/linux.hh"
+
+// open(2) flags translation table
+OpenFlagTransTable AlphaLinux::openFlagTable[] = {
+#ifdef _MSC_VER
+ { AlphaLinux::TGT_O_RDONLY, _O_RDONLY },
+ { AlphaLinux::TGT_O_WRONLY, _O_WRONLY },
+ { AlphaLinux::TGT_O_RDWR, _O_RDWR },
+ { AlphaLinux::TGT_O_APPEND, _O_APPEND },
+ { AlphaLinux::TGT_O_CREAT, _O_CREAT },
+ { AlphaLinux::TGT_O_TRUNC, _O_TRUNC },
+ { AlphaLinux::TGT_O_EXCL, _O_EXCL },
+#ifdef _O_NONBLOCK
+ { AlphaLinux::TGT_O_NONBLOCK, _O_NONBLOCK },
+#endif
+#ifdef _O_NOCTTY
+ { AlphaLinux::TGT_O_NOCTTY, _O_NOCTTY },
+#endif
+#ifdef _O_SYNC
+ { AlphaLinux::TGT_O_SYNC, _O_SYNC },
+#endif
+#else /* !_MSC_VER */
+ { AlphaLinux::TGT_O_RDONLY, O_RDONLY },
+ { AlphaLinux::TGT_O_WRONLY, O_WRONLY },
+ { AlphaLinux::TGT_O_RDWR, O_RDWR },
+ { AlphaLinux::TGT_O_APPEND, O_APPEND },
+ { AlphaLinux::TGT_O_CREAT, O_CREAT },
+ { AlphaLinux::TGT_O_TRUNC, O_TRUNC },
+ { AlphaLinux::TGT_O_EXCL, O_EXCL },
+ { AlphaLinux::TGT_O_NONBLOCK, O_NONBLOCK },
+ { AlphaLinux::TGT_O_NOCTTY, O_NOCTTY },
+#ifdef O_SYNC
+ { AlphaLinux::TGT_O_SYNC, O_SYNC },
+#endif
+#endif /* _MSC_VER */
+};
+
+const int AlphaLinux::NUM_OPEN_FLAGS =
+ (sizeof(AlphaLinux::openFlagTable)/sizeof(AlphaLinux::openFlagTable[0]));
+
+
+
diff --git a/src/arch/alpha/linux/linux.hh b/src/arch/alpha/linux/linux.hh
new file mode 100644
index 000000000..f04e2bfa8
--- /dev/null
+++ b/src/arch/alpha/linux/linux.hh
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ALPHA_ALPHA_LINUX_HH
+#define __ALPHA_ALPHA_LINUX_HH
+
+#include "kern/linux/linux.hh"
+
+/* AlphaLinux class contains static constants/definitions/misc.
+ * structures which are specific to the Linux OS AND the Alpha
+ * architecture
+ */
+class AlphaLinux : public Linux
+{
+ public:
+
+ /// This table maps the target open() flags to the corresponding
+ /// host open() flags.
+ static OpenFlagTransTable openFlagTable[];
+
+ /// Number of entries in openFlagTable[].
+ static const int NUM_OPEN_FLAGS;
+
+ //@{
+ /// open(2) flag values.
+ static const int TGT_O_RDONLY = 00000000; //!< O_RDONLY
+ static const int TGT_O_WRONLY = 00000001; //!< O_WRONLY
+ static const int TGT_O_RDWR = 00000002; //!< O_RDWR
+ static const int TGT_O_NONBLOCK = 00000004; //!< O_NONBLOCK
+ static const int TGT_O_APPEND = 00000010; //!< O_APPEND
+ static const int TGT_O_CREAT = 00001000; //!< O_CREAT
+ static const int TGT_O_TRUNC = 00002000; //!< O_TRUNC
+ static const int TGT_O_EXCL = 00004000; //!< O_EXCL
+ static const int TGT_O_NOCTTY = 00010000; //!< O_NOCTTY
+ static const int TGT_O_SYNC = 00040000; //!< O_SYNC
+ static const int TGT_O_DRD = 00100000; //!< O_DRD
+ static const int TGT_O_DIRECTIO = 00200000; //!< O_DIRECTIO
+ static const int TGT_O_CACHE = 00400000; //!< O_CACHE
+ static const int TGT_O_DSYNC = 02000000; //!< O_DSYNC
+ static const int TGT_O_RSYNC = 04000000; //!< O_RSYNC
+ //@}
+
+ /// For mmap().
+ static const unsigned TGT_MAP_ANONYMOUS = 0x10;
+
+ //@{
+ /// For getsysinfo().
+ static const unsigned GSI_PLATFORM_NAME = 103; //!< platform name as string
+ static const unsigned GSI_CPU_INFO = 59; //!< CPU information
+ static const unsigned GSI_PROC_TYPE = 60; //!< get proc_type
+ static const unsigned GSI_MAX_CPU = 30; //!< max # cpu's on this machine
+ static const unsigned GSI_CPUS_IN_BOX = 55; //!< number of CPUs in system
+ static const unsigned GSI_PHYSMEM = 19; //!< Physical memory in KB
+ static const unsigned GSI_CLK_TCK = 42; //!< clock freq in Hz
+ static const unsigned GSI_IEEE_FP_CONTROL = 45;
+ //@}
+
+ //@{
+ /// For getrusage().
+ static const int TGT_RUSAGE_SELF = 0;
+ static const int TGT_RUSAGE_CHILDREN = -1;
+ static const int TGT_RUSAGE_BOTH = -2;
+ //@}
+
+ //@{
+ /// For setsysinfo().
+ static const unsigned SSI_IEEE_FP_CONTROL = 14; //!< ieee_set_fp_control()
+ //@}
+
+ //@{
+ /// ioctl() command codes.
+ static const unsigned TIOCGETP = 0x40067408;
+ static const unsigned TIOCSETP = 0x80067409;
+ static const unsigned TIOCSETN = 0x8006740a;
+ static const unsigned TIOCSETC = 0x80067411;
+ static const unsigned TIOCGETC = 0x40067412;
+ static const unsigned FIONREAD = 0x4004667f;
+ static const unsigned TIOCISATTY = 0x2000745e;
+ static const unsigned TIOCGETS = 0x402c7413;
+ static const unsigned TIOCGETA = 0x40127417;
+ //@}
+
+ /// For table().
+ static const int TBL_SYSINFO = 12;
+
+ /// Resource enumeration for getrlimit().
+ enum rlimit_resources {
+ TGT_RLIMIT_CPU = 0,
+ TGT_RLIMIT_FSIZE = 1,
+ TGT_RLIMIT_DATA = 2,
+ TGT_RLIMIT_STACK = 3,
+ TGT_RLIMIT_CORE = 4,
+ TGT_RLIMIT_RSS = 5,
+ TGT_RLIMIT_NOFILE = 6,
+ TGT_RLIMIT_AS = 7,
+ TGT_RLIMIT_VMEM = 7,
+ TGT_RLIMIT_NPROC = 8,
+ TGT_RLIMIT_MEMLOCK = 9,
+ TGT_RLIMIT_LOCKS = 10
+ };
+};
+
+#endif
diff --git a/src/arch/alpha/linux/process.cc b/src/arch/alpha/linux/process.cc
new file mode 100644
index 000000000..9f4f65db8
--- /dev/null
+++ b/src/arch/alpha/linux/process.cc
@@ -0,0 +1,591 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "arch/alpha/linux/linux.hh"
+#include "arch/alpha/linux/process.hh"
+#include "arch/alpha/isa_traits.hh"
+
+#include "base/trace.hh"
+#include "cpu/exec_context.hh"
+#include "kern/linux/linux.hh"
+
+#include "sim/process.hh"
+#include "sim/syscall_emul.hh"
+
+using namespace std;
+using namespace AlphaISA;
+
+
+
+/// Target uname() handler.
+static SyscallReturn
+unameFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ TypedBufferArg<Linux::utsname> name(xc->getSyscallArg(0));
+
+ strcpy(name->sysname, "Linux");
+ strcpy(name->nodename, "m5.eecs.umich.edu");
+ strcpy(name->release, "2.4.20");
+ strcpy(name->version, "#1 Mon Aug 18 11:32:15 EDT 2003");
+ strcpy(name->machine, "alpha");
+
+ name.copyOut(xc->getMemPort());
+ return 0;
+}
+
+/// Target osf_getsysyinfo() handler. Even though this call is
+/// borrowed from Tru64, the subcases that get used appear to be
+/// different in practice from those used by Tru64 processes.
+static SyscallReturn
+osf_getsysinfoFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ unsigned op = xc->getSyscallArg(0);
+ // unsigned nbytes = xc->getSyscallArg(2);
+
+ switch (op) {
+
+ case 45: { // GSI_IEEE_FP_CONTROL
+ TypedBufferArg<uint64_t> fpcr(xc->getSyscallArg(1));
+ // I don't think this exactly matches the HW FPCR
+ *fpcr = 0;
+ fpcr.copyOut(xc->getMemPort());
+ return 0;
+ }
+
+ default:
+ cerr << "osf_getsysinfo: unknown op " << op << endl;
+ abort();
+ break;
+ }
+
+ return 1;
+}
+
+/// Target osf_setsysinfo() handler.
+static SyscallReturn
+osf_setsysinfoFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ unsigned op = xc->getSyscallArg(0);
+ // unsigned nbytes = xc->getSyscallArg(2);
+
+ switch (op) {
+
+ case 14: { // SSI_IEEE_FP_CONTROL
+ TypedBufferArg<uint64_t> fpcr(xc->getSyscallArg(1));
+ // I don't think this exactly matches the HW FPCR
+ fpcr.copyIn(xc->getMemPort());
+ DPRINTFR(SyscallVerbose, "osf_setsysinfo(SSI_IEEE_FP_CONTROL): "
+ " setting FPCR to 0x%x\n", gtoh(*(uint64_t*)fpcr));
+ return 0;
+ }
+
+ default:
+ cerr << "osf_setsysinfo: unknown op " << op << endl;
+ abort();
+ break;
+ }
+
+ return 1;
+}
+
+
+SyscallDesc AlphaLinuxProcess::syscallDescs[] = {
+ /* 0 */ SyscallDesc("osf_syscall", unimplementedFunc),
+ /* 1 */ SyscallDesc("exit", exitFunc),
+ /* 2 */ SyscallDesc("fork", unimplementedFunc),
+ /* 3 */ SyscallDesc("read", readFunc),
+ /* 4 */ SyscallDesc("write", writeFunc),
+ /* 5 */ SyscallDesc("osf_old_open", unimplementedFunc),
+ /* 6 */ SyscallDesc("close", closeFunc),
+ /* 7 */ SyscallDesc("osf_wait4", unimplementedFunc),
+ /* 8 */ SyscallDesc("osf_old_creat", unimplementedFunc),
+ /* 9 */ SyscallDesc("link", unimplementedFunc),
+ /* 10 */ SyscallDesc("unlink", unlinkFunc),
+ /* 11 */ SyscallDesc("osf_execve", unimplementedFunc),
+ /* 12 */ SyscallDesc("chdir", unimplementedFunc),
+ /* 13 */ SyscallDesc("fchdir", unimplementedFunc),
+ /* 14 */ SyscallDesc("mknod", unimplementedFunc),
+ /* 15 */ SyscallDesc("chmod", chmodFunc<AlphaLinux>),
+ /* 16 */ SyscallDesc("chown", chownFunc),
+ /* 17 */ SyscallDesc("brk", obreakFunc),
+ /* 18 */ SyscallDesc("osf_getfsstat", unimplementedFunc),
+ /* 19 */ SyscallDesc("lseek", lseekFunc),
+ /* 20 */ SyscallDesc("getxpid", getpidPseudoFunc),
+ /* 21 */ SyscallDesc("osf_mount", unimplementedFunc),
+ /* 22 */ SyscallDesc("umount", unimplementedFunc),
+ /* 23 */ SyscallDesc("setuid", setuidFunc),
+ /* 24 */ SyscallDesc("getxuid", getuidPseudoFunc),
+ /* 25 */ SyscallDesc("exec_with_loader", unimplementedFunc),
+ /* 26 */ SyscallDesc("osf_ptrace", unimplementedFunc),
+ /* 27 */ SyscallDesc("osf_nrecvmsg", unimplementedFunc),
+ /* 28 */ SyscallDesc("osf_nsendmsg", unimplementedFunc),
+ /* 29 */ SyscallDesc("osf_nrecvfrom", unimplementedFunc),
+ /* 30 */ SyscallDesc("osf_naccept", unimplementedFunc),
+ /* 31 */ SyscallDesc("osf_ngetpeername", unimplementedFunc),
+ /* 32 */ SyscallDesc("osf_ngetsockname", unimplementedFunc),
+ /* 33 */ SyscallDesc("access", unimplementedFunc),
+ /* 34 */ SyscallDesc("osf_chflags", unimplementedFunc),
+ /* 35 */ SyscallDesc("osf_fchflags", unimplementedFunc),
+ /* 36 */ SyscallDesc("sync", unimplementedFunc),
+ /* 37 */ SyscallDesc("kill", unimplementedFunc),
+ /* 38 */ SyscallDesc("osf_old_stat", unimplementedFunc),
+ /* 39 */ SyscallDesc("setpgid", unimplementedFunc),
+ /* 40 */ SyscallDesc("osf_old_lstat", unimplementedFunc),
+ /* 41 */ SyscallDesc("dup", unimplementedFunc),
+ /* 42 */ SyscallDesc("pipe", pipePseudoFunc),
+ /* 43 */ SyscallDesc("osf_set_program_attributes", unimplementedFunc),
+ /* 44 */ SyscallDesc("osf_profil", unimplementedFunc),
+ /* 45 */ SyscallDesc("open", openFunc<AlphaLinux>),
+ /* 46 */ SyscallDesc("osf_old_sigaction", unimplementedFunc),
+ /* 47 */ SyscallDesc("getxgid", getgidPseudoFunc),
+ /* 48 */ SyscallDesc("osf_sigprocmask", ignoreFunc),
+ /* 49 */ SyscallDesc("osf_getlogin", unimplementedFunc),
+ /* 50 */ SyscallDesc("osf_setlogin", unimplementedFunc),
+ /* 51 */ SyscallDesc("acct", unimplementedFunc),
+ /* 52 */ SyscallDesc("sigpending", unimplementedFunc),
+ /* 53 */ SyscallDesc("osf_classcntl", unimplementedFunc),
+ /* 54 */ SyscallDesc("ioctl", ioctlFunc<AlphaLinux>),
+ /* 55 */ SyscallDesc("osf_reboot", unimplementedFunc),
+ /* 56 */ SyscallDesc("osf_revoke", unimplementedFunc),
+ /* 57 */ SyscallDesc("symlink", unimplementedFunc),
+ /* 58 */ SyscallDesc("readlink", unimplementedFunc),
+ /* 59 */ SyscallDesc("execve", unimplementedFunc),
+ /* 60 */ SyscallDesc("umask", unimplementedFunc),
+ /* 61 */ SyscallDesc("chroot", unimplementedFunc),
+ /* 62 */ SyscallDesc("osf_old_fstat", unimplementedFunc),
+ /* 63 */ SyscallDesc("getpgrp", unimplementedFunc),
+ /* 64 */ SyscallDesc("getpagesize", getpagesizeFunc),
+ /* 65 */ SyscallDesc("osf_mremap", unimplementedFunc),
+ /* 66 */ SyscallDesc("vfork", unimplementedFunc),
+ /* 67 */ SyscallDesc("stat", statFunc<AlphaLinux>),
+ /* 68 */ SyscallDesc("lstat", lstatFunc<AlphaLinux>),
+ /* 69 */ SyscallDesc("osf_sbrk", unimplementedFunc),
+ /* 70 */ SyscallDesc("osf_sstk", unimplementedFunc),
+ /* 71 */ SyscallDesc("mmap", mmapFunc<AlphaLinux>),
+ /* 72 */ SyscallDesc("osf_old_vadvise", unimplementedFunc),
+ /* 73 */ SyscallDesc("munmap", munmapFunc),
+ /* 74 */ SyscallDesc("mprotect", ignoreFunc),
+ /* 75 */ SyscallDesc("madvise", unimplementedFunc),
+ /* 76 */ SyscallDesc("vhangup", unimplementedFunc),
+ /* 77 */ SyscallDesc("osf_kmodcall", unimplementedFunc),
+ /* 78 */ SyscallDesc("osf_mincore", unimplementedFunc),
+ /* 79 */ SyscallDesc("getgroups", unimplementedFunc),
+ /* 80 */ SyscallDesc("setgroups", unimplementedFunc),
+ /* 81 */ SyscallDesc("osf_old_getpgrp", unimplementedFunc),
+ /* 82 */ SyscallDesc("setpgrp", unimplementedFunc),
+ /* 83 */ SyscallDesc("osf_setitimer", unimplementedFunc),
+ /* 84 */ SyscallDesc("osf_old_wait", unimplementedFunc),
+ /* 85 */ SyscallDesc("osf_table", unimplementedFunc),
+ /* 86 */ SyscallDesc("osf_getitimer", unimplementedFunc),
+ /* 87 */ SyscallDesc("gethostname", gethostnameFunc),
+ /* 88 */ SyscallDesc("sethostname", unimplementedFunc),
+ /* 89 */ SyscallDesc("getdtablesize", unimplementedFunc),
+ /* 90 */ SyscallDesc("dup2", unimplementedFunc),
+ /* 91 */ SyscallDesc("fstat", fstatFunc<AlphaLinux>),
+ /* 92 */ SyscallDesc("fcntl", fcntlFunc),
+ /* 93 */ SyscallDesc("osf_select", unimplementedFunc),
+ /* 94 */ SyscallDesc("poll", unimplementedFunc),
+ /* 95 */ SyscallDesc("fsync", unimplementedFunc),
+ /* 96 */ SyscallDesc("setpriority", unimplementedFunc),
+ /* 97 */ SyscallDesc("socket", unimplementedFunc),
+ /* 98 */ SyscallDesc("connect", unimplementedFunc),
+ /* 99 */ SyscallDesc("accept", unimplementedFunc),
+ /* 100 */ SyscallDesc("getpriority", unimplementedFunc),
+ /* 101 */ SyscallDesc("send", unimplementedFunc),
+ /* 102 */ SyscallDesc("recv", unimplementedFunc),
+ /* 103 */ SyscallDesc("sigreturn", unimplementedFunc),
+ /* 104 */ SyscallDesc("bind", unimplementedFunc),
+ /* 105 */ SyscallDesc("setsockopt", unimplementedFunc),
+ /* 106 */ SyscallDesc("listen", unimplementedFunc),
+ /* 107 */ SyscallDesc("osf_plock", unimplementedFunc),
+ /* 108 */ SyscallDesc("osf_old_sigvec", unimplementedFunc),
+ /* 109 */ SyscallDesc("osf_old_sigblock", unimplementedFunc),
+ /* 110 */ SyscallDesc("osf_old_sigsetmask", unimplementedFunc),
+ /* 111 */ SyscallDesc("sigsuspend", unimplementedFunc),
+ /* 112 */ SyscallDesc("osf_sigstack", ignoreFunc),
+ /* 113 */ SyscallDesc("recvmsg", unimplementedFunc),
+ /* 114 */ SyscallDesc("sendmsg", unimplementedFunc),
+ /* 115 */ SyscallDesc("osf_old_vtrace", unimplementedFunc),
+ /* 116 */ SyscallDesc("osf_gettimeofday", unimplementedFunc),
+ /* 117 */ SyscallDesc("osf_getrusage", unimplementedFunc),
+ /* 118 */ SyscallDesc("getsockopt", unimplementedFunc),
+ /* 119 */ SyscallDesc("numa_syscalls", unimplementedFunc),
+ /* 120 */ SyscallDesc("readv", unimplementedFunc),
+ /* 121 */ SyscallDesc("writev", writevFunc<AlphaLinux>),
+ /* 122 */ SyscallDesc("osf_settimeofday", unimplementedFunc),
+ /* 123 */ SyscallDesc("fchown", fchownFunc),
+ /* 124 */ SyscallDesc("fchmod", fchmodFunc<AlphaLinux>),
+ /* 125 */ SyscallDesc("recvfrom", unimplementedFunc),
+ /* 126 */ SyscallDesc("setreuid", unimplementedFunc),
+ /* 127 */ SyscallDesc("setregid", unimplementedFunc),
+ /* 128 */ SyscallDesc("rename", renameFunc),
+ /* 129 */ SyscallDesc("truncate", unimplementedFunc),
+ /* 130 */ SyscallDesc("ftruncate", unimplementedFunc),
+ /* 131 */ SyscallDesc("flock", unimplementedFunc),
+ /* 132 */ SyscallDesc("setgid", unimplementedFunc),
+ /* 133 */ SyscallDesc("sendto", unimplementedFunc),
+ /* 134 */ SyscallDesc("shutdown", unimplementedFunc),
+ /* 135 */ SyscallDesc("socketpair", unimplementedFunc),
+ /* 136 */ SyscallDesc("mkdir", unimplementedFunc),
+ /* 137 */ SyscallDesc("rmdir", unimplementedFunc),
+ /* 138 */ SyscallDesc("osf_utimes", unimplementedFunc),
+ /* 139 */ SyscallDesc("osf_old_sigreturn", unimplementedFunc),
+ /* 140 */ SyscallDesc("osf_adjtime", unimplementedFunc),
+ /* 141 */ SyscallDesc("getpeername", unimplementedFunc),
+ /* 142 */ SyscallDesc("osf_gethostid", unimplementedFunc),
+ /* 143 */ SyscallDesc("osf_sethostid", unimplementedFunc),
+ /* 144 */ SyscallDesc("getrlimit", getrlimitFunc<AlphaLinux>),
+ /* 145 */ SyscallDesc("setrlimit", ignoreFunc),
+ /* 146 */ SyscallDesc("osf_old_killpg", unimplementedFunc),
+ /* 147 */ SyscallDesc("setsid", unimplementedFunc),
+ /* 148 */ SyscallDesc("quotactl", unimplementedFunc),
+ /* 149 */ SyscallDesc("osf_oldquota", unimplementedFunc),
+ /* 150 */ SyscallDesc("getsockname", unimplementedFunc),
+ /* 151 */ SyscallDesc("osf_pread", unimplementedFunc),
+ /* 152 */ SyscallDesc("osf_pwrite", unimplementedFunc),
+ /* 153 */ SyscallDesc("osf_pid_block", unimplementedFunc),
+ /* 154 */ SyscallDesc("osf_pid_unblock", unimplementedFunc),
+ /* 155 */ SyscallDesc("osf_signal_urti", unimplementedFunc),
+ /* 156 */ SyscallDesc("sigaction", ignoreFunc),
+ /* 157 */ SyscallDesc("osf_sigwaitprim", unimplementedFunc),
+ /* 158 */ SyscallDesc("osf_nfssvc", unimplementedFunc),
+ /* 159 */ SyscallDesc("osf_getdirentries", unimplementedFunc),
+ /* 160 */ SyscallDesc("osf_statfs", unimplementedFunc),
+ /* 161 */ SyscallDesc("osf_fstatfs", unimplementedFunc),
+ /* 162 */ SyscallDesc("unknown #162", unimplementedFunc),
+ /* 163 */ SyscallDesc("osf_async_daemon", unimplementedFunc),
+ /* 164 */ SyscallDesc("osf_getfh", unimplementedFunc),
+ /* 165 */ SyscallDesc("osf_getdomainname", unimplementedFunc),
+ /* 166 */ SyscallDesc("setdomainname", unimplementedFunc),
+ /* 167 */ SyscallDesc("unknown #167", unimplementedFunc),
+ /* 168 */ SyscallDesc("unknown #168", unimplementedFunc),
+ /* 169 */ SyscallDesc("osf_exportfs", unimplementedFunc),
+ /* 170 */ SyscallDesc("unknown #170", unimplementedFunc),
+ /* 171 */ SyscallDesc("unknown #171", unimplementedFunc),
+ /* 172 */ SyscallDesc("unknown #172", unimplementedFunc),
+ /* 173 */ SyscallDesc("unknown #173", unimplementedFunc),
+ /* 174 */ SyscallDesc("unknown #174", unimplementedFunc),
+ /* 175 */ SyscallDesc("unknown #175", unimplementedFunc),
+ /* 176 */ SyscallDesc("unknown #176", unimplementedFunc),
+ /* 177 */ SyscallDesc("unknown #177", unimplementedFunc),
+ /* 178 */ SyscallDesc("unknown #178", unimplementedFunc),
+ /* 179 */ SyscallDesc("unknown #179", unimplementedFunc),
+ /* 180 */ SyscallDesc("unknown #180", unimplementedFunc),
+ /* 181 */ SyscallDesc("osf_alt_plock", unimplementedFunc),
+ /* 182 */ SyscallDesc("unknown #182", unimplementedFunc),
+ /* 183 */ SyscallDesc("unknown #183", unimplementedFunc),
+ /* 184 */ SyscallDesc("osf_getmnt", unimplementedFunc),
+ /* 185 */ SyscallDesc("unknown #185", unimplementedFunc),
+ /* 186 */ SyscallDesc("unknown #186", unimplementedFunc),
+ /* 187 */ SyscallDesc("osf_alt_sigpending", unimplementedFunc),
+ /* 188 */ SyscallDesc("osf_alt_setsid", unimplementedFunc),
+ /* 189 */ SyscallDesc("unknown #189", unimplementedFunc),
+ /* 190 */ SyscallDesc("unknown #190", unimplementedFunc),
+ /* 191 */ SyscallDesc("unknown #191", unimplementedFunc),
+ /* 192 */ SyscallDesc("unknown #192", unimplementedFunc),
+ /* 193 */ SyscallDesc("unknown #193", unimplementedFunc),
+ /* 194 */ SyscallDesc("unknown #194", unimplementedFunc),
+ /* 195 */ SyscallDesc("unknown #195", unimplementedFunc),
+ /* 196 */ SyscallDesc("unknown #196", unimplementedFunc),
+ /* 197 */ SyscallDesc("unknown #197", unimplementedFunc),
+ /* 198 */ SyscallDesc("unknown #198", unimplementedFunc),
+ /* 199 */ SyscallDesc("osf_swapon", unimplementedFunc),
+ /* 200 */ SyscallDesc("msgctl", unimplementedFunc),
+ /* 201 */ SyscallDesc("msgget", unimplementedFunc),
+ /* 202 */ SyscallDesc("msgrcv", unimplementedFunc),
+ /* 203 */ SyscallDesc("msgsnd", unimplementedFunc),
+ /* 204 */ SyscallDesc("semctl", unimplementedFunc),
+ /* 205 */ SyscallDesc("semget", unimplementedFunc),
+ /* 206 */ SyscallDesc("semop", unimplementedFunc),
+ /* 207 */ SyscallDesc("osf_utsname", unimplementedFunc),
+ /* 208 */ SyscallDesc("lchown", unimplementedFunc),
+ /* 209 */ SyscallDesc("osf_shmat", unimplementedFunc),
+ /* 210 */ SyscallDesc("shmctl", unimplementedFunc),
+ /* 211 */ SyscallDesc("shmdt", unimplementedFunc),
+ /* 212 */ SyscallDesc("shmget", unimplementedFunc),
+ /* 213 */ SyscallDesc("osf_mvalid", unimplementedFunc),
+ /* 214 */ SyscallDesc("osf_getaddressconf", unimplementedFunc),
+ /* 215 */ SyscallDesc("osf_msleep", unimplementedFunc),
+ /* 216 */ SyscallDesc("osf_mwakeup", unimplementedFunc),
+ /* 217 */ SyscallDesc("msync", unimplementedFunc),
+ /* 218 */ SyscallDesc("osf_signal", unimplementedFunc),
+ /* 219 */ SyscallDesc("osf_utc_gettime", unimplementedFunc),
+ /* 220 */ SyscallDesc("osf_utc_adjtime", unimplementedFunc),
+ /* 221 */ SyscallDesc("unknown #221", unimplementedFunc),
+ /* 222 */ SyscallDesc("osf_security", unimplementedFunc),
+ /* 223 */ SyscallDesc("osf_kloadcall", unimplementedFunc),
+ /* 224 */ SyscallDesc("unknown #224", unimplementedFunc),
+ /* 225 */ SyscallDesc("unknown #225", unimplementedFunc),
+ /* 226 */ SyscallDesc("unknown #226", unimplementedFunc),
+ /* 227 */ SyscallDesc("unknown #227", unimplementedFunc),
+ /* 228 */ SyscallDesc("unknown #228", unimplementedFunc),
+ /* 229 */ SyscallDesc("unknown #229", unimplementedFunc),
+ /* 230 */ SyscallDesc("unknown #230", unimplementedFunc),
+ /* 231 */ SyscallDesc("unknown #231", unimplementedFunc),
+ /* 232 */ SyscallDesc("unknown #232", unimplementedFunc),
+ /* 233 */ SyscallDesc("getpgid", unimplementedFunc),
+ /* 234 */ SyscallDesc("getsid", unimplementedFunc),
+ /* 235 */ SyscallDesc("sigaltstack", ignoreFunc),
+ /* 236 */ SyscallDesc("osf_waitid", unimplementedFunc),
+ /* 237 */ SyscallDesc("osf_priocntlset", unimplementedFunc),
+ /* 238 */ SyscallDesc("osf_sigsendset", unimplementedFunc),
+ /* 239 */ SyscallDesc("osf_set_speculative", unimplementedFunc),
+ /* 240 */ SyscallDesc("osf_msfs_syscall", unimplementedFunc),
+ /* 241 */ SyscallDesc("osf_sysinfo", unimplementedFunc),
+ /* 242 */ SyscallDesc("osf_uadmin", unimplementedFunc),
+ /* 243 */ SyscallDesc("osf_fuser", unimplementedFunc),
+ /* 244 */ SyscallDesc("osf_proplist_syscall", unimplementedFunc),
+ /* 245 */ SyscallDesc("osf_ntp_adjtime", unimplementedFunc),
+ /* 246 */ SyscallDesc("osf_ntp_gettime", unimplementedFunc),
+ /* 247 */ SyscallDesc("osf_pathconf", unimplementedFunc),
+ /* 248 */ SyscallDesc("osf_fpathconf", unimplementedFunc),
+ /* 249 */ SyscallDesc("unknown #249", unimplementedFunc),
+ /* 250 */ SyscallDesc("osf_uswitch", unimplementedFunc),
+ /* 251 */ SyscallDesc("osf_usleep_thread", unimplementedFunc),
+ /* 252 */ SyscallDesc("osf_audcntl", unimplementedFunc),
+ /* 253 */ SyscallDesc("osf_audgen", unimplementedFunc),
+ /* 254 */ SyscallDesc("sysfs", unimplementedFunc),
+ /* 255 */ SyscallDesc("osf_subsys_info", unimplementedFunc),
+ /* 256 */ SyscallDesc("osf_getsysinfo", osf_getsysinfoFunc),
+ /* 257 */ SyscallDesc("osf_setsysinfo", osf_setsysinfoFunc),
+ /* 258 */ SyscallDesc("osf_afs_syscall", unimplementedFunc),
+ /* 259 */ SyscallDesc("osf_swapctl", unimplementedFunc),
+ /* 260 */ SyscallDesc("osf_memcntl", unimplementedFunc),
+ /* 261 */ SyscallDesc("osf_fdatasync", unimplementedFunc),
+ /* 262 */ SyscallDesc("unknown #262", unimplementedFunc),
+ /* 263 */ SyscallDesc("unknown #263", unimplementedFunc),
+ /* 264 */ SyscallDesc("unknown #264", unimplementedFunc),
+ /* 265 */ SyscallDesc("unknown #265", unimplementedFunc),
+ /* 266 */ SyscallDesc("unknown #266", unimplementedFunc),
+ /* 267 */ SyscallDesc("unknown #267", unimplementedFunc),
+ /* 268 */ SyscallDesc("unknown #268", unimplementedFunc),
+ /* 269 */ SyscallDesc("unknown #269", unimplementedFunc),
+ /* 270 */ SyscallDesc("unknown #270", unimplementedFunc),
+ /* 271 */ SyscallDesc("unknown #271", unimplementedFunc),
+ /* 272 */ SyscallDesc("unknown #272", unimplementedFunc),
+ /* 273 */ SyscallDesc("unknown #273", unimplementedFunc),
+ /* 274 */ SyscallDesc("unknown #274", unimplementedFunc),
+ /* 275 */ SyscallDesc("unknown #275", unimplementedFunc),
+ /* 276 */ SyscallDesc("unknown #276", unimplementedFunc),
+ /* 277 */ SyscallDesc("unknown #277", unimplementedFunc),
+ /* 278 */ SyscallDesc("unknown #278", unimplementedFunc),
+ /* 279 */ SyscallDesc("unknown #279", unimplementedFunc),
+ /* 280 */ SyscallDesc("unknown #280", unimplementedFunc),
+ /* 281 */ SyscallDesc("unknown #281", unimplementedFunc),
+ /* 282 */ SyscallDesc("unknown #282", unimplementedFunc),
+ /* 283 */ SyscallDesc("unknown #283", unimplementedFunc),
+ /* 284 */ SyscallDesc("unknown #284", unimplementedFunc),
+ /* 285 */ SyscallDesc("unknown #285", unimplementedFunc),
+ /* 286 */ SyscallDesc("unknown #286", unimplementedFunc),
+ /* 287 */ SyscallDesc("unknown #287", unimplementedFunc),
+ /* 288 */ SyscallDesc("unknown #288", unimplementedFunc),
+ /* 289 */ SyscallDesc("unknown #289", unimplementedFunc),
+ /* 290 */ SyscallDesc("unknown #290", unimplementedFunc),
+ /* 291 */ SyscallDesc("unknown #291", unimplementedFunc),
+ /* 292 */ SyscallDesc("unknown #292", unimplementedFunc),
+ /* 293 */ SyscallDesc("unknown #293", unimplementedFunc),
+ /* 294 */ SyscallDesc("unknown #294", unimplementedFunc),
+ /* 295 */ SyscallDesc("unknown #295", unimplementedFunc),
+ /* 296 */ SyscallDesc("unknown #296", unimplementedFunc),
+ /* 297 */ SyscallDesc("unknown #297", unimplementedFunc),
+ /* 298 */ SyscallDesc("unknown #298", unimplementedFunc),
+ /* 299 */ SyscallDesc("unknown #299", unimplementedFunc),
+/*
+ * Linux-specific system calls begin at 300
+ */
+ /* 300 */ SyscallDesc("bdflush", unimplementedFunc),
+ /* 301 */ SyscallDesc("sethae", unimplementedFunc),
+ /* 302 */ SyscallDesc("mount", unimplementedFunc),
+ /* 303 */ SyscallDesc("old_adjtimex", unimplementedFunc),
+ /* 304 */ SyscallDesc("swapoff", unimplementedFunc),
+ /* 305 */ SyscallDesc("getdents", unimplementedFunc),
+ /* 306 */ SyscallDesc("create_module", unimplementedFunc),
+ /* 307 */ SyscallDesc("init_module", unimplementedFunc),
+ /* 308 */ SyscallDesc("delete_module", unimplementedFunc),
+ /* 309 */ SyscallDesc("get_kernel_syms", unimplementedFunc),
+ /* 310 */ SyscallDesc("syslog", unimplementedFunc),
+ /* 311 */ SyscallDesc("reboot", unimplementedFunc),
+ /* 312 */ SyscallDesc("clone", unimplementedFunc),
+ /* 313 */ SyscallDesc("uselib", unimplementedFunc),
+ /* 314 */ SyscallDesc("mlock", unimplementedFunc),
+ /* 315 */ SyscallDesc("munlock", unimplementedFunc),
+ /* 316 */ SyscallDesc("mlockall", unimplementedFunc),
+ /* 317 */ SyscallDesc("munlockall", unimplementedFunc),
+ /* 318 */ SyscallDesc("sysinfo", unimplementedFunc),
+ /* 319 */ SyscallDesc("_sysctl", unimplementedFunc),
+ /* 320 */ SyscallDesc("was sys_idle", unimplementedFunc),
+ /* 321 */ SyscallDesc("oldumount", unimplementedFunc),
+ /* 322 */ SyscallDesc("swapon", unimplementedFunc),
+ /* 323 */ SyscallDesc("times", ignoreFunc),
+ /* 324 */ SyscallDesc("personality", unimplementedFunc),
+ /* 325 */ SyscallDesc("setfsuid", unimplementedFunc),
+ /* 326 */ SyscallDesc("setfsgid", unimplementedFunc),
+ /* 327 */ SyscallDesc("ustat", unimplementedFunc),
+ /* 328 */ SyscallDesc("statfs", unimplementedFunc),
+ /* 329 */ SyscallDesc("fstatfs", unimplementedFunc),
+ /* 330 */ SyscallDesc("sched_setparam", unimplementedFunc),
+ /* 331 */ SyscallDesc("sched_getparam", unimplementedFunc),
+ /* 332 */ SyscallDesc("sched_setscheduler", unimplementedFunc),
+ /* 333 */ SyscallDesc("sched_getscheduler", unimplementedFunc),
+ /* 334 */ SyscallDesc("sched_yield", unimplementedFunc),
+ /* 335 */ SyscallDesc("sched_get_priority_max", unimplementedFunc),
+ /* 336 */ SyscallDesc("sched_get_priority_min", unimplementedFunc),
+ /* 337 */ SyscallDesc("sched_rr_get_interval", unimplementedFunc),
+ /* 338 */ SyscallDesc("afs_syscall", unimplementedFunc),
+ /* 339 */ SyscallDesc("uname", unameFunc),
+ /* 340 */ SyscallDesc("nanosleep", unimplementedFunc),
+ /* 341 */ SyscallDesc("mremap", unimplementedFunc),
+ /* 342 */ SyscallDesc("nfsservctl", unimplementedFunc),
+ /* 343 */ SyscallDesc("setresuid", unimplementedFunc),
+ /* 344 */ SyscallDesc("getresuid", unimplementedFunc),
+ /* 345 */ SyscallDesc("pciconfig_read", unimplementedFunc),
+ /* 346 */ SyscallDesc("pciconfig_write", unimplementedFunc),
+ /* 347 */ SyscallDesc("query_module", unimplementedFunc),
+ /* 348 */ SyscallDesc("prctl", unimplementedFunc),
+ /* 349 */ SyscallDesc("pread", unimplementedFunc),
+ /* 350 */ SyscallDesc("pwrite", unimplementedFunc),
+ /* 351 */ SyscallDesc("rt_sigreturn", unimplementedFunc),
+ /* 352 */ SyscallDesc("rt_sigaction", ignoreFunc),
+ /* 353 */ SyscallDesc("rt_sigprocmask", unimplementedFunc),
+ /* 354 */ SyscallDesc("rt_sigpending", unimplementedFunc),
+ /* 355 */ SyscallDesc("rt_sigtimedwait", unimplementedFunc),
+ /* 356 */ SyscallDesc("rt_sigqueueinfo", unimplementedFunc),
+ /* 357 */ SyscallDesc("rt_sigsuspend", unimplementedFunc),
+ /* 358 */ SyscallDesc("select", unimplementedFunc),
+ /* 359 */ SyscallDesc("gettimeofday", gettimeofdayFunc<AlphaLinux>),
+ /* 360 */ SyscallDesc("settimeofday", unimplementedFunc),
+ /* 361 */ SyscallDesc("getitimer", unimplementedFunc),
+ /* 362 */ SyscallDesc("setitimer", unimplementedFunc),
+ /* 363 */ SyscallDesc("utimes", utimesFunc<AlphaLinux>),
+ /* 364 */ SyscallDesc("getrusage", getrusageFunc<AlphaLinux>),
+ /* 365 */ SyscallDesc("wait4", unimplementedFunc),
+ /* 366 */ SyscallDesc("adjtimex", unimplementedFunc),
+ /* 367 */ SyscallDesc("getcwd", unimplementedFunc),
+ /* 368 */ SyscallDesc("capget", unimplementedFunc),
+ /* 369 */ SyscallDesc("capset", unimplementedFunc),
+ /* 370 */ SyscallDesc("sendfile", unimplementedFunc),
+ /* 371 */ SyscallDesc("setresgid", unimplementedFunc),
+ /* 372 */ SyscallDesc("getresgid", unimplementedFunc),
+ /* 373 */ SyscallDesc("dipc", unimplementedFunc),
+ /* 374 */ SyscallDesc("pivot_root", unimplementedFunc),
+ /* 375 */ SyscallDesc("mincore", unimplementedFunc),
+ /* 376 */ SyscallDesc("pciconfig_iobase", unimplementedFunc),
+ /* 377 */ SyscallDesc("getdents64", unimplementedFunc),
+ /* 378 */ SyscallDesc("gettid", unimplementedFunc),
+ /* 379 */ SyscallDesc("readahead", unimplementedFunc),
+ /* 380 */ SyscallDesc("security", unimplementedFunc),
+ /* 381 */ SyscallDesc("tkill", unimplementedFunc),
+ /* 382 */ SyscallDesc("setxattr", unimplementedFunc),
+ /* 383 */ SyscallDesc("lsetxattr", unimplementedFunc),
+ /* 384 */ SyscallDesc("fsetxattr", unimplementedFunc),
+ /* 385 */ SyscallDesc("getxattr", unimplementedFunc),
+ /* 386 */ SyscallDesc("lgetxattr", unimplementedFunc),
+ /* 387 */ SyscallDesc("fgetxattr", unimplementedFunc),
+ /* 388 */ SyscallDesc("listxattr", unimplementedFunc),
+ /* 389 */ SyscallDesc("llistxattr", unimplementedFunc),
+ /* 390 */ SyscallDesc("flistxattr", unimplementedFunc),
+ /* 391 */ SyscallDesc("removexattr", unimplementedFunc),
+ /* 392 */ SyscallDesc("lremovexattr", unimplementedFunc),
+ /* 393 */ SyscallDesc("fremovexattr", unimplementedFunc),
+ /* 394 */ SyscallDesc("futex", unimplementedFunc),
+ /* 395 */ SyscallDesc("sched_setaffinity", unimplementedFunc),
+ /* 396 */ SyscallDesc("sched_getaffinity", unimplementedFunc),
+ /* 397 */ SyscallDesc("tuxcall", unimplementedFunc),
+ /* 398 */ SyscallDesc("io_setup", unimplementedFunc),
+ /* 399 */ SyscallDesc("io_destroy", unimplementedFunc),
+ /* 400 */ SyscallDesc("io_getevents", unimplementedFunc),
+ /* 401 */ SyscallDesc("io_submit", unimplementedFunc),
+ /* 402 */ SyscallDesc("io_cancel", unimplementedFunc),
+ /* 403 */ SyscallDesc("unknown #403", unimplementedFunc),
+ /* 404 */ SyscallDesc("unknown #404", unimplementedFunc),
+ /* 405 */ SyscallDesc("exit_group", exitFunc), // exit all threads...
+ /* 406 */ SyscallDesc("lookup_dcookie", unimplementedFunc),
+ /* 407 */ SyscallDesc("sys_epoll_create", unimplementedFunc),
+ /* 408 */ SyscallDesc("sys_epoll_ctl", unimplementedFunc),
+ /* 409 */ SyscallDesc("sys_epoll_wait", unimplementedFunc),
+ /* 410 */ SyscallDesc("remap_file_pages", unimplementedFunc),
+ /* 411 */ SyscallDesc("set_tid_address", unimplementedFunc),
+ /* 412 */ SyscallDesc("restart_syscall", unimplementedFunc),
+ /* 413 */ SyscallDesc("fadvise64", unimplementedFunc),
+ /* 414 */ SyscallDesc("timer_create", unimplementedFunc),
+ /* 415 */ SyscallDesc("timer_settime", unimplementedFunc),
+ /* 416 */ SyscallDesc("timer_gettime", unimplementedFunc),
+ /* 417 */ SyscallDesc("timer_getoverrun", unimplementedFunc),
+ /* 418 */ SyscallDesc("timer_delete", unimplementedFunc),
+ /* 419 */ SyscallDesc("clock_settime", unimplementedFunc),
+ /* 420 */ SyscallDesc("clock_gettime", unimplementedFunc),
+ /* 421 */ SyscallDesc("clock_getres", unimplementedFunc),
+ /* 422 */ SyscallDesc("clock_nanosleep", unimplementedFunc),
+ /* 423 */ SyscallDesc("semtimedop", unimplementedFunc),
+ /* 424 */ SyscallDesc("tgkill", unimplementedFunc),
+ /* 425 */ SyscallDesc("stat64", unimplementedFunc),
+ /* 426 */ SyscallDesc("lstat64", lstat64Func<AlphaLinux>),
+ /* 427 */ SyscallDesc("fstat64", fstat64Func<AlphaLinux>),
+ /* 428 */ SyscallDesc("vserver", unimplementedFunc),
+ /* 429 */ SyscallDesc("mbind", unimplementedFunc),
+ /* 430 */ SyscallDesc("get_mempolicy", unimplementedFunc),
+ /* 431 */ SyscallDesc("set_mempolicy", unimplementedFunc),
+ /* 432 */ SyscallDesc("mq_open", unimplementedFunc),
+ /* 433 */ SyscallDesc("mq_unlink", unimplementedFunc),
+ /* 434 */ SyscallDesc("mq_timedsend", unimplementedFunc),
+ /* 435 */ SyscallDesc("mq_timedreceive", unimplementedFunc),
+ /* 436 */ SyscallDesc("mq_notify", unimplementedFunc),
+ /* 437 */ SyscallDesc("mq_getsetattr", unimplementedFunc),
+ /* 438 */ SyscallDesc("waitid", unimplementedFunc),
+ /* 439 */ SyscallDesc("add_key", unimplementedFunc),
+ /* 440 */ SyscallDesc("request_key", unimplementedFunc),
+ /* 441 */ SyscallDesc("keyctl", unimplementedFunc)
+};
+
+AlphaLinuxProcess::AlphaLinuxProcess(const std::string &name,
+ ObjectFile *objFile,
+ System *system,
+ int stdin_fd,
+ int stdout_fd,
+ int stderr_fd,
+ std::vector<std::string> &argv,
+ std::vector<std::string> &envp)
+ : AlphaLiveProcess(name, objFile, system, stdin_fd, stdout_fd,
+ stderr_fd, argv, envp),
+ Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc))
+{
+ //init_regs->intRegFile[0] = 0;
+}
+
+
+
+SyscallDesc*
+AlphaLinuxProcess::getDesc(int callnum)
+{
+ if (callnum < 0 || callnum > Num_Syscall_Descs)
+ return NULL;
+ return &syscallDescs[callnum];
+}
diff --git a/src/arch/alpha/linux/process.hh b/src/arch/alpha/linux/process.hh
new file mode 100644
index 000000000..2e0566665
--- /dev/null
+++ b/src/arch/alpha/linux/process.hh
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2003-2004 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ALPHA_LINUX_PROCESS_HH__
+#define __ALPHA_LINUX_PROCESS_HH__
+
+#include "arch/alpha/process.hh"
+
+namespace AlphaISA {
+
+/// A process with emulated Alpha/Linux syscalls.
+class AlphaLinuxProcess : public AlphaLiveProcess
+{
+ public:
+ /// Constructor.
+ AlphaLinuxProcess(const std::string &name,
+ ObjectFile *objFile,
+ System *system,
+ int stdin_fd, int stdout_fd, int stderr_fd,
+ std::vector<std::string> &argv,
+ std::vector<std::string> &envp);
+
+ virtual SyscallDesc* getDesc(int callnum);
+
+ /// The target system's hostname.
+ static const char *hostname;
+
+ /// Array of syscall descriptors, indexed by call number.
+ static SyscallDesc syscallDescs[];
+
+ const int Num_Syscall_Descs;
+};
+
+} // namespace AlphaISA
+#endif // __ALPHA_LINUX_PROCESS_HH__
diff --git a/src/arch/alpha/linux/system.cc b/src/arch/alpha/linux/system.cc
new file mode 100644
index 000000000..cdb96096c
--- /dev/null
+++ b/src/arch/alpha/linux/system.cc
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * This code loads the linux kernel, console, pal and patches certain
+ * functions. The symbol tables are loaded so that traces can show
+ * the executing function and we can skip functions. Various delay
+ * loops are skipped and their final values manually computed to speed
+ * up boot time.
+ */
+
+#include "arch/arguments.hh"
+#include "arch/vtophys.hh"
+#include "arch/alpha/linux/system.hh"
+#include "arch/alpha/linux/threadinfo.hh"
+#include "arch/alpha/system.hh"
+#include "base/loader/symtab.hh"
+#include "cpu/exec_context.hh"
+#include "cpu/base.hh"
+#include "dev/platform.hh"
+#include "kern/linux/printk.hh"
+#include "kern/linux/events.hh"
+#include "mem/physical.hh"
+#include "mem/port.hh"
+#include "sim/builder.hh"
+#include "sim/byteswap.hh"
+
+using namespace std;
+using namespace AlphaISA;
+using namespace Linux;
+
+LinuxAlphaSystem::LinuxAlphaSystem(Params *p)
+ : AlphaSystem(p)
+{
+ Addr addr = 0;
+
+ /**
+ * The symbol swapper_pg_dir marks the beginning of the kernel and
+ * the location of bootloader passed arguments
+ */
+ if (!kernelSymtab->findAddress("swapper_pg_dir", KernelStart)) {
+ panic("Could not determine start location of kernel");
+ }
+
+ /**
+ * Since we aren't using a bootloader, we have to copy the
+ * kernel arguments directly into the kernel's memory.
+ */
+ virtPort.writeBlob(CommandLine(), (uint8_t*)params()->boot_osflags.c_str(),
+ params()->boot_osflags.length()+1);
+
+ /**
+ * find the address of the est_cycle_freq variable and insert it
+ * so we don't through the lengthly process of trying to
+ * calculated it by using the PIT, RTC, etc.
+ */
+ if (kernelSymtab->findAddress("est_cycle_freq", addr))
+ virtPort.write(addr, (uint64_t)(Clock::Frequency /
+ p->boot_cpu_frequency));
+
+
+ /**
+ * EV5 only supports 127 ASNs so we are going to tell the kernel that the
+ * paritiuclar EV6 we have only supports 127 asns.
+ * @todo At some point we should change ev5.hh and the palcode to support
+ * 255 ASNs.
+ */
+ if (kernelSymtab->findAddress("dp264_mv", addr))
+ virtPort.write(addr + 0x18, LittleEndianGuest::htog((uint32_t)127));
+ else
+ panic("could not find dp264_mv\n");
+
+#ifndef NDEBUG
+ kernelPanicEvent = addKernelFuncEvent<BreakPCEvent>("panic");
+ if (!kernelPanicEvent)
+ panic("could not find kernel symbol \'panic\'");
+
+#if 0
+ kernelDieEvent = addKernelFuncEvent<BreakPCEvent>("die_if_kernel");
+ if (!kernelDieEvent)
+ panic("could not find kernel symbol \'die_if_kernel\'");
+#endif
+
+#endif
+
+ /**
+ * Any time ide_delay_50ms, calibarte_delay or
+ * determine_cpu_caches is called just skip the
+ * function. Currently determine_cpu_caches only is used put
+ * information in proc, however if that changes in the future we
+ * will have to fill in the cache size variables appropriately.
+ */
+
+ skipIdeDelay50msEvent =
+ addKernelFuncEvent<SkipFuncEvent>("ide_delay_50ms");
+ skipDelayLoopEvent =
+ addKernelFuncEvent<SkipDelayLoopEvent>("calibrate_delay");
+ skipCacheProbeEvent =
+ addKernelFuncEvent<SkipFuncEvent>("determine_cpu_caches");
+ debugPrintkEvent = addKernelFuncEvent<DebugPrintkEvent>("dprintk");
+ idleStartEvent = addKernelFuncEvent<IdleStartEvent>("cpu_idle");
+
+ if (kernelSymtab->findAddress("alpha_switch_to", addr) && DTRACE(Thread)) {
+ printThreadEvent = new PrintThreadInfo(&pcEventQueue, "threadinfo",
+ addr + sizeof(MachInst) * 6);
+ } else {
+ printThreadEvent = NULL;
+ }
+
+ if (params()->bin_int) {
+ intStartEvent = addPalFuncEvent<InterruptStartEvent>("sys_int_21");
+ if (!intStartEvent)
+ panic("could not find symbol: sys_int_21\n");
+
+ intEndEvent = addPalFuncEvent<InterruptEndEvent>("rti_to_kern");
+ if (!intEndEvent)
+ panic("could not find symbol: rti_to_kern\n");
+
+ intEndEvent2 = addPalFuncEvent<InterruptEndEvent>("rti_to_user");
+ if (!intEndEvent2)
+ panic("could not find symbol: rti_to_user\n");
+
+ intEndEvent3 = addKernelFuncEvent<InterruptEndEvent>("do_softirq");
+ if (!intEndEvent3)
+ panic("could not find symbol: do_softirq\n");
+ }
+}
+
+LinuxAlphaSystem::~LinuxAlphaSystem()
+{
+#ifndef NDEBUG
+ delete kernelPanicEvent;
+#endif
+ delete skipIdeDelay50msEvent;
+ delete skipDelayLoopEvent;
+ delete skipCacheProbeEvent;
+ delete debugPrintkEvent;
+ delete idleStartEvent;
+ delete printThreadEvent;
+ delete intStartEvent;
+ delete intEndEvent;
+ delete intEndEvent2;
+}
+
+
+void
+LinuxAlphaSystem::setDelayLoop(ExecContext *xc)
+{
+ Addr addr = 0;
+ if (kernelSymtab->findAddress("loops_per_jiffy", addr)) {
+ Tick cpuFreq = xc->getCpuPtr()->frequency();
+ Tick intrFreq = platform->intrFrequency();
+ xc->getVirtPort(xc)->write(addr,
+ (uint32_t)((cpuFreq / intrFreq) * 0.9988));
+ }
+}
+
+
+void
+LinuxAlphaSystem::SkipDelayLoopEvent::process(ExecContext *xc)
+{
+ SkipFuncEvent::process(xc);
+ // calculate and set loops_per_jiffy
+ ((LinuxAlphaSystem *)xc->getSystemPtr())->setDelayLoop(xc);
+}
+
+void
+LinuxAlphaSystem::PrintThreadInfo::process(ExecContext *xc)
+{
+ Linux::ThreadInfo ti(xc);
+
+ DPRINTF(Thread, "Currently Executing Thread %s, pid %d, started at: %d\n",
+ ti.curTaskName(), ti.curTaskPID(), ti.curTaskStart());
+}
+
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(LinuxAlphaSystem)
+
+ Param<Tick> boot_cpu_frequency;
+ SimObjectParam<PhysicalMemory *> physmem;
+
+ Param<string> kernel;
+ Param<string> console;
+ Param<string> pal;
+
+ Param<string> boot_osflags;
+ Param<string> readfile;
+ Param<unsigned int> init_param;
+
+ Param<uint64_t> system_type;
+ Param<uint64_t> system_rev;
+
+ Param<bool> bin;
+ VectorParam<string> binned_fns;
+ Param<bool> bin_int;
+
+END_DECLARE_SIM_OBJECT_PARAMS(LinuxAlphaSystem)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(LinuxAlphaSystem)
+
+ INIT_PARAM(boot_cpu_frequency, "Frequency of the boot CPU"),
+ INIT_PARAM(physmem, "phsyical memory"),
+ INIT_PARAM(kernel, "file that contains the kernel code"),
+ INIT_PARAM(console, "file that contains the console code"),
+ INIT_PARAM(pal, "file that contains palcode"),
+ INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot",
+ "a"),
+ INIT_PARAM_DFLT(readfile, "file to read startup script from", ""),
+ INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0),
+ INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 34),
+ INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10),
+ INIT_PARAM_DFLT(bin, "is this system to be binned", false),
+ INIT_PARAM(binned_fns, "functions to be broken down and binned"),
+ INIT_PARAM_DFLT(bin_int, "is interrupt code binned seperately?", true)
+
+END_INIT_SIM_OBJECT_PARAMS(LinuxAlphaSystem)
+
+CREATE_SIM_OBJECT(LinuxAlphaSystem)
+{
+ AlphaSystem::Params *p = new AlphaSystem::Params;
+ p->name = getInstanceName();
+ p->boot_cpu_frequency = boot_cpu_frequency;
+ p->physmem = physmem;
+ p->kernel_path = kernel;
+ p->console_path = console;
+ p->palcode = pal;
+ p->boot_osflags = boot_osflags;
+ p->init_param = init_param;
+ p->readfile = readfile;
+ p->system_type = system_type;
+ p->system_rev = system_rev;
+ p->bin = bin;
+ p->binned_fns = binned_fns;
+ p->bin_int = bin_int;
+ return new LinuxAlphaSystem(p);
+}
+
+REGISTER_SIM_OBJECT("LinuxAlphaSystem", LinuxAlphaSystem)
+
diff --git a/src/arch/alpha/linux/system.hh b/src/arch/alpha/linux/system.hh
new file mode 100644
index 000000000..0c1fb037e
--- /dev/null
+++ b/src/arch/alpha/linux/system.hh
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2004-2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ARCH_ALPHA_LINUX_SYSTEM_HH__
+#define __ARCH_ALPHA_LINUX_SYSTEM_HH__
+
+class ExecContext;
+
+class BreakPCEvent;
+class IdleStartEvent;
+
+#include "arch/alpha/system.hh"
+#include "kern/linux/events.hh"
+
+using namespace AlphaISA;
+using namespace Linux;
+
+/**
+ * This class contains linux specific system code (Loading, Events, Binning).
+ * It points to objects that are the system binaries to load and patches them
+ * appropriately to work in simulator.
+ */
+class LinuxAlphaSystem : public AlphaSystem
+{
+ private:
+ class SkipDelayLoopEvent : public SkipFuncEvent
+ {
+ public:
+ SkipDelayLoopEvent(PCEventQueue *q, const std::string &desc, Addr addr)
+ : SkipFuncEvent(q, desc, addr) {}
+ virtual void process(ExecContext *xc);
+ };
+
+ class PrintThreadInfo : public PCEvent
+ {
+ public:
+ PrintThreadInfo(PCEventQueue *q, const std::string &desc, Addr addr)
+ : PCEvent(q, desc, addr) {}
+ virtual void process(ExecContext *xc);
+ };
+
+
+ /**
+ * Addresses defining where the kernel bootloader places various
+ * elements. Details found in include/asm-alpha/system.h
+ */
+ Addr KernelStart; // Lookup the symbol swapper_pg_dir
+
+ public:
+ Addr InitStack() const { return KernelStart + 0x02000; }
+ Addr EmptyPGT() const { return KernelStart + 0x04000; }
+ Addr EmptyPGE() const { return KernelStart + 0x08000; }
+ Addr ZeroPGE() const { return KernelStart + 0x0A000; }
+ Addr StartAddr() const { return KernelStart + 0x10000; }
+
+ Addr Param() const { return ZeroPGE() + 0x0; }
+ Addr CommandLine() const { return Param() + 0x0; }
+ Addr InitrdStart() const { return Param() + 0x100; }
+ Addr InitrdSize() const { return Param() + 0x108; }
+ static const int CommandLineSize = 256;
+
+ private:
+#ifndef NDEBUG
+ /** Event to halt the simulator if the kernel calls panic() */
+ BreakPCEvent *kernelPanicEvent;
+
+ /** Event to halt the simulator if the kernel calls die_if_kernel */
+ BreakPCEvent *kernelDieEvent;
+#endif
+
+ /**
+ * Event to skip determine_cpu_caches() because we don't support
+ * the IPRs that the code can access to figure out cache sizes
+ */
+ SkipFuncEvent *skipCacheProbeEvent;
+
+ /** PC based event to skip the ide_delay_50ms() call */
+ SkipFuncEvent *skipIdeDelay50msEvent;
+
+ /**
+ * PC based event to skip the dprink() call and emulate its
+ * functionality
+ */
+ DebugPrintkEvent *debugPrintkEvent;
+
+ /**
+ * Skip calculate_delay_loop() rather than waiting for this to be
+ * calculated
+ */
+ SkipDelayLoopEvent *skipDelayLoopEvent;
+
+ /**
+ * Event to print information about thread switches if the trace flag
+ * Thread is set
+ */
+ PrintThreadInfo *printThreadEvent;
+
+ /**
+ * Event to bin Interrupts seperately from kernel code
+ */
+ InterruptStartEvent *intStartEvent;
+
+ /**
+ * Event to bin Interrupts seperately from kernel code
+ */
+ InterruptEndEvent *intEndEvent;
+ InterruptEndEvent *intEndEvent2;
+ InterruptEndEvent *intEndEvent3;
+
+ /** Grab the PCBB of the idle process when it starts */
+ IdleStartEvent *idleStartEvent;
+
+ public:
+ LinuxAlphaSystem(Params *p);
+ ~LinuxAlphaSystem();
+
+ void setDelayLoop(ExecContext *xc);
+};
+
+#endif // __ARCH_ALPHA_LINUX_SYSTEM_HH__
diff --git a/src/arch/alpha/linux/thread_info.hh b/src/arch/alpha/linux/thread_info.hh
new file mode 100644
index 000000000..88791b00d
--- /dev/null
+++ b/src/arch/alpha/linux/thread_info.hh
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ARCH_ALPHA_LINUX_THREAD_INFO_H__
+#define __ARCH_ALPHA_LINUX_THREAD_INFO_H__
+
+#include "arch/alpha/linux/hwrpb.hh"
+
+namespace Linux {
+ struct thread_info {
+ struct pcb_struct pcb;
+ Addr_a task;
+ };
+}
+
+#endif // __ARCH_ALPHA_LINUX_THREAD_INFO_H__
diff --git a/src/arch/alpha/linux/threadinfo.hh b/src/arch/alpha/linux/threadinfo.hh
new file mode 100644
index 000000000..8f03c9314
--- /dev/null
+++ b/src/arch/alpha/linux/threadinfo.hh
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2004 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ARCH_ALPHA_LINUX_LINUX_TREADNIFO_HH__
+#define __ARCH_ALPHA_LINUX_LINUX_TREADNIFO_HH__
+
+#include "arch/alpha/linux/thread_info.hh"
+#include "cpu/exec_context.hh"
+#include "kern/linux/sched.hh"
+#include "sim/vptr.hh"
+
+namespace Linux {
+
+class ThreadInfo
+{
+ private:
+ ExecContext *xc;
+
+ public:
+ ThreadInfo(ExecContext *exec) : xc(exec) {}
+ ~ThreadInfo() {}
+
+ inline VPtr<thread_info>
+ curThreadInfo()
+ {
+ Addr current;
+
+ /* Each kernel stack is only 2 pages, the start of which is the
+ * thread_info struct. So we can get the address by masking off
+ * the lower 14 bits.
+ */
+ current = xc->readIntReg(TheISA::StackPointerReg) & ~0x3fff;
+ return VPtr<thread_info>(xc, current);
+ }
+
+ inline VPtr<task_struct>
+ curTaskInfo()
+ {
+ Addr task = curThreadInfo()->task;
+ return VPtr<task_struct>(xc, task);
+ }
+
+ std::string
+ curTaskName()
+ {
+ return curTaskInfo()->name;
+ }
+
+ int32_t
+ curTaskPID()
+ {
+ return curTaskInfo()->pid;
+ }
+
+ uint64_t
+ curTaskStart()
+ {
+ return curTaskInfo()->start;
+ }
+};
+
+/* namespace Linux */ }
+
+#endif // __ARCH_ALPHA_LINUX_LINUX_THREADINFO_HH__
diff --git a/src/arch/alpha/osfpal.cc b/src/arch/alpha/osfpal.cc
new file mode 100644
index 000000000..a48bd28d9
--- /dev/null
+++ b/src/arch/alpha/osfpal.cc
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "arch/alpha/osfpal.hh"
+
+namespace {
+ const char *strings[PAL::NumCodes] = {
+ // Priviledged PAL instructions
+ "halt", // 0x00
+ "cflush", // 0x01
+ "draina", // 0x02
+ 0, // 0x03
+ 0, // 0x04
+ 0, // 0x05
+ 0, // 0x06
+ 0, // 0x07
+ 0, // 0x08
+ "cserve", // 0x09
+ "swppal", // 0x0a
+ 0, // 0x0b
+ 0, // 0x0c
+ "wripir", // 0x0d
+ 0, // 0x0e
+ 0, // 0x0f
+ "rdmces", // 0x10
+ "wrmces", // 0x11
+ 0, // 0x12
+ 0, // 0x13
+ 0, // 0x14
+ 0, // 0x15
+ 0, // 0x16
+ 0, // 0x17
+ 0, // 0x18
+ 0, // 0x19
+ 0, // 0x1a
+ 0, // 0x1b
+ 0, // 0x1c
+ 0, // 0x1d
+ 0, // 0x1e
+ 0, // 0x1f
+ 0, // 0x20
+ 0, // 0x21
+ 0, // 0x22
+ 0, // 0x23
+ 0, // 0x24
+ 0, // 0x25
+ 0, // 0x26
+ 0, // 0x27
+ 0, // 0x28
+ 0, // 0x29
+ 0, // 0x2a
+ "wrfen", // 0x2b
+ 0, // 0x2c
+ "wrvptptr", // 0x2d
+ 0, // 0x2e
+ 0, // 0x2f
+ "swpctx", // 0x30
+ "wrval", // 0x31
+ "rdval", // 0x32
+ "tbi", // 0x33
+ "wrent", // 0x34
+ "swpipl", // 0x35
+ "rdps", // 0x36
+ "wrkgp", // 0x37
+ "wrusp", // 0x38
+ "wrperfmon", // 0x39
+ "rdusp", // 0x3a
+ 0, // 0x3b
+ "whami", // 0x3c
+ "retsys", // 0x3d
+ "wtint", // 0x3e
+ "rti", // 0x3f
+ 0, // 0x40
+ 0, // 0x41
+ 0, // 0x42
+ 0, // 0x43
+ 0, // 0x44
+ 0, // 0x45
+ 0, // 0x46
+ 0, // 0x47
+ 0, // 0x48
+ 0, // 0x49
+ 0, // 0x4a
+ 0, // 0x4b
+ 0, // 0x4c
+ 0, // 0x4d
+ 0, // 0x4e
+ 0, // 0x4f
+ 0, // 0x50
+ 0, // 0x51
+ 0, // 0x52
+ 0, // 0x53
+ 0, // 0x54
+ 0, // 0x55
+ 0, // 0x56
+ 0, // 0x57
+ 0, // 0x58
+ 0, // 0x59
+ 0, // 0x5a
+ 0, // 0x5b
+ 0, // 0x5c
+ 0, // 0x5d
+ 0, // 0x5e
+ 0, // 0x5f
+ 0, // 0x60
+ 0, // 0x61
+ 0, // 0x62
+ 0, // 0x63
+ 0, // 0x64
+ 0, // 0x65
+ 0, // 0x66
+ 0, // 0x67
+ 0, // 0x68
+ 0, // 0x69
+ 0, // 0x6a
+ 0, // 0x6b
+ 0, // 0x6c
+ 0, // 0x6d
+ 0, // 0x6e
+ 0, // 0x6f
+ 0, // 0x70
+ 0, // 0x71
+ 0, // 0x72
+ 0, // 0x73
+ 0, // 0x74
+ 0, // 0x75
+ 0, // 0x76
+ 0, // 0x77
+ 0, // 0x78
+ 0, // 0x79
+ 0, // 0x7a
+ 0, // 0x7b
+ 0, // 0x7c
+ 0, // 0x7d
+ 0, // 0x7e
+ 0, // 0x7f
+
+ // Unpriviledged PAL instructions
+ "bpt", // 0x80
+ "bugchk", // 0x81
+ 0, // 0x82
+ "callsys", // 0x83
+ 0, // 0x84
+ 0, // 0x85
+ "imb", // 0x86
+ 0, // 0x87
+ 0, // 0x88
+ 0, // 0x89
+ 0, // 0x8a
+ 0, // 0x8b
+ 0, // 0x8c
+ 0, // 0x8d
+ 0, // 0x8e
+ 0, // 0x8f
+ 0, // 0x90
+ 0, // 0x91
+ "urti", // 0x92
+ 0, // 0x93
+ 0, // 0x94
+ 0, // 0x95
+ 0, // 0x96
+ 0, // 0x97
+ 0, // 0x98
+ 0, // 0x99
+ 0, // 0x9a
+ 0, // 0x9b
+ 0, // 0x9c
+ 0, // 0x9d
+ "rdunique", // 0x9e
+ "wrunique", // 0x9f
+ 0, // 0xa0
+ 0, // 0xa1
+ 0, // 0xa2
+ 0, // 0xa3
+ 0, // 0xa4
+ 0, // 0xa5
+ 0, // 0xa6
+ 0, // 0xa7
+ 0, // 0xa8
+ 0, // 0xa9
+ "gentrap", // 0xaa
+ 0, // 0xab
+ 0, // 0xac
+ 0, // 0xad
+ "clrfen", // 0xae
+ 0, // 0xaf
+ 0, // 0xb0
+ 0, // 0xb1
+ 0, // 0xb2
+ 0, // 0xb3
+ 0, // 0xb4
+ 0, // 0xb5
+ 0, // 0xb6
+ 0, // 0xb7
+ 0, // 0xb8
+ 0, // 0xb9
+ 0, // 0xba
+ 0, // 0xbb
+ 0, // 0xbc
+ 0, // 0xbd
+ "nphalt", // 0xbe
+ "copypal", // 0xbf
+#if 0
+ 0, // 0xc0
+ 0, // 0xc1
+ 0, // 0xc2
+ 0, // 0xc3
+ 0, // 0xc4
+ 0, // 0xc5
+ 0, // 0xc6
+ 0, // 0xc7
+ 0, // 0xc8
+ 0, // 0xc9
+ 0, // 0xca
+ 0, // 0xcb
+ 0, // 0xcc
+ 0, // 0xcd
+ 0, // 0xce
+ 0, // 0xcf
+ 0, // 0xd0
+ 0, // 0xd1
+ 0, // 0xd2
+ 0, // 0xd3
+ 0, // 0xd4
+ 0, // 0xd5
+ 0, // 0xd6
+ 0, // 0xd7
+ 0, // 0xd8
+ 0, // 0xd9
+ 0, // 0xda
+ 0, // 0xdb
+ 0, // 0xdc
+ 0, // 0xdd
+ 0, // 0xde
+ 0, // 0xdf
+ 0, // 0xe0
+ 0, // 0xe1
+ 0, // 0xe2
+ 0, // 0xe3
+ 0, // 0xe4
+ 0, // 0xe5
+ 0, // 0xe6
+ 0, // 0xe7
+ 0, // 0xe8
+ 0, // 0xe9
+ 0, // 0xea
+ 0, // 0xeb
+ 0, // 0xec
+ 0, // 0xed
+ 0, // 0xee
+ 0, // 0xef
+ 0, // 0xf0
+ 0, // 0xf1
+ 0, // 0xf2
+ 0, // 0xf3
+ 0, // 0xf4
+ 0, // 0xf5
+ 0, // 0xf6
+ 0, // 0xf7
+ 0, // 0xf8
+ 0, // 0xf9
+ 0, // 0xfa
+ 0, // 0xfb
+ 0, // 0xfc
+ 0, // 0xfd
+ 0, // 0xfe
+ 0 // 0xff
+#endif
+ };
+}
+
+const char *
+PAL::name(int index)
+{
+ if (index > NumCodes || index < 0)
+ return 0;
+
+ return strings[index];
+}
diff --git a/src/arch/alpha/osfpal.hh b/src/arch/alpha/osfpal.hh
new file mode 100644
index 000000000..f46d2bce1
--- /dev/null
+++ b/src/arch/alpha/osfpal.hh
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __OSFPAL_HH__
+#define __OSFPAL_HH__
+
+struct PAL
+{
+ enum {
+ // Privileged PAL functions
+ halt = 0x00,
+ cflush = 0x01,
+ draina = 0x02,
+ cserve = 0x09,
+ swppal = 0x0a,
+ wripir = 0x0d,
+ rdmces = 0x10,
+ wrmces = 0x11,
+ wrfen = 0x2b,
+ wrvptptr = 0x2d,
+ swpctx = 0x30,
+ wrval = 0x31,
+ rdval = 0x32,
+ tbi = 0x33,
+ wrent = 0x34,
+ swpipl = 0x35,
+ rdps = 0x36,
+ wrkgp = 0x37,
+ wrusp = 0x38,
+ wrperfmon = 0x39,
+ rdusp = 0x3a,
+ whami = 0x3c,
+ retsys = 0x3d,
+ wtint = 0x3e,
+ rti = 0x3f,
+
+ // unprivileged pal functions
+ bpt = 0x80,
+ bugchk = 0x81,
+ callsys = 0x83,
+ imb = 0x86,
+ urti = 0x92,
+ rdunique = 0x9e,
+ wrunique = 0x9f,
+ gentrap = 0xaa,
+ clrfen = 0xae,
+ nphalt = 0xbe,
+ copypal = 0xbf,
+ NumCodes
+ };
+
+ static const char *name(int index);
+};
+
+#endif // __OSFPAL_HH__
diff --git a/src/arch/alpha/process.cc b/src/arch/alpha/process.cc
new file mode 100644
index 000000000..25ee79692
--- /dev/null
+++ b/src/arch/alpha/process.cc
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2003-2004 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "arch/alpha/constants.hh"
+#include "arch/alpha/process.hh"
+#include "arch/alpha/linux/process.hh"
+#include "arch/alpha/tru64/process.hh"
+#include "base/loader/object_file.hh"
+#include "base/misc.hh"
+#include "cpu/exec_context.hh"
+#include "sim/builder.hh"
+#include "sim/system.hh"
+
+
+using namespace AlphaISA;
+using namespace std;
+
+AlphaLiveProcess *
+AlphaLiveProcess::create(const std::string &nm, System *system, int stdin_fd,
+ int stdout_fd, int stderr_fd, std::string executable,
+ std::vector<std::string> &argv, std::vector<std::string> &envp)
+{
+ AlphaLiveProcess *process = NULL;
+
+ ObjectFile *objFile = createObjectFile(executable);
+ if (objFile == NULL) {
+ fatal("Can't load object file %s", executable);
+ }
+
+
+ if (objFile->getArch() != ObjectFile::Alpha)
+ fatal("Object file does not match architecture.");
+ switch (objFile->getOpSys()) {
+ case ObjectFile::Tru64:
+ process = new AlphaTru64Process(nm, objFile, system,
+ stdin_fd, stdout_fd, stderr_fd,
+ argv, envp);
+ break;
+
+ case ObjectFile::Linux:
+ process = new AlphaLinuxProcess(nm, objFile, system,
+ stdin_fd, stdout_fd, stderr_fd,
+ argv, envp);
+ break;
+
+ default:
+ fatal("Unknown/unsupported operating system.");
+ }
+
+ if (process == NULL)
+ fatal("Unknown error creating process object.");
+ return process;
+}
+
+AlphaLiveProcess::AlphaLiveProcess(const std::string &nm, ObjectFile *objFile,
+ System *_system, int stdin_fd, int stdout_fd, int stderr_fd,
+ std::vector<std::string> &argv, std::vector<std::string> &envp)
+ : LiveProcess(nm, objFile, _system, stdin_fd, stdout_fd, stderr_fd,
+ argv, envp)
+{
+ brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize();
+ brk_point = roundUp(brk_point, VMPageSize);
+
+ // Set up stack. On Alpha, stack goes below text section. This
+ // code should get moved to some architecture-specific spot.
+ stack_base = objFile->textBase() - (409600+4096);
+
+ // Set up region for mmaps. Tru64 seems to start just above 0 and
+ // grow up from there.
+ mmap_start = mmap_end = 0x10000;
+
+ // Set pointer for next thread stack. Reserve 8M for main stack.
+ next_thread_stack_base = stack_base - (8 * 1024 * 1024);
+
+}
+
+void
+AlphaLiveProcess::startup()
+{
+ argsInit(MachineBytes, VMPageSize);
+
+ execContexts[0]->setIntReg(GlobalPointerReg, objFile->globalPointer());
+}
+
+
+
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaLiveProcess)
+
+ VectorParam<string> cmd;
+ Param<string> executable;
+ Param<string> input;
+ Param<string> output;
+ VectorParam<string> env;
+ SimObjectParam<System *> system;
+
+END_DECLARE_SIM_OBJECT_PARAMS(AlphaLiveProcess)
+
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaLiveProcess)
+
+ INIT_PARAM(cmd, "command line (executable plus arguments)"),
+ INIT_PARAM(executable, "executable (overrides cmd[0] if set)"),
+ INIT_PARAM(input, "filename for stdin (dflt: use sim stdin)"),
+ INIT_PARAM(output, "filename for stdout/stderr (dflt: use sim stdout)"),
+ INIT_PARAM(env, "environment settings"),
+ INIT_PARAM(system, "system")
+
+END_INIT_SIM_OBJECT_PARAMS(AlphaLiveProcess)
+
+
+CREATE_SIM_OBJECT(AlphaLiveProcess)
+{
+ string in = input;
+ string out = output;
+
+ // initialize file descriptors to default: same as simulator
+ int stdin_fd, stdout_fd, stderr_fd;
+
+ if (in == "stdin" || in == "cin")
+ stdin_fd = STDIN_FILENO;
+ else
+ stdin_fd = Process::openInputFile(input);
+
+ if (out == "stdout" || out == "cout")
+ stdout_fd = STDOUT_FILENO;
+ else if (out == "stderr" || out == "cerr")
+ stdout_fd = STDERR_FILENO;
+ else
+ stdout_fd = Process::openOutputFile(out);
+
+ stderr_fd = (stdout_fd != STDOUT_FILENO) ? stdout_fd : STDERR_FILENO;
+
+ return AlphaLiveProcess::create(getInstanceName(), system,
+ stdin_fd, stdout_fd, stderr_fd,
+ (string)executable == "" ? cmd[0] : executable,
+ cmd, env);
+}
+
+
+REGISTER_SIM_OBJECT("AlphaLiveProcess", AlphaLiveProcess)
+
diff --git a/src/arch/alpha/process.hh b/src/arch/alpha/process.hh
new file mode 100644
index 000000000..d97b36e2d
--- /dev/null
+++ b/src/arch/alpha/process.hh
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2003-2004 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ALPHA_PROCESS_HH__
+#define __ALPHA_PROCESS_HH__
+
+#include <string>
+#include <vector>
+#include "sim/process.hh"
+
+class ObjectFile;
+class System;
+
+
+class AlphaLiveProcess : public LiveProcess
+{
+ protected:
+ AlphaLiveProcess(const std::string &nm, ObjectFile *objFile,
+ System *_system, int stdin_fd, int stdout_fd, int stderr_fd,
+ std::vector<std::string> &argv,
+ std::vector<std::string> &envp);
+
+ void startup();
+
+ public:
+ // this function is used to create the LiveProcess object, since
+ // we can't tell which subclass of LiveProcess to use until we
+ // open and look at the object file.
+ static AlphaLiveProcess *create(const std::string &nm,
+ System *_system,
+ int stdin_fd, int stdout_fd, int stderr_fd,
+ std::string executable,
+ std::vector<std::string> &argv,
+ std::vector<std::string> &envp);
+
+};
+
+
+#endif // __ALPHA_PROCESS_HH__
diff --git a/src/arch/alpha/regfile.hh b/src/arch/alpha/regfile.hh
new file mode 100644
index 000000000..af01b7829
--- /dev/null
+++ b/src/arch/alpha/regfile.hh
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ARCH_ALPHA_REGFILE_HH__
+#define __ARCH_ALPHA_REGFILE_HH__
+
+#include "arch/alpha/types.hh"
+#include "arch/alpha/constants.hh"
+#include "sim/faults.hh"
+
+class Checkpoint;
+class ExecContext;
+
+namespace AlphaISA
+{
+ class IntRegFile
+ {
+ protected:
+ IntReg regs[NumIntRegs];
+
+ public:
+
+ IntReg readReg(int intReg)
+ {
+ return regs[intReg];
+ }
+
+ Fault setReg(int intReg, const IntReg &val)
+ {
+ regs[intReg] = val;
+ return NoFault;
+ }
+
+ void serialize(std::ostream &os);
+
+ void unserialize(Checkpoint *cp, const std::string &section);
+
+ };
+
+ class FloatRegFile
+ {
+ public:
+
+ union {
+ uint64_t q[NumFloatRegs]; // integer qword view
+ double d[NumFloatRegs]; // double-precision floating point view
+ };
+
+ void serialize(std::ostream &os);
+
+ void unserialize(Checkpoint *cp, const std::string &section);
+
+ };
+
+ class MiscRegFile {
+ protected:
+ uint64_t fpcr; // floating point condition codes
+ uint64_t uniq; // process-unique register
+ bool lock_flag; // lock flag for LL/SC
+ Addr lock_addr; // lock address for LL/SC
+
+ public:
+ MiscReg readReg(int misc_reg);
+
+ MiscReg readRegWithEffect(int misc_reg, Fault &fault,
+ ExecContext *xc);
+
+ //These functions should be removed once the simplescalar cpu model
+ //has been replaced.
+ int getInstAsid();
+ int getDataAsid();
+
+ Fault setReg(int misc_reg, const MiscReg &val);
+
+ Fault setRegWithEffect(int misc_reg, const MiscReg &val,
+ ExecContext *xc);
+
+#if FULL_SYSTEM
+ protected:
+ typedef uint64_t InternalProcReg;
+
+ InternalProcReg ipr[NumInternalProcRegs]; // Internal processor regs
+
+ private:
+ InternalProcReg readIpr(int idx, Fault &fault, ExecContext *xc);
+
+ Fault setIpr(int idx, InternalProcReg val, ExecContext *xc);
+#endif
+ friend class RegFile;
+ };
+
+ class RegFile {
+
+ protected:
+ Addr pc; // program counter
+ Addr npc; // next-cycle program counter
+ Addr nnpc;
+
+ public:
+ Addr readPC()
+ {
+ return pc;
+ }
+
+ void setPC(Addr val)
+ {
+ pc = val;
+ }
+
+ Addr readNextPC()
+ {
+ return npc;
+ }
+
+ void setNextPC(Addr val)
+ {
+ npc = val;
+ }
+
+ Addr readNextNPC()
+ {
+ return nnpc;
+ }
+
+ void setNextNPC(Addr val)
+ {
+ nnpc = val;
+ }
+
+ protected:
+ IntRegFile intRegFile; // (signed) integer register file
+ FloatRegFile floatRegFile; // floating point register file
+ MiscRegFile miscRegFile; // control register file
+
+ public:
+
+#if FULL_SYSTEM
+ int intrflag; // interrupt flag
+ inline int instAsid()
+ { return miscRegFile.getInstAsid(); }
+ inline int dataAsid()
+ { return miscRegFile.getDataAsid(); }
+#endif // FULL_SYSTEM
+
+ void clear()
+ {
+ bzero(&intRegFile, sizeof(intRegFile));
+ bzero(&floatRegFile, sizeof(floatRegFile));
+ bzero(&miscRegFile, sizeof(miscRegFile));
+ }
+
+ MiscReg readMiscReg(int miscReg)
+ {
+ return miscRegFile.readReg(miscReg);
+ }
+
+ MiscReg readMiscRegWithEffect(int miscReg,
+ Fault &fault, ExecContext *xc)
+ {
+ fault = NoFault;
+ return miscRegFile.readRegWithEffect(miscReg, fault, xc);
+ }
+
+ Fault setMiscReg(int miscReg, const MiscReg &val)
+ {
+ return miscRegFile.setReg(miscReg, val);
+ }
+
+ Fault setMiscRegWithEffect(int miscReg, const MiscReg &val,
+ ExecContext * xc)
+ {
+ return miscRegFile.setRegWithEffect(miscReg, val, xc);
+ }
+
+ FloatReg readFloatReg(int floatReg)
+ {
+ return floatRegFile.d[floatReg];
+ }
+
+ FloatReg readFloatReg(int floatReg, int width)
+ {
+ return readFloatReg(floatReg);
+ }
+
+ FloatRegBits readFloatRegBits(int floatReg)
+ {
+ return floatRegFile.q[floatReg];
+ }
+
+ FloatRegBits readFloatRegBits(int floatReg, int width)
+ {
+ return readFloatRegBits(floatReg);
+ }
+
+ Fault setFloatReg(int floatReg, const FloatReg &val)
+ {
+ floatRegFile.d[floatReg] = val;
+ return NoFault;
+ }
+
+ Fault setFloatReg(int floatReg, const FloatReg &val, int width)
+ {
+ return setFloatReg(floatReg, val);
+ }
+
+ Fault setFloatRegBits(int floatReg, const FloatRegBits &val)
+ {
+ floatRegFile.q[floatReg] = val;
+ return NoFault;
+ }
+
+ Fault setFloatRegBits(int floatReg, const FloatRegBits &val, int width)
+ {
+ return setFloatRegBits(floatReg, val);
+ }
+
+ IntReg readIntReg(int intReg)
+ {
+ return intRegFile.readReg(intReg);
+ }
+
+ Fault setIntReg(int intReg, const IntReg &val)
+ {
+ return intRegFile.setReg(intReg, val);
+ }
+
+ void serialize(std::ostream &os);
+ void unserialize(Checkpoint *cp, const std::string &section);
+
+ enum ContextParam
+ {
+ CONTEXT_PALMODE
+ };
+
+ typedef bool ContextVal;
+
+ void changeContext(ContextParam param, ContextVal val)
+ {
+ //This would be an alternative place to call/implement
+ //the swapPALShadow function
+ }
+ };
+
+ void copyRegs(ExecContext *src, ExecContext *dest);
+
+ void copyMiscRegs(ExecContext *src, ExecContext *dest);
+
+#if FULL_SYSTEM
+ void copyIprs(ExecContext *src, ExecContext *dest);
+#endif
+} // namespace AlphaISA
+
+#endif
diff --git a/src/arch/alpha/stacktrace.cc b/src/arch/alpha/stacktrace.cc
new file mode 100644
index 000000000..8691e12dc
--- /dev/null
+++ b/src/arch/alpha/stacktrace.cc
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string>
+
+#include "arch/alpha/isa_traits.hh"
+#include "arch/alpha/stacktrace.hh"
+#include "arch/alpha/vtophys.hh"
+#include "base/bitfield.hh"
+#include "base/trace.hh"
+#include "cpu/base.hh"
+#include "cpu/exec_context.hh"
+#include "sim/system.hh"
+
+using namespace std;
+using namespace AlphaISA;
+
+ProcessInfo::ProcessInfo(ExecContext *_xc)
+ : xc(_xc)
+{
+ Addr addr = 0;
+
+ if (!xc->getSystemPtr()->kernelSymtab->findAddress("thread_info_size", addr))
+ panic("thread info not compiled into kernel\n");
+ thread_info_size = gtoh(xc->getVirtPort()->read<int32_t>(addr));
+
+ if (!xc->getSystemPtr()->kernelSymtab->findAddress("task_struct_size", addr))
+ panic("thread info not compiled into kernel\n");
+ task_struct_size = gtoh(xc->getVirtPort()->read<int32_t>(addr));
+
+ if (!xc->getSystemPtr()->kernelSymtab->findAddress("thread_info_task", addr))
+ panic("thread info not compiled into kernel\n");
+ task_off = gtoh(xc->getVirtPort()->read<int32_t>(addr));
+
+ if (!xc->getSystemPtr()->kernelSymtab->findAddress("task_struct_pid", addr))
+ panic("thread info not compiled into kernel\n");
+ pid_off = gtoh(xc->getVirtPort()->read<int32_t>(addr));
+
+ if (!xc->getSystemPtr()->kernelSymtab->findAddress("task_struct_comm", addr))
+ panic("thread info not compiled into kernel\n");
+ name_off = gtoh(xc->getVirtPort()->read<int32_t>(addr));
+}
+
+Addr
+ProcessInfo::task(Addr ksp) const
+{
+ Addr base = ksp & ~0x3fff;
+ if (base == ULL(0xfffffc0000000000))
+ return 0;
+
+ return gtoh(xc->getVirtPort()->read<Addr>(base + task_off));
+}
+
+int
+ProcessInfo::pid(Addr ksp) const
+{
+ Addr task = this->task(ksp);
+ if (!task)
+ return -1;
+
+ return gtoh(xc->getVirtPort()->read<uint16_t>(task + pid_off));
+}
+
+string
+ProcessInfo::name(Addr ksp) const
+{
+ Addr task = this->task(ksp);
+ if (!task)
+ return "console";
+
+ char comm[256];
+ CopyStringOut(xc, comm, task + name_off, sizeof(comm));
+ if (!comm[0])
+ return "startup";
+
+ return comm;
+}
+
+StackTrace::StackTrace()
+ : xc(0), stack(64)
+{
+}
+
+StackTrace::StackTrace(ExecContext *_xc, StaticInstPtr inst)
+ : xc(0), stack(64)
+{
+ trace(_xc, inst);
+}
+
+StackTrace::~StackTrace()
+{
+}
+
+void
+StackTrace::trace(ExecContext *_xc, bool is_call)
+{
+ xc = _xc;
+
+ bool usermode = (xc->readMiscReg(AlphaISA::IPR_DTB_CM) & 0x18) != 0;
+
+ Addr pc = xc->readNextPC();
+ bool kernel = xc->getSystemPtr()->kernelStart <= pc &&
+ pc <= xc->getSystemPtr()->kernelEnd;
+
+ if (usermode) {
+ stack.push_back(user);
+ return;
+ }
+
+ if (!kernel) {
+ stack.push_back(console);
+ return;
+ }
+
+ SymbolTable *symtab = xc->getSystemPtr()->kernelSymtab;
+ Addr ksp = xc->readIntReg(TheISA::StackPointerReg);
+ Addr bottom = ksp & ~0x3fff;
+ Addr addr;
+
+ if (is_call) {
+ if (!symtab->findNearestAddr(pc, addr))
+ panic("could not find address %#x", pc);
+
+ stack.push_back(addr);
+ pc = xc->readPC();
+ }
+
+ Addr ra;
+ int size;
+
+ while (ksp > bottom) {
+ if (!symtab->findNearestAddr(pc, addr))
+ panic("could not find symbol for pc=%#x", pc);
+ assert(pc >= addr && "symbol botch: callpc < func");
+
+ stack.push_back(addr);
+
+ if (isEntry(addr))
+ return;
+
+ if (decodePrologue(ksp, pc, addr, size, ra)) {
+ if (!ra)
+ return;
+
+ if (size <= 0) {
+ stack.push_back(unknown);
+ return;
+ }
+
+ pc = ra;
+ ksp += size;
+ } else {
+ stack.push_back(unknown);
+ return;
+ }
+
+ bool kernel = xc->getSystemPtr()->kernelStart <= pc &&
+ pc <= xc->getSystemPtr()->kernelEnd;
+ if (!kernel)
+ return;
+
+ if (stack.size() >= 1000)
+ panic("unwinding too far");
+ }
+
+ panic("unwinding too far");
+}
+
+bool
+StackTrace::isEntry(Addr addr)
+{
+ if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp12))
+ return true;
+
+ if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp7))
+ return true;
+
+ if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp11))
+ return true;
+
+ if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp21))
+ return true;
+
+ if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp9))
+ return true;
+
+ if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp2))
+ return true;
+
+ return false;
+}
+
+bool
+StackTrace::decodeStack(MachInst inst, int &disp)
+{
+ // lda $sp, -disp($sp)
+ //
+ // Opcode<31:26> == 0x08
+ // RA<25:21> == 30
+ // RB<20:16> == 30
+ // Disp<15:0>
+ const MachInst mem_mask = 0xffff0000;
+ const MachInst lda_pattern = 0x23de0000;
+ const MachInst lda_disp_mask = 0x0000ffff;
+
+ // subq $sp, disp, $sp
+ // addq $sp, disp, $sp
+ //
+ // Opcode<31:26> == 0x10
+ // RA<25:21> == 30
+ // Lit<20:13>
+ // One<12> = 1
+ // Func<11:5> == 0x20 (addq)
+ // Func<11:5> == 0x29 (subq)
+ // RC<4:0> == 30
+ const MachInst intop_mask = 0xffe01fff;
+ const MachInst addq_pattern = 0x43c0141e;
+ const MachInst subq_pattern = 0x43c0153e;
+ const MachInst intop_disp_mask = 0x001fe000;
+ const int intop_disp_shift = 13;
+
+ if ((inst & mem_mask) == lda_pattern)
+ disp = -sext<16>(inst & lda_disp_mask);
+ else if ((inst & intop_mask) == addq_pattern)
+ disp = -int((inst & intop_disp_mask) >> intop_disp_shift);
+ else if ((inst & intop_mask) == subq_pattern)
+ disp = int((inst & intop_disp_mask) >> intop_disp_shift);
+ else
+ return false;
+
+ return true;
+}
+
+bool
+StackTrace::decodeSave(MachInst inst, int &reg, int &disp)
+{
+ // lda $stq, disp($sp)
+ //
+ // Opcode<31:26> == 0x08
+ // RA<25:21> == ?
+ // RB<20:16> == 30
+ // Disp<15:0>
+ const MachInst stq_mask = 0xfc1f0000;
+ const MachInst stq_pattern = 0xb41e0000;
+ const MachInst stq_disp_mask = 0x0000ffff;
+ const MachInst reg_mask = 0x03e00000;
+ const int reg_shift = 21;
+
+ if ((inst & stq_mask) == stq_pattern) {
+ reg = (inst & reg_mask) >> reg_shift;
+ disp = sext<16>(inst & stq_disp_mask);
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * Decode the function prologue for the function we're in, and note
+ * which registers are stored where, and how large the stack frame is.
+ */
+bool
+StackTrace::decodePrologue(Addr sp, Addr callpc, Addr func,
+ int &size, Addr &ra)
+{
+ size = 0;
+ ra = 0;
+
+ for (Addr pc = func; pc < callpc; pc += sizeof(MachInst)) {
+ MachInst inst;
+ CopyOut(xc, (uint8_t *)&inst, pc, sizeof(MachInst));
+
+ int reg, disp;
+ if (decodeStack(inst, disp)) {
+ if (size) {
+ // panic("decoding frame size again");
+ return true;
+ }
+ size += disp;
+ } else if (decodeSave(inst, reg, disp)) {
+ if (!ra && reg == ReturnAddressReg) {
+ CopyOut(xc, (uint8_t *)&ra, sp + disp, sizeof(Addr));
+ if (!ra) {
+ // panic("no return address value pc=%#x\n", pc);
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+#if TRACING_ON
+void
+StackTrace::dump()
+{
+ StringWrap name(xc->getCpuPtr()->name());
+ SymbolTable *symtab = xc->getSystemPtr()->kernelSymtab;
+
+ DPRINTFN("------ Stack ------\n");
+
+ string symbol;
+ for (int i = 0, size = stack.size(); i < size; ++i) {
+ Addr addr = stack[size - i - 1];
+ if (addr == user)
+ symbol = "user";
+ else if (addr == console)
+ symbol = "console";
+ else if (addr == unknown)
+ symbol = "unknown";
+ else
+ symtab->findSymbol(addr, symbol);
+
+ DPRINTFN("%#x: %s\n", addr, symbol);
+ }
+}
+#endif
diff --git a/src/arch/alpha/stacktrace.hh b/src/arch/alpha/stacktrace.hh
new file mode 100644
index 000000000..1d8d97a79
--- /dev/null
+++ b/src/arch/alpha/stacktrace.hh
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ARCH_ALPHA_STACKTRACE_HH__
+#define __ARCH_ALPHA_STACKTRACE_HH__
+
+#include "base/trace.hh"
+#include "cpu/static_inst.hh"
+
+class ExecContext;
+class StackTrace;
+
+class ProcessInfo
+{
+ private:
+ ExecContext *xc;
+
+ int thread_info_size;
+ int task_struct_size;
+ int task_off;
+ int pid_off;
+ int name_off;
+
+ public:
+ ProcessInfo(ExecContext *_xc);
+
+ Addr task(Addr ksp) const;
+ int pid(Addr ksp) const;
+ std::string name(Addr ksp) const;
+};
+
+class StackTrace
+{
+ protected:
+ typedef TheISA::MachInst MachInst;
+ private:
+ ExecContext *xc;
+ std::vector<Addr> stack;
+
+ private:
+ bool isEntry(Addr addr);
+ bool decodePrologue(Addr sp, Addr callpc, Addr func, int &size, Addr &ra);
+ bool decodeSave(MachInst inst, int &reg, int &disp);
+ bool decodeStack(MachInst inst, int &disp);
+
+ void trace(ExecContext *xc, bool is_call);
+
+ public:
+ StackTrace();
+ StackTrace(ExecContext *xc, StaticInstPtr inst);
+ ~StackTrace();
+
+ void clear()
+ {
+ xc = 0;
+ stack.clear();
+ }
+
+ bool valid() const { return xc != NULL; }
+ bool trace(ExecContext *xc, StaticInstPtr inst);
+
+ public:
+ const std::vector<Addr> &getstack() const { return stack; }
+
+ static const int user = 1;
+ static const int console = 2;
+ static const int unknown = 3;
+
+#if TRACING_ON
+ private:
+ void dump();
+
+ public:
+ void dprintf() { if (DTRACE(Stack)) dump(); }
+#else
+ public:
+ void dprintf() {}
+#endif
+};
+
+inline bool
+StackTrace::trace(ExecContext *xc, StaticInstPtr inst)
+{
+ if (!inst->isCall() && !inst->isReturn())
+ return false;
+
+ if (valid())
+ clear();
+
+ trace(xc, !inst->isReturn());
+ return true;
+}
+
+#endif // __ARCH_ALPHA_STACKTRACE_HH__
diff --git a/src/arch/alpha/system.cc b/src/arch/alpha/system.cc
new file mode 100644
index 000000000..4234019cd
--- /dev/null
+++ b/src/arch/alpha/system.cc
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "arch/alpha/ev5.hh"
+#include "arch/alpha/system.hh"
+#include "arch/vtophys.hh"
+#include "base/remote_gdb.hh"
+#include "base/loader/object_file.hh"
+#include "base/loader/symtab.hh"
+#include "base/trace.hh"
+#include "mem/physical.hh"
+#include "sim/byteswap.hh"
+#include "sim/builder.hh"
+
+
+using namespace LittleEndianGuest;
+
+AlphaSystem::AlphaSystem(Params *p)
+ : System(p)
+{
+ consoleSymtab = new SymbolTable;
+ palSymtab = new SymbolTable;
+
+
+ /**
+ * Load the pal, and console code into memory
+ */
+ // Load Console Code
+ console = createObjectFile(params()->console_path);
+ if (console == NULL)
+ fatal("Could not load console file %s", params()->console_path);
+
+ // Load pal file
+ pal = createObjectFile(params()->palcode);
+ if (pal == NULL)
+ fatal("Could not load PALcode file %s", params()->palcode);
+
+
+ // Load program sections into memory
+ pal->loadSections(&functionalPort, AlphaISA::LoadAddrMask);
+ console->loadSections(&functionalPort, AlphaISA::LoadAddrMask);
+
+ // load symbols
+ if (!console->loadGlobalSymbols(consoleSymtab))
+ panic("could not load console symbols\n");
+
+ if (!pal->loadGlobalSymbols(palSymtab))
+ panic("could not load pal symbols\n");
+
+ if (!pal->loadLocalSymbols(palSymtab))
+ panic("could not load pal symbols\n");
+
+ if (!console->loadGlobalSymbols(debugSymbolTable))
+ panic("could not load console symbols\n");
+
+ if (!pal->loadGlobalSymbols(debugSymbolTable))
+ panic("could not load pal symbols\n");
+
+ if (!pal->loadLocalSymbols(debugSymbolTable))
+ panic("could not load pal symbols\n");
+
+ Addr addr = 0;
+#ifndef NDEBUG
+ consolePanicEvent = addConsoleFuncEvent<BreakPCEvent>("panic");
+#endif
+
+ /**
+ * Copy the osflags (kernel arguments) into the consoles
+ * memory. (Presently Linux does not use the console service
+ * routine to get these command line arguments, but Tru64 and
+ * others do.)
+ */
+ if (consoleSymtab->findAddress("env_booted_osflags", addr)) {
+ virtPort.writeBlob(addr, (uint8_t*)params()->boot_osflags.c_str(),
+ strlen(params()->boot_osflags.c_str()));
+ }
+
+ /**
+ * Set the hardware reset parameter block system type and revision
+ * information to Tsunami.
+ */
+ if (consoleSymtab->findAddress("m5_rpb", addr)) {
+ uint64_t data;
+ data = htog(params()->system_type);
+ virtPort.write(addr+0x50, data);
+ data = htog(params()->system_rev);
+ virtPort.write(addr+0x58, data);
+ } else
+ panic("could not find hwrpb\n");
+
+}
+
+AlphaSystem::~AlphaSystem()
+{
+ delete consoleSymtab;
+ delete console;
+ delete pal;
+#ifdef DEBUG
+ delete consolePanicEvent;
+#endif
+}
+
+/**
+ * This function fixes up addresses that are used to match PCs for
+ * hooking simulator events on to target function executions.
+ *
+ * Alpha binaries may have multiple global offset table (GOT)
+ * sections. A function that uses the GOT starts with a
+ * two-instruction prolog which sets the global pointer (gp == r29) to
+ * the appropriate GOT section. The proper gp value is calculated
+ * based on the function address, which must be passed by the caller
+ * in the procedure value register (pv aka t12 == r27). This sequence
+ * looks like the following:
+ *
+ * opcode Ra Rb offset
+ * ldah gp,X(pv) 09 29 27 X
+ * lda gp,Y(gp) 08 29 29 Y
+ *
+ * for some constant offsets X and Y. The catch is that the linker
+ * (or maybe even the compiler, I'm not sure) may recognize that the
+ * caller and callee are using the same GOT section, making this
+ * prolog redundant, and modify the call target to skip these
+ * instructions. If we check for execution of the first instruction
+ * of a function (the one the symbol points to) to detect when to skip
+ * it, we'll miss all these modified calls. It might work to
+ * unconditionally check for the third instruction, but not all
+ * functions have this prolog, and there's some chance that those
+ * first two instructions could have undesired consequences. So we do
+ * the Right Thing and pattern-match the first two instructions of the
+ * function to decide where to patch.
+ *
+ * Eventually this code should be moved into an ISA-specific file.
+ */
+Addr
+AlphaSystem::fixFuncEventAddr(Addr addr)
+{
+ // mask for just the opcode, Ra, and Rb fields (not the offset)
+ const uint32_t inst_mask = 0xffff0000;
+ // ldah gp,X(pv): opcode 9, Ra = 29, Rb = 27
+ const uint32_t gp_ldah_pattern = (9 << 26) | (29 << 21) | (27 << 16);
+ // lda gp,Y(gp): opcode 8, Ra = 29, rb = 29
+ const uint32_t gp_lda_pattern = (8 << 26) | (29 << 21) | (29 << 16);
+
+ uint32_t i1 = virtPort.read<uint32_t>(addr);
+ uint32_t i2 = virtPort.read<uint32_t>(addr + sizeof(AlphaISA::MachInst));
+
+ if ((i1 & inst_mask) == gp_ldah_pattern &&
+ (i2 & inst_mask) == gp_lda_pattern) {
+ Addr new_addr = addr + 2* sizeof(AlphaISA::MachInst);
+ DPRINTF(Loader, "fixFuncEventAddr: %p -> %p", addr, new_addr);
+ return new_addr;
+ } else {
+ return addr;
+ }
+}
+
+
+void
+AlphaSystem::setAlphaAccess(Addr access)
+{
+ Addr addr = 0;
+ if (consoleSymtab->findAddress("m5AlphaAccess", addr)) {
+ virtPort.write(addr, htog(EV5::Phys2K0Seg(access)));
+ } else
+ panic("could not find m5AlphaAccess\n");
+}
+
+bool
+AlphaSystem::breakpoint()
+{
+ return remoteGDB[0]->trap(ALPHA_KENTRY_INT);
+}
+
+void
+AlphaSystem::serialize(std::ostream &os)
+{
+ System::serialize(os);
+ consoleSymtab->serialize("console_symtab", os);
+ palSymtab->serialize("pal_symtab", os);
+}
+
+
+void
+AlphaSystem::unserialize(Checkpoint *cp, const std::string &section)
+{
+ System::unserialize(cp,section);
+ consoleSymtab->unserialize("console_symtab", cp, section);
+ palSymtab->unserialize("pal_symtab", cp, section);
+}
+
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaSystem)
+
+ Param<Tick> boot_cpu_frequency;
+ SimObjectParam<PhysicalMemory *> physmem;
+
+ Param<std::string> kernel;
+ Param<std::string> console;
+ Param<std::string> pal;
+
+ Param<std::string> boot_osflags;
+ Param<std::string> readfile;
+ Param<unsigned int> init_param;
+
+ Param<uint64_t> system_type;
+ Param<uint64_t> system_rev;
+
+ Param<bool> bin;
+ VectorParam<std::string> binned_fns;
+ Param<bool> bin_int;
+
+END_DECLARE_SIM_OBJECT_PARAMS(AlphaSystem)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaSystem)
+
+ INIT_PARAM(boot_cpu_frequency, "Frequency of the boot CPU"),
+ INIT_PARAM(physmem, "phsyical memory"),
+ INIT_PARAM(kernel, "file that contains the kernel code"),
+ INIT_PARAM(console, "file that contains the console code"),
+ INIT_PARAM(pal, "file that contains palcode"),
+ INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot",
+ "a"),
+ INIT_PARAM_DFLT(readfile, "file to read startup script from", ""),
+ INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0),
+ INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 34),
+ INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10),
+ INIT_PARAM_DFLT(bin, "is this system to be binned", false),
+ INIT_PARAM(binned_fns, "functions to be broken down and binned"),
+ INIT_PARAM_DFLT(bin_int, "is interrupt code binned seperately?", true)
+
+END_INIT_SIM_OBJECT_PARAMS(AlphaSystem)
+
+CREATE_SIM_OBJECT(AlphaSystem)
+{
+ AlphaSystem::Params *p = new AlphaSystem::Params;
+ p->name = getInstanceName();
+ p->boot_cpu_frequency = boot_cpu_frequency;
+ p->physmem = physmem;
+ p->kernel_path = kernel;
+ p->console_path = console;
+ p->palcode = pal;
+ p->boot_osflags = boot_osflags;
+ p->init_param = init_param;
+ p->readfile = readfile;
+ p->system_type = system_type;
+ p->system_rev = system_rev;
+ p->bin = bin;
+ p->binned_fns = binned_fns;
+ p->bin_int = bin_int;
+ return new AlphaSystem(p);
+}
+
+REGISTER_SIM_OBJECT("AlphaSystem", AlphaSystem)
+
+
diff --git a/src/arch/alpha/system.hh b/src/arch/alpha/system.hh
new file mode 100644
index 000000000..924e16826
--- /dev/null
+++ b/src/arch/alpha/system.hh
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ARCH_ALPHA_SYSTEM_HH__
+#define __ARCH_ALPHA_SYSTEM_HH__
+
+#include <string>
+#include <vector>
+
+#include "sim/system.hh"
+#include "base/loader/symtab.hh"
+#include "cpu/pc_event.hh"
+#include "kern/system_events.hh"
+#include "sim/sim_object.hh"
+
+class AlphaSystem : public System
+{
+ public:
+ struct Params : public System::Params
+ {
+ std::string console_path;
+ std::string palcode;
+ uint64_t system_type;
+ uint64_t system_rev;
+ };
+
+ AlphaSystem(Params *p);
+
+ ~AlphaSystem();
+
+ virtual bool breakpoint();
+
+/**
+ * Serialization stuff
+ */
+ public:
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+
+ /**
+ * Set the m5AlphaAccess pointer in the console
+ */
+ void setAlphaAccess(Addr access);
+
+ /** console symbol table */
+ SymbolTable *consoleSymtab;
+
+ /** pal symbol table */
+ SymbolTable *palSymtab;
+
+ /** Object pointer for the console code */
+ ObjectFile *console;
+
+ /** Object pointer for the PAL code */
+ ObjectFile *pal;
+
+#ifndef NDEBUG
+ /** Event to halt the simulator if the console calls panic() */
+ BreakPCEvent *consolePanicEvent;
+#endif
+ protected:
+ const Params *params() const { return (const Params *)_params; }
+
+ /** Add a function-based event to PALcode. */
+ template <class T>
+ T *AlphaSystem::addPalFuncEvent(const char *lbl)
+ {
+ return addFuncEvent<T>(palSymtab, lbl);
+ }
+
+ /** Add a function-based event to the console code. */
+ template <class T>
+ T *AlphaSystem::addConsoleFuncEvent(const char *lbl)
+ {
+ return addFuncEvent<T>(consoleSymtab, lbl);
+ }
+
+ virtual Addr fixFuncEventAddr(Addr addr);
+
+};
+
+#endif
+
diff --git a/src/arch/alpha/tlb.cc b/src/arch/alpha/tlb.cc
new file mode 100644
index 000000000..05b02d74b
--- /dev/null
+++ b/src/arch/alpha/tlb.cc
@@ -0,0 +1,628 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string>
+#include <vector>
+
+#include "arch/alpha/tlb.hh"
+#include "base/inifile.hh"
+#include "base/str.hh"
+#include "base/trace.hh"
+#include "config/alpha_tlaser.hh"
+#include "cpu/exec_context.hh"
+#include "sim/builder.hh"
+
+using namespace std;
+using namespace EV5;
+
+///////////////////////////////////////////////////////////////////////
+//
+// Alpha TLB
+//
+#ifdef DEBUG
+bool uncacheBit39 = false;
+bool uncacheBit40 = false;
+#endif
+
+#define MODE2MASK(X) (1 << (X))
+
+AlphaTLB::AlphaTLB(const string &name, int s)
+ : SimObject(name), size(s), nlu(0)
+{
+ table = new AlphaISA::PTE[size];
+ memset(table, 0, sizeof(AlphaISA::PTE[size]));
+}
+
+AlphaTLB::~AlphaTLB()
+{
+ if (table)
+ delete [] table;
+}
+
+// look up an entry in the TLB
+AlphaISA::PTE *
+AlphaTLB::lookup(Addr vpn, uint8_t asn) const
+{
+ // assume not found...
+ AlphaISA::PTE *retval = NULL;
+
+ PageTable::const_iterator i = lookupTable.find(vpn);
+ if (i != lookupTable.end()) {
+ while (i->first == vpn) {
+ int index = i->second;
+ AlphaISA::PTE *pte = &table[index];
+ assert(pte->valid);
+ if (vpn == pte->tag && (pte->asma || pte->asn == asn)) {
+ retval = pte;
+ break;
+ }
+
+ ++i;
+ }
+ }
+
+ DPRINTF(TLB, "lookup %#x, asn %#x -> %s ppn %#x\n", vpn, (int)asn,
+ retval ? "hit" : "miss", retval ? retval->ppn : 0);
+ return retval;
+}
+
+
+Fault
+AlphaTLB::checkCacheability(RequestPtr &req)
+{
+ // in Alpha, cacheability is controlled by upper-level bits of the
+ // physical address
+
+ /*
+ * We support having the uncacheable bit in either bit 39 or bit 40.
+ * The Turbolaser platform (and EV5) support having the bit in 39, but
+ * Tsunami (which Linux assumes uses an EV6) generates accesses with
+ * the bit in 40. So we must check for both, but we have debug flags
+ * to catch a weird case where both are used, which shouldn't happen.
+ */
+
+
+#if ALPHA_TLASER
+ if (req->getPaddr() & PAddrUncachedBit39) {
+#else
+ if (req->getPaddr() & PAddrUncachedBit43) {
+#endif
+ // IPR memory space not implemented
+ if (PAddrIprSpace(req->getPaddr())) {
+ return new UnimpFault("IPR memory space not implemented!");
+ } else {
+ // mark request as uncacheable
+ req->setFlags(req->getFlags() | UNCACHEABLE);
+
+#if !ALPHA_TLASER
+ // Clear bits 42:35 of the physical address (10-2 in Tsunami manual)
+ req->setPaddr(req->getPaddr() & PAddrUncachedMask);
+#endif
+ }
+ }
+ return NoFault;
+}
+
+
+// insert a new TLB entry
+void
+AlphaTLB::insert(Addr addr, AlphaISA::PTE &pte)
+{
+ AlphaISA::VAddr vaddr = addr;
+ if (table[nlu].valid) {
+ Addr oldvpn = table[nlu].tag;
+ PageTable::iterator i = lookupTable.find(oldvpn);
+
+ if (i == lookupTable.end())
+ panic("TLB entry not found in lookupTable");
+
+ int index;
+ while ((index = i->second) != nlu) {
+ if (table[index].tag != oldvpn)
+ panic("TLB entry not found in lookupTable");
+
+ ++i;
+ }
+
+ DPRINTF(TLB, "remove @%d: %#x -> %#x\n", nlu, oldvpn, table[nlu].ppn);
+
+ lookupTable.erase(i);
+ }
+
+ DPRINTF(TLB, "insert @%d: %#x -> %#x\n", nlu, vaddr.vpn(), pte.ppn);
+
+ table[nlu] = pte;
+ table[nlu].tag = vaddr.vpn();
+ table[nlu].valid = true;
+
+ lookupTable.insert(make_pair(vaddr.vpn(), nlu));
+ nextnlu();
+}
+
+void
+AlphaTLB::flushAll()
+{
+ DPRINTF(TLB, "flushAll\n");
+ memset(table, 0, sizeof(AlphaISA::PTE[size]));
+ lookupTable.clear();
+ nlu = 0;
+}
+
+void
+AlphaTLB::flushProcesses()
+{
+ PageTable::iterator i = lookupTable.begin();
+ PageTable::iterator end = lookupTable.end();
+ while (i != end) {
+ int index = i->second;
+ AlphaISA::PTE *pte = &table[index];
+ assert(pte->valid);
+
+ // we can't increment i after we erase it, so save a copy and
+ // increment it to get the next entry now
+ PageTable::iterator cur = i;
+ ++i;
+
+ if (!pte->asma) {
+ DPRINTF(TLB, "flush @%d: %#x -> %#x\n", index, pte->tag, pte->ppn);
+ pte->valid = false;
+ lookupTable.erase(cur);
+ }
+ }
+}
+
+void
+AlphaTLB::flushAddr(Addr addr, uint8_t asn)
+{
+ AlphaISA::VAddr vaddr = addr;
+
+ PageTable::iterator i = lookupTable.find(vaddr.vpn());
+ if (i == lookupTable.end())
+ return;
+
+ while (i->first == vaddr.vpn()) {
+ int index = i->second;
+ AlphaISA::PTE *pte = &table[index];
+ assert(pte->valid);
+
+ if (vaddr.vpn() == pte->tag && (pte->asma || pte->asn == asn)) {
+ DPRINTF(TLB, "flushaddr @%d: %#x -> %#x\n", index, vaddr.vpn(),
+ pte->ppn);
+
+ // invalidate this entry
+ pte->valid = false;
+
+ lookupTable.erase(i);
+ }
+
+ ++i;
+ }
+}
+
+
+void
+AlphaTLB::serialize(ostream &os)
+{
+ SERIALIZE_SCALAR(size);
+ SERIALIZE_SCALAR(nlu);
+
+ for (int i = 0; i < size; i++) {
+ nameOut(os, csprintf("%s.PTE%d", name(), i));
+ table[i].serialize(os);
+ }
+}
+
+void
+AlphaTLB::unserialize(Checkpoint *cp, const string &section)
+{
+ UNSERIALIZE_SCALAR(size);
+ UNSERIALIZE_SCALAR(nlu);
+
+ for (int i = 0; i < size; i++) {
+ table[i].unserialize(cp, csprintf("%s.PTE%d", section, i));
+ if (table[i].valid) {
+ lookupTable.insert(make_pair(table[i].tag, i));
+ }
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////
+//
+// Alpha ITB
+//
+AlphaITB::AlphaITB(const std::string &name, int size)
+ : AlphaTLB(name, size)
+{}
+
+
+void
+AlphaITB::regStats()
+{
+ hits
+ .name(name() + ".hits")
+ .desc("ITB hits");
+ misses
+ .name(name() + ".misses")
+ .desc("ITB misses");
+ acv
+ .name(name() + ".acv")
+ .desc("ITB acv");
+ accesses
+ .name(name() + ".accesses")
+ .desc("ITB accesses");
+
+ accesses = hits + misses;
+}
+
+
+Fault
+AlphaITB::translate(RequestPtr &req, ExecContext *xc) const
+{
+ if (AlphaISA::PcPAL(req->getVaddr())) {
+ // strip off PAL PC marker (lsb is 1)
+ req->setPaddr((req->getVaddr() & ~3) & PAddrImplMask);
+ hits++;
+ return NoFault;
+ }
+
+ if (req->getFlags() & PHYSICAL) {
+ req->setPaddr(req->getVaddr());
+ } else {
+ // verify that this is a good virtual address
+ if (!validVirtualAddress(req->getVaddr())) {
+ acv++;
+ return new ItbAcvFault(req->getVaddr());
+ }
+
+
+ // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13> for EV5
+ // VA<47:41> == 0x7e, VA<40:13> maps directly to PA<40:13> for EV6
+#if ALPHA_TLASER
+ if ((MCSR_SP(xc->readMiscReg(AlphaISA::IPR_MCSR)) & 2) &&
+ VAddrSpaceEV5(req->getVaddr()) == 2) {
+#else
+ if (VAddrSpaceEV6(req->getVaddr()) == 0x7e) {
+#endif
+ // only valid in kernel mode
+ if (ICM_CM(xc->readMiscReg(AlphaISA::IPR_ICM)) !=
+ AlphaISA::mode_kernel) {
+ acv++;
+ return new ItbAcvFault(req->getVaddr());
+ }
+
+ req->setPaddr(req->getVaddr() & PAddrImplMask);
+
+#if !ALPHA_TLASER
+ // sign extend the physical address properly
+ if (req->getPaddr() & PAddrUncachedBit40)
+ req->setPaddr(req->getPaddr() | ULL(0xf0000000000));
+ else
+ req->setPaddr(req->getPaddr() & ULL(0xffffffffff));
+#endif
+
+ } else {
+ // not a physical address: need to look up pte
+ int asn = DTB_ASN_ASN(xc->readMiscReg(AlphaISA::IPR_DTB_ASN));
+ AlphaISA::PTE *pte = lookup(AlphaISA::VAddr(req->getVaddr()).vpn(),
+ asn);
+
+ if (!pte) {
+ misses++;
+ return new ItbPageFault(req->getVaddr());
+ }
+
+ req->setPaddr((pte->ppn << AlphaISA::PageShift) +
+ (AlphaISA::VAddr(req->getVaddr()).offset()
+ & ~3));
+
+ // check permissions for this access
+ if (!(pte->xre &
+ (1 << ICM_CM(xc->readMiscReg(AlphaISA::IPR_ICM))))) {
+ // instruction access fault
+ acv++;
+ return new ItbAcvFault(req->getVaddr());
+ }
+
+ hits++;
+ }
+ }
+
+ // check that the physical address is ok (catch bad physical addresses)
+ if (req->getPaddr() & ~PAddrImplMask)
+ return genMachineCheckFault();
+
+ return checkCacheability(req);
+
+}
+
+///////////////////////////////////////////////////////////////////////
+//
+// Alpha DTB
+//
+AlphaDTB::AlphaDTB(const std::string &name, int size)
+ : AlphaTLB(name, size)
+{}
+
+void
+AlphaDTB::regStats()
+{
+ read_hits
+ .name(name() + ".read_hits")
+ .desc("DTB read hits")
+ ;
+
+ read_misses
+ .name(name() + ".read_misses")
+ .desc("DTB read misses")
+ ;
+
+ read_acv
+ .name(name() + ".read_acv")
+ .desc("DTB read access violations")
+ ;
+
+ read_accesses
+ .name(name() + ".read_accesses")
+ .desc("DTB read accesses")
+ ;
+
+ write_hits
+ .name(name() + ".write_hits")
+ .desc("DTB write hits")
+ ;
+
+ write_misses
+ .name(name() + ".write_misses")
+ .desc("DTB write misses")
+ ;
+
+ write_acv
+ .name(name() + ".write_acv")
+ .desc("DTB write access violations")
+ ;
+
+ write_accesses
+ .name(name() + ".write_accesses")
+ .desc("DTB write accesses")
+ ;
+
+ hits
+ .name(name() + ".hits")
+ .desc("DTB hits")
+ ;
+
+ misses
+ .name(name() + ".misses")
+ .desc("DTB misses")
+ ;
+
+ acv
+ .name(name() + ".acv")
+ .desc("DTB access violations")
+ ;
+
+ accesses
+ .name(name() + ".accesses")
+ .desc("DTB accesses")
+ ;
+
+ hits = read_hits + write_hits;
+ misses = read_misses + write_misses;
+ acv = read_acv + write_acv;
+ accesses = read_accesses + write_accesses;
+}
+
+Fault
+AlphaDTB::translate(RequestPtr &req, ExecContext *xc, bool write) const
+{
+ Addr pc = xc->readPC();
+
+ AlphaISA::mode_type mode =
+ (AlphaISA::mode_type)DTB_CM_CM(xc->readMiscReg(AlphaISA::IPR_DTB_CM));
+
+
+ /**
+ * Check for alignment faults
+ */
+ if (req->getVaddr() & (req->getSize() - 1)) {
+ DPRINTF(TLB, "Alignment Fault on %#x, size = %d", req->getVaddr(),
+ req->getSize());
+ uint64_t flags = write ? MM_STAT_WR_MASK : 0;
+ return new DtbAlignmentFault(req->getVaddr(), req->getFlags(), flags);
+ }
+
+ if (pc & 0x1) {
+ mode = (req->getFlags() & ALTMODE) ?
+ (AlphaISA::mode_type)ALT_MODE_AM(
+ xc->readMiscReg(AlphaISA::IPR_ALT_MODE))
+ : AlphaISA::mode_kernel;
+ }
+
+ if (req->getFlags() & PHYSICAL) {
+ req->setPaddr(req->getVaddr());
+ } else {
+ // verify that this is a good virtual address
+ if (!validVirtualAddress(req->getVaddr())) {
+ if (write) { write_acv++; } else { read_acv++; }
+ uint64_t flags = (write ? MM_STAT_WR_MASK : 0) |
+ MM_STAT_BAD_VA_MASK |
+ MM_STAT_ACV_MASK;
+ return new DtbPageFault(req->getVaddr(), req->getFlags(), flags);
+ }
+
+ // Check for "superpage" mapping
+#if ALPHA_TLASER
+ if ((MCSR_SP(xc->readMiscReg(AlphaISA::IPR_MCSR)) & 2) &&
+ VAddrSpaceEV5(req->getVaddr()) == 2) {
+#else
+ if (VAddrSpaceEV6(req->getVaddr()) == 0x7e) {
+#endif
+
+ // only valid in kernel mode
+ if (DTB_CM_CM(xc->readMiscReg(AlphaISA::IPR_DTB_CM)) !=
+ AlphaISA::mode_kernel) {
+ if (write) { write_acv++; } else { read_acv++; }
+ uint64_t flags = ((write ? MM_STAT_WR_MASK : 0) |
+ MM_STAT_ACV_MASK);
+ return new DtbAcvFault(req->getVaddr(), req->getFlags(), flags);
+ }
+
+ req->setPaddr(req->getVaddr() & PAddrImplMask);
+
+#if !ALPHA_TLASER
+ // sign extend the physical address properly
+ if (req->getPaddr() & PAddrUncachedBit40)
+ req->setPaddr(req->getPaddr() | ULL(0xf0000000000));
+ else
+ req->setPaddr(req->getPaddr() & ULL(0xffffffffff));
+#endif
+
+ } else {
+ if (write)
+ write_accesses++;
+ else
+ read_accesses++;
+
+ int asn = DTB_ASN_ASN(xc->readMiscReg(AlphaISA::IPR_DTB_ASN));
+
+ // not a physical address: need to look up pte
+ AlphaISA::PTE *pte = lookup(AlphaISA::VAddr(req->getVaddr()).vpn(),
+ asn);
+
+ if (!pte) {
+ // page fault
+ if (write) { write_misses++; } else { read_misses++; }
+ uint64_t flags = (write ? MM_STAT_WR_MASK : 0) |
+ MM_STAT_DTB_MISS_MASK;
+ return (req->getFlags() & VPTE) ?
+ (Fault)(new PDtbMissFault(req->getVaddr(), req->getFlags(),
+ flags)) :
+ (Fault)(new NDtbMissFault(req->getVaddr(), req->getFlags(),
+ flags));
+ }
+
+ req->setPaddr((pte->ppn << AlphaISA::PageShift) +
+ AlphaISA::VAddr(req->getVaddr()).offset());
+
+ if (write) {
+ if (!(pte->xwe & MODE2MASK(mode))) {
+ // declare the instruction access fault
+ write_acv++;
+ uint64_t flags = MM_STAT_WR_MASK |
+ MM_STAT_ACV_MASK |
+ (pte->fonw ? MM_STAT_FONW_MASK : 0);
+ return new DtbPageFault(req->getVaddr(), req->getFlags(), flags);
+ }
+ if (pte->fonw) {
+ write_acv++;
+ uint64_t flags = MM_STAT_WR_MASK |
+ MM_STAT_FONW_MASK;
+ return new DtbPageFault(req->getVaddr(), req->getFlags(), flags);
+ }
+ } else {
+ if (!(pte->xre & MODE2MASK(mode))) {
+ read_acv++;
+ uint64_t flags = MM_STAT_ACV_MASK |
+ (pte->fonr ? MM_STAT_FONR_MASK : 0);
+ return new DtbAcvFault(req->getVaddr(), req->getFlags(), flags);
+ }
+ if (pte->fonr) {
+ read_acv++;
+ uint64_t flags = MM_STAT_FONR_MASK;
+ return new DtbPageFault(req->getVaddr(), req->getFlags(), flags);
+ }
+ }
+ }
+
+ if (write)
+ write_hits++;
+ else
+ read_hits++;
+ }
+
+ // check that the physical address is ok (catch bad physical addresses)
+ if (req->getPaddr() & ~PAddrImplMask)
+ return genMachineCheckFault();
+
+ return checkCacheability(req);
+}
+
+AlphaISA::PTE &
+AlphaTLB::index(bool advance)
+{
+ AlphaISA::PTE *pte = &table[nlu];
+
+ if (advance)
+ nextnlu();
+
+ return *pte;
+}
+
+DEFINE_SIM_OBJECT_CLASS_NAME("AlphaTLB", AlphaTLB)
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaITB)
+
+ Param<int> size;
+
+END_DECLARE_SIM_OBJECT_PARAMS(AlphaITB)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaITB)
+
+ INIT_PARAM_DFLT(size, "TLB size", 48)
+
+END_INIT_SIM_OBJECT_PARAMS(AlphaITB)
+
+
+CREATE_SIM_OBJECT(AlphaITB)
+{
+ return new AlphaITB(getInstanceName(), size);
+}
+
+REGISTER_SIM_OBJECT("AlphaITB", AlphaITB)
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaDTB)
+
+ Param<int> size;
+
+END_DECLARE_SIM_OBJECT_PARAMS(AlphaDTB)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaDTB)
+
+ INIT_PARAM_DFLT(size, "TLB size", 64)
+
+END_INIT_SIM_OBJECT_PARAMS(AlphaDTB)
+
+
+CREATE_SIM_OBJECT(AlphaDTB)
+{
+ return new AlphaDTB(getInstanceName(), size);
+}
+
+REGISTER_SIM_OBJECT("AlphaDTB", AlphaDTB)
+
diff --git a/src/arch/alpha/tlb.hh b/src/arch/alpha/tlb.hh
new file mode 100644
index 000000000..f6256020e
--- /dev/null
+++ b/src/arch/alpha/tlb.hh
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ALPHA_MEMORY_HH__
+#define __ALPHA_MEMORY_HH__
+
+#include <map>
+
+#include "arch/alpha/ev5.hh"
+#include "arch/alpha/isa_traits.hh"
+#include "arch/alpha/faults.hh"
+#include "base/statistics.hh"
+#include "mem/request.hh"
+#include "sim/sim_object.hh"
+
+class ExecContext;
+
+class AlphaTLB : public SimObject
+{
+ protected:
+ typedef std::multimap<Addr, int> PageTable;
+ PageTable lookupTable; // Quick lookup into page table
+
+ AlphaISA::PTE *table; // the Page Table
+ int size; // TLB Size
+ int nlu; // not last used entry (for replacement)
+
+ void nextnlu() { if (++nlu >= size) nlu = 0; }
+ AlphaISA::PTE *lookup(Addr vpn, uint8_t asn) const;
+
+ public:
+ AlphaTLB(const std::string &name, int size);
+ virtual ~AlphaTLB();
+
+ int getsize() const { return size; }
+
+ AlphaISA::PTE &index(bool advance = true);
+ void insert(Addr vaddr, AlphaISA::PTE &pte);
+
+ void flushAll();
+ void flushProcesses();
+ void flushAddr(Addr addr, uint8_t asn);
+
+ // static helper functions... really EV5 VM traits
+ static bool validVirtualAddress(Addr vaddr) {
+ // unimplemented bits must be all 0 or all 1
+ Addr unimplBits = vaddr & EV5::VAddrUnImplMask;
+ return (unimplBits == 0) || (unimplBits == EV5::VAddrUnImplMask);
+ }
+
+ static Fault checkCacheability(RequestPtr &req);
+
+ // Checkpointing
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+};
+
+class AlphaITB : public AlphaTLB
+{
+ protected:
+ mutable Stats::Scalar<> hits;
+ mutable Stats::Scalar<> misses;
+ mutable Stats::Scalar<> acv;
+ mutable Stats::Formula accesses;
+
+ public:
+ AlphaITB(const std::string &name, int size);
+ virtual void regStats();
+
+ Fault translate(RequestPtr &req, ExecContext *xc) const;
+};
+
+class AlphaDTB : public AlphaTLB
+{
+ protected:
+ mutable Stats::Scalar<> read_hits;
+ mutable Stats::Scalar<> read_misses;
+ mutable Stats::Scalar<> read_acv;
+ mutable Stats::Scalar<> read_accesses;
+ mutable Stats::Scalar<> write_hits;
+ mutable Stats::Scalar<> write_misses;
+ mutable Stats::Scalar<> write_acv;
+ mutable Stats::Scalar<> write_accesses;
+ Stats::Formula hits;
+ Stats::Formula misses;
+ Stats::Formula acv;
+ Stats::Formula accesses;
+
+ public:
+ AlphaDTB(const std::string &name, int size);
+ virtual void regStats();
+
+ Fault translate(RequestPtr &req, ExecContext *xc, bool write) const;
+};
+
+#endif // __ALPHA_MEMORY_HH__
diff --git a/src/arch/alpha/tru64/process.cc b/src/arch/alpha/tru64/process.cc
new file mode 100644
index 000000000..55f75f7d0
--- /dev/null
+++ b/src/arch/alpha/tru64/process.cc
@@ -0,0 +1,586 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "arch/alpha/tru64/tru64.hh"
+#include "arch/alpha/isa_traits.hh"
+#include "arch/alpha/tru64/process.hh"
+
+#include "cpu/exec_context.hh"
+#include "kern/tru64/tru64.hh"
+
+#include "sim/process.hh"
+#include "sim/syscall_emul.hh"
+
+using namespace std;
+using namespace AlphaISA;
+
+/// Target uname() handler.
+static SyscallReturn
+unameFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ TypedBufferArg<AlphaTru64::utsname> name(xc->getSyscallArg(0));
+
+ strcpy(name->sysname, "OSF1");
+ strcpy(name->nodename, "m5.eecs.umich.edu");
+ strcpy(name->release, "V5.1");
+ strcpy(name->version, "732");
+ strcpy(name->machine, "alpha");
+
+ name.copyOut(xc->getMemPort());
+ return 0;
+}
+
+/// Target getsysyinfo() handler.
+static SyscallReturn
+getsysinfoFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ unsigned op = xc->getSyscallArg(0);
+ unsigned nbytes = xc->getSyscallArg(2);
+
+ switch (op) {
+
+ case AlphaTru64::GSI_MAX_CPU: {
+ TypedBufferArg<uint32_t> max_cpu(xc->getSyscallArg(1));
+ *max_cpu = htog((uint32_t)process->numCpus());
+ max_cpu.copyOut(xc->getMemPort());
+ return 1;
+ }
+
+ case AlphaTru64::GSI_CPUS_IN_BOX: {
+ TypedBufferArg<uint32_t> cpus_in_box(xc->getSyscallArg(1));
+ *cpus_in_box = htog((uint32_t)process->numCpus());
+ cpus_in_box.copyOut(xc->getMemPort());
+ return 1;
+ }
+
+ case AlphaTru64::GSI_PHYSMEM: {
+ TypedBufferArg<uint64_t> physmem(xc->getSyscallArg(1));
+ *physmem = htog((uint64_t)1024 * 1024); // physical memory in KB
+ physmem.copyOut(xc->getMemPort());
+ return 1;
+ }
+
+ case AlphaTru64::GSI_CPU_INFO: {
+ TypedBufferArg<AlphaTru64::cpu_info> infop(xc->getSyscallArg(1));
+
+ infop->current_cpu = htog(0);
+ infop->cpus_in_box = htog(process->numCpus());
+ infop->cpu_type = htog(57);
+ infop->ncpus = htog(process->numCpus());
+ uint64_t cpumask = (1 << process->numCpus()) - 1;
+ infop->cpus_present = infop->cpus_running = htog(cpumask);
+ infop->cpu_binding = htog(0);
+ infop->cpu_ex_binding = htog(0);
+ infop->mhz = htog(667);
+
+ infop.copyOut(xc->getMemPort());
+ return 1;
+ }
+
+ case AlphaTru64::GSI_PROC_TYPE: {
+ TypedBufferArg<uint64_t> proc_type(xc->getSyscallArg(1));
+ *proc_type = htog((uint64_t)11);
+ proc_type.copyOut(xc->getMemPort());
+ return 1;
+ }
+
+ case AlphaTru64::GSI_PLATFORM_NAME: {
+ BufferArg bufArg(xc->getSyscallArg(1), nbytes);
+ strncpy((char *)bufArg.bufferPtr(),
+ "COMPAQ Professional Workstation XP1000",
+ nbytes);
+ bufArg.copyOut(xc->getMemPort());
+ return 1;
+ }
+
+ case AlphaTru64::GSI_CLK_TCK: {
+ TypedBufferArg<uint64_t> clk_hz(xc->getSyscallArg(1));
+ *clk_hz = htog((uint64_t)1024);
+ clk_hz.copyOut(xc->getMemPort());
+ return 1;
+ }
+
+ default:
+ warn("getsysinfo: unknown op %d\n", op);
+ break;
+ }
+
+ return 0;
+}
+
+/// Target setsysyinfo() handler.
+static SyscallReturn
+setsysinfoFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ unsigned op = xc->getSyscallArg(0);
+
+ switch (op) {
+ case AlphaTru64::SSI_IEEE_FP_CONTROL:
+ warn("setsysinfo: ignoring ieee_set_fp_control() arg 0x%x\n",
+ xc->getSyscallArg(1));
+ break;
+
+ default:
+ warn("setsysinfo: unknown op %d\n", op);
+ break;
+ }
+
+ return 0;
+}
+
+
+/// Target table() handler.
+static
+SyscallReturn tableFunc(SyscallDesc *desc, int callnum,Process *process,
+ ExecContext *xc)
+{
+ using namespace std;
+ using namespace TheISA;
+
+ int id = xc->getSyscallArg(0); // table ID
+ int index = xc->getSyscallArg(1); // index into table
+ // arg 2 is buffer pointer; type depends on table ID
+ int nel = xc->getSyscallArg(3); // number of elements
+ int lel = xc->getSyscallArg(4); // expected element size
+
+ switch (id) {
+ case AlphaTru64::TBL_SYSINFO: {
+ if (index != 0 || nel != 1 || lel != sizeof(Tru64::tbl_sysinfo))
+ return -EINVAL;
+ TypedBufferArg<Tru64::tbl_sysinfo> elp(xc->getSyscallArg(2));
+
+ const int clk_hz = one_million;
+ elp->si_user = htog(curTick / (Clock::Frequency / clk_hz));
+ elp->si_nice = htog(0);
+ elp->si_sys = htog(0);
+ elp->si_idle = htog(0);
+ elp->wait = htog(0);
+ elp->si_hz = htog(clk_hz);
+ elp->si_phz = htog(clk_hz);
+ elp->si_boottime = htog(seconds_since_epoch); // seconds since epoch?
+ elp->si_max_procs = htog(process->numCpus());
+ elp.copyOut(xc->getMemPort());
+ return 0;
+ }
+
+ default:
+ cerr << "table(): id " << id << " unknown." << endl;
+ return -EINVAL;
+ }
+}
+
+SyscallDesc AlphaTru64Process::syscallDescs[] = {
+ /* 0 */ SyscallDesc("syscall (#0)", AlphaTru64::indirectSyscallFunc,
+ SyscallDesc::SuppressReturnValue),
+ /* 1 */ SyscallDesc("exit", exitFunc),
+ /* 2 */ SyscallDesc("fork", unimplementedFunc),
+ /* 3 */ SyscallDesc("read", readFunc),
+ /* 4 */ SyscallDesc("write", writeFunc),
+ /* 5 */ SyscallDesc("old_open", unimplementedFunc),
+ /* 6 */ SyscallDesc("close", closeFunc),
+ /* 7 */ SyscallDesc("wait4", unimplementedFunc),
+ /* 8 */ SyscallDesc("old_creat", unimplementedFunc),
+ /* 9 */ SyscallDesc("link", unimplementedFunc),
+ /* 10 */ SyscallDesc("unlink", unlinkFunc),
+ /* 11 */ SyscallDesc("execv", unimplementedFunc),
+ /* 12 */ SyscallDesc("chdir", unimplementedFunc),
+ /* 13 */ SyscallDesc("fchdir", unimplementedFunc),
+ /* 14 */ SyscallDesc("mknod", unimplementedFunc),
+ /* 15 */ SyscallDesc("chmod", unimplementedFunc),
+ /* 16 */ SyscallDesc("chown", unimplementedFunc),
+ /* 17 */ SyscallDesc("obreak", obreakFunc),
+ /* 18 */ SyscallDesc("pre_F64_getfsstat", unimplementedFunc),
+ /* 19 */ SyscallDesc("lseek", lseekFunc),
+ /* 20 */ SyscallDesc("getpid", getpidPseudoFunc),
+ /* 21 */ SyscallDesc("mount", unimplementedFunc),
+ /* 22 */ SyscallDesc("unmount", unimplementedFunc),
+ /* 23 */ SyscallDesc("setuid", setuidFunc),
+ /* 24 */ SyscallDesc("getuid", getuidPseudoFunc),
+ /* 25 */ SyscallDesc("exec_with_loader", unimplementedFunc),
+ /* 26 */ SyscallDesc("ptrace", unimplementedFunc),
+ /* 27 */ SyscallDesc("recvmsg", unimplementedFunc),
+ /* 28 */ SyscallDesc("sendmsg", unimplementedFunc),
+ /* 29 */ SyscallDesc("recvfrom", unimplementedFunc),
+ /* 30 */ SyscallDesc("accept", unimplementedFunc),
+ /* 31 */ SyscallDesc("getpeername", unimplementedFunc),
+ /* 32 */ SyscallDesc("getsockname", unimplementedFunc),
+ /* 33 */ SyscallDesc("access", unimplementedFunc),
+ /* 34 */ SyscallDesc("chflags", unimplementedFunc),
+ /* 35 */ SyscallDesc("fchflags", unimplementedFunc),
+ /* 36 */ SyscallDesc("sync", unimplementedFunc),
+ /* 37 */ SyscallDesc("kill", unimplementedFunc),
+ /* 38 */ SyscallDesc("old_stat", unimplementedFunc),
+ /* 39 */ SyscallDesc("setpgid", unimplementedFunc),
+ /* 40 */ SyscallDesc("old_lstat", unimplementedFunc),
+ /* 41 */ SyscallDesc("dup", unimplementedFunc),
+ /* 42 */ SyscallDesc("pipe", unimplementedFunc),
+ /* 43 */ SyscallDesc("set_program_attributes", unimplementedFunc),
+ /* 44 */ SyscallDesc("profil", unimplementedFunc),
+ /* 45 */ SyscallDesc("open", openFunc<AlphaTru64>),
+ /* 46 */ SyscallDesc("obsolete osigaction", unimplementedFunc),
+ /* 47 */ SyscallDesc("getgid", getgidPseudoFunc),
+ /* 48 */ SyscallDesc("sigprocmask", ignoreFunc),
+ /* 49 */ SyscallDesc("getlogin", unimplementedFunc),
+ /* 50 */ SyscallDesc("setlogin", unimplementedFunc),
+ /* 51 */ SyscallDesc("acct", unimplementedFunc),
+ /* 52 */ SyscallDesc("sigpending", unimplementedFunc),
+ /* 53 */ SyscallDesc("classcntl", unimplementedFunc),
+ /* 54 */ SyscallDesc("ioctl", ioctlFunc<AlphaTru64>),
+ /* 55 */ SyscallDesc("reboot", unimplementedFunc),
+ /* 56 */ SyscallDesc("revoke", unimplementedFunc),
+ /* 57 */ SyscallDesc("symlink", unimplementedFunc),
+ /* 58 */ SyscallDesc("readlink", unimplementedFunc),
+ /* 59 */ SyscallDesc("execve", unimplementedFunc),
+ /* 60 */ SyscallDesc("umask", unimplementedFunc),
+ /* 61 */ SyscallDesc("chroot", unimplementedFunc),
+ /* 62 */ SyscallDesc("old_fstat", unimplementedFunc),
+ /* 63 */ SyscallDesc("getpgrp", unimplementedFunc),
+ /* 64 */ SyscallDesc("getpagesize", getpagesizeFunc),
+ /* 65 */ SyscallDesc("mremap", unimplementedFunc),
+ /* 66 */ SyscallDesc("vfork", unimplementedFunc),
+ /* 67 */ SyscallDesc("pre_F64_stat", statFunc<AlphaTru64::PreF64>),
+ /* 68 */ SyscallDesc("pre_F64_lstat", lstatFunc<AlphaTru64::PreF64>),
+ /* 69 */ SyscallDesc("sbrk", unimplementedFunc),
+ /* 70 */ SyscallDesc("sstk", unimplementedFunc),
+ /* 71 */ SyscallDesc("mmap", mmapFunc<AlphaTru64>),
+ /* 72 */ SyscallDesc("ovadvise", unimplementedFunc),
+ /* 73 */ SyscallDesc("munmap", munmapFunc),
+ /* 74 */ SyscallDesc("mprotect", ignoreFunc),
+ /* 75 */ SyscallDesc("madvise", unimplementedFunc),
+ /* 76 */ SyscallDesc("old_vhangup", unimplementedFunc),
+ /* 77 */ SyscallDesc("kmodcall", unimplementedFunc),
+ /* 78 */ SyscallDesc("mincore", unimplementedFunc),
+ /* 79 */ SyscallDesc("getgroups", unimplementedFunc),
+ /* 80 */ SyscallDesc("setgroups", unimplementedFunc),
+ /* 81 */ SyscallDesc("old_getpgrp", unimplementedFunc),
+ /* 82 */ SyscallDesc("setpgrp", unimplementedFunc),
+ /* 83 */ SyscallDesc("setitimer", unimplementedFunc),
+ /* 84 */ SyscallDesc("old_wait", unimplementedFunc),
+ /* 85 */ SyscallDesc("table", tableFunc),
+ /* 86 */ SyscallDesc("getitimer", unimplementedFunc),
+ /* 87 */ SyscallDesc("gethostname", gethostnameFunc),
+ /* 88 */ SyscallDesc("sethostname", unimplementedFunc),
+ /* 89 */ SyscallDesc("getdtablesize", unimplementedFunc),
+ /* 90 */ SyscallDesc("dup2", unimplementedFunc),
+ /* 91 */ SyscallDesc("pre_F64_fstat", fstatFunc<AlphaTru64::PreF64>),
+ /* 92 */ SyscallDesc("fcntl", fcntlFunc),
+ /* 93 */ SyscallDesc("select", unimplementedFunc),
+ /* 94 */ SyscallDesc("poll", unimplementedFunc),
+ /* 95 */ SyscallDesc("fsync", unimplementedFunc),
+ /* 96 */ SyscallDesc("setpriority", unimplementedFunc),
+ /* 97 */ SyscallDesc("socket", unimplementedFunc),
+ /* 98 */ SyscallDesc("connect", unimplementedFunc),
+ /* 99 */ SyscallDesc("old_accept", unimplementedFunc),
+ /* 100 */ SyscallDesc("getpriority", unimplementedFunc),
+ /* 101 */ SyscallDesc("old_send", unimplementedFunc),
+ /* 102 */ SyscallDesc("old_recv", unimplementedFunc),
+ /* 103 */ SyscallDesc("sigreturn", AlphaTru64::sigreturnFunc,
+ SyscallDesc::SuppressReturnValue),
+ /* 104 */ SyscallDesc("bind", unimplementedFunc),
+ /* 105 */ SyscallDesc("setsockopt", unimplementedFunc),
+ /* 106 */ SyscallDesc("listen", unimplementedFunc),
+ /* 107 */ SyscallDesc("plock", unimplementedFunc),
+ /* 108 */ SyscallDesc("old_sigvec", unimplementedFunc),
+ /* 109 */ SyscallDesc("old_sigblock", unimplementedFunc),
+ /* 110 */ SyscallDesc("old_sigsetmask", unimplementedFunc),
+ /* 111 */ SyscallDesc("sigsuspend", unimplementedFunc),
+ /* 112 */ SyscallDesc("sigstack", ignoreFunc),
+ /* 113 */ SyscallDesc("old_recvmsg", unimplementedFunc),
+ /* 114 */ SyscallDesc("old_sendmsg", unimplementedFunc),
+ /* 115 */ SyscallDesc("obsolete vtrace", unimplementedFunc),
+ /* 116 */ SyscallDesc("gettimeofday", gettimeofdayFunc<AlphaTru64>),
+ /* 117 */ SyscallDesc("getrusage", getrusageFunc<AlphaTru64>),
+ /* 118 */ SyscallDesc("getsockopt", unimplementedFunc),
+ /* 119 */ SyscallDesc("numa_syscalls", unimplementedFunc),
+ /* 120 */ SyscallDesc("readv", unimplementedFunc),
+ /* 121 */ SyscallDesc("writev", unimplementedFunc),
+ /* 122 */ SyscallDesc("settimeofday", unimplementedFunc),
+ /* 123 */ SyscallDesc("fchown", unimplementedFunc),
+ /* 124 */ SyscallDesc("fchmod", unimplementedFunc),
+ /* 125 */ SyscallDesc("old_recvfrom", unimplementedFunc),
+ /* 126 */ SyscallDesc("setreuid", unimplementedFunc),
+ /* 127 */ SyscallDesc("setregid", unimplementedFunc),
+ /* 128 */ SyscallDesc("rename", renameFunc),
+ /* 129 */ SyscallDesc("truncate", truncateFunc),
+ /* 130 */ SyscallDesc("ftruncate", ftruncateFunc),
+ /* 131 */ SyscallDesc("flock", unimplementedFunc),
+ /* 132 */ SyscallDesc("setgid", unimplementedFunc),
+ /* 133 */ SyscallDesc("sendto", unimplementedFunc),
+ /* 134 */ SyscallDesc("shutdown", unimplementedFunc),
+ /* 135 */ SyscallDesc("socketpair", unimplementedFunc),
+ /* 136 */ SyscallDesc("mkdir", unimplementedFunc),
+ /* 137 */ SyscallDesc("rmdir", unimplementedFunc),
+ /* 138 */ SyscallDesc("utimes", unimplementedFunc),
+ /* 139 */ SyscallDesc("obsolete 4.2 sigreturn", unimplementedFunc),
+ /* 140 */ SyscallDesc("adjtime", unimplementedFunc),
+ /* 141 */ SyscallDesc("old_getpeername", unimplementedFunc),
+ /* 142 */ SyscallDesc("gethostid", unimplementedFunc),
+ /* 143 */ SyscallDesc("sethostid", unimplementedFunc),
+ /* 144 */ SyscallDesc("getrlimit", getrlimitFunc<AlphaTru64>),
+ /* 145 */ SyscallDesc("setrlimit", ignoreFunc),
+ /* 146 */ SyscallDesc("old_killpg", unimplementedFunc),
+ /* 147 */ SyscallDesc("setsid", unimplementedFunc),
+ /* 148 */ SyscallDesc("quotactl", unimplementedFunc),
+ /* 149 */ SyscallDesc("oldquota", unimplementedFunc),
+ /* 150 */ SyscallDesc("old_getsockname", unimplementedFunc),
+ /* 151 */ SyscallDesc("pread", unimplementedFunc),
+ /* 152 */ SyscallDesc("pwrite", unimplementedFunc),
+ /* 153 */ SyscallDesc("pid_block", unimplementedFunc),
+ /* 154 */ SyscallDesc("pid_unblock", unimplementedFunc),
+ /* 155 */ SyscallDesc("signal_urti", unimplementedFunc),
+ /* 156 */ SyscallDesc("sigaction", ignoreFunc),
+ /* 157 */ SyscallDesc("sigwaitprim", unimplementedFunc),
+ /* 158 */ SyscallDesc("nfssvc", unimplementedFunc),
+ /* 159 */ SyscallDesc("getdirentries", AlphaTru64::getdirentriesFunc),
+ /* 160 */ SyscallDesc("pre_F64_statfs", statfsFunc<AlphaTru64::PreF64>),
+ /* 161 */ SyscallDesc("pre_F64_fstatfs", fstatfsFunc<AlphaTru64::PreF64>),
+ /* 162 */ SyscallDesc("unknown #162", unimplementedFunc),
+ /* 163 */ SyscallDesc("async_daemon", unimplementedFunc),
+ /* 164 */ SyscallDesc("getfh", unimplementedFunc),
+ /* 165 */ SyscallDesc("getdomainname", unimplementedFunc),
+ /* 166 */ SyscallDesc("setdomainname", unimplementedFunc),
+ /* 167 */ SyscallDesc("unknown #167", unimplementedFunc),
+ /* 168 */ SyscallDesc("unknown #168", unimplementedFunc),
+ /* 169 */ SyscallDesc("exportfs", unimplementedFunc),
+ /* 170 */ SyscallDesc("unknown #170", unimplementedFunc),
+ /* 171 */ SyscallDesc("unknown #171", unimplementedFunc),
+ /* 172 */ SyscallDesc("unknown #172", unimplementedFunc),
+ /* 173 */ SyscallDesc("unknown #173", unimplementedFunc),
+ /* 174 */ SyscallDesc("unknown #174", unimplementedFunc),
+ /* 175 */ SyscallDesc("unknown #175", unimplementedFunc),
+ /* 176 */ SyscallDesc("unknown #176", unimplementedFunc),
+ /* 177 */ SyscallDesc("unknown #177", unimplementedFunc),
+ /* 178 */ SyscallDesc("unknown #178", unimplementedFunc),
+ /* 179 */ SyscallDesc("unknown #179", unimplementedFunc),
+ /* 180 */ SyscallDesc("unknown #180", unimplementedFunc),
+ /* 181 */ SyscallDesc("alt_plock", unimplementedFunc),
+ /* 182 */ SyscallDesc("unknown #182", unimplementedFunc),
+ /* 183 */ SyscallDesc("unknown #183", unimplementedFunc),
+ /* 184 */ SyscallDesc("getmnt", unimplementedFunc),
+ /* 185 */ SyscallDesc("unknown #185", unimplementedFunc),
+ /* 186 */ SyscallDesc("unknown #186", unimplementedFunc),
+ /* 187 */ SyscallDesc("alt_sigpending", unimplementedFunc),
+ /* 188 */ SyscallDesc("alt_setsid", unimplementedFunc),
+ /* 189 */ SyscallDesc("unknown #189", unimplementedFunc),
+ /* 190 */ SyscallDesc("unknown #190", unimplementedFunc),
+ /* 191 */ SyscallDesc("unknown #191", unimplementedFunc),
+ /* 192 */ SyscallDesc("unknown #192", unimplementedFunc),
+ /* 193 */ SyscallDesc("unknown #193", unimplementedFunc),
+ /* 194 */ SyscallDesc("unknown #194", unimplementedFunc),
+ /* 195 */ SyscallDesc("unknown #195", unimplementedFunc),
+ /* 196 */ SyscallDesc("unknown #196", unimplementedFunc),
+ /* 197 */ SyscallDesc("unknown #197", unimplementedFunc),
+ /* 198 */ SyscallDesc("unknown #198", unimplementedFunc),
+ /* 199 */ SyscallDesc("swapon", unimplementedFunc),
+ /* 200 */ SyscallDesc("msgctl", unimplementedFunc),
+ /* 201 */ SyscallDesc("msgget", unimplementedFunc),
+ /* 202 */ SyscallDesc("msgrcv", unimplementedFunc),
+ /* 203 */ SyscallDesc("msgsnd", unimplementedFunc),
+ /* 204 */ SyscallDesc("semctl", unimplementedFunc),
+ /* 205 */ SyscallDesc("semget", unimplementedFunc),
+ /* 206 */ SyscallDesc("semop", unimplementedFunc),
+ /* 207 */ SyscallDesc("uname", unameFunc),
+ /* 208 */ SyscallDesc("lchown", unimplementedFunc),
+ /* 209 */ SyscallDesc("shmat", unimplementedFunc),
+ /* 210 */ SyscallDesc("shmctl", unimplementedFunc),
+ /* 211 */ SyscallDesc("shmdt", unimplementedFunc),
+ /* 212 */ SyscallDesc("shmget", unimplementedFunc),
+ /* 213 */ SyscallDesc("mvalid", unimplementedFunc),
+ /* 214 */ SyscallDesc("getaddressconf", unimplementedFunc),
+ /* 215 */ SyscallDesc("msleep", unimplementedFunc),
+ /* 216 */ SyscallDesc("mwakeup", unimplementedFunc),
+ /* 217 */ SyscallDesc("msync", unimplementedFunc),
+ /* 218 */ SyscallDesc("signal", unimplementedFunc),
+ /* 219 */ SyscallDesc("utc_gettime", unimplementedFunc),
+ /* 220 */ SyscallDesc("utc_adjtime", unimplementedFunc),
+ /* 221 */ SyscallDesc("unknown #221", unimplementedFunc),
+ /* 222 */ SyscallDesc("security", unimplementedFunc),
+ /* 223 */ SyscallDesc("kloadcall", unimplementedFunc),
+ /* 224 */ SyscallDesc("stat", statFunc<AlphaTru64::F64>),
+ /* 225 */ SyscallDesc("lstat", lstatFunc<AlphaTru64::F64>),
+ /* 226 */ SyscallDesc("fstat", fstatFunc<AlphaTru64::F64>),
+ /* 227 */ SyscallDesc("statfs", statfsFunc<AlphaTru64::F64>),
+ /* 228 */ SyscallDesc("fstatfs", fstatfsFunc<AlphaTru64::F64>),
+ /* 229 */ SyscallDesc("getfsstat", unimplementedFunc),
+ /* 230 */ SyscallDesc("gettimeofday64", unimplementedFunc),
+ /* 231 */ SyscallDesc("settimeofday64", unimplementedFunc),
+ /* 232 */ SyscallDesc("unknown #232", unimplementedFunc),
+ /* 233 */ SyscallDesc("getpgid", unimplementedFunc),
+ /* 234 */ SyscallDesc("getsid", unimplementedFunc),
+ /* 235 */ SyscallDesc("sigaltstack", ignoreFunc),
+ /* 236 */ SyscallDesc("waitid", unimplementedFunc),
+ /* 237 */ SyscallDesc("priocntlset", unimplementedFunc),
+ /* 238 */ SyscallDesc("sigsendset", unimplementedFunc),
+ /* 239 */ SyscallDesc("set_speculative", unimplementedFunc),
+ /* 240 */ SyscallDesc("msfs_syscall", unimplementedFunc),
+ /* 241 */ SyscallDesc("sysinfo", unimplementedFunc),
+ /* 242 */ SyscallDesc("uadmin", unimplementedFunc),
+ /* 243 */ SyscallDesc("fuser", unimplementedFunc),
+ /* 244 */ SyscallDesc("proplist_syscall", unimplementedFunc),
+ /* 245 */ SyscallDesc("ntp_adjtime", unimplementedFunc),
+ /* 246 */ SyscallDesc("ntp_gettime", unimplementedFunc),
+ /* 247 */ SyscallDesc("pathconf", unimplementedFunc),
+ /* 248 */ SyscallDesc("fpathconf", unimplementedFunc),
+ /* 249 */ SyscallDesc("sync2", unimplementedFunc),
+ /* 250 */ SyscallDesc("uswitch", unimplementedFunc),
+ /* 251 */ SyscallDesc("usleep_thread", unimplementedFunc),
+ /* 252 */ SyscallDesc("audcntl", unimplementedFunc),
+ /* 253 */ SyscallDesc("audgen", unimplementedFunc),
+ /* 254 */ SyscallDesc("sysfs", unimplementedFunc),
+ /* 255 */ SyscallDesc("subsys_info", unimplementedFunc),
+ /* 256 */ SyscallDesc("getsysinfo", getsysinfoFunc),
+ /* 257 */ SyscallDesc("setsysinfo", setsysinfoFunc),
+ /* 258 */ SyscallDesc("afs_syscall", unimplementedFunc),
+ /* 259 */ SyscallDesc("swapctl", unimplementedFunc),
+ /* 260 */ SyscallDesc("memcntl", unimplementedFunc),
+ /* 261 */ SyscallDesc("fdatasync", unimplementedFunc),
+ /* 262 */ SyscallDesc("oflock", unimplementedFunc),
+ /* 263 */ SyscallDesc("F64_readv", unimplementedFunc),
+ /* 264 */ SyscallDesc("F64_writev", unimplementedFunc),
+ /* 265 */ SyscallDesc("cdslxlate", unimplementedFunc),
+ /* 266 */ SyscallDesc("sendfile", unimplementedFunc),
+};
+
+
+
+SyscallDesc AlphaTru64Process::machSyscallDescs[] = {
+ /* 0 */ SyscallDesc("kern_invalid", unimplementedFunc),
+ /* 1 */ SyscallDesc("m5_mutex_lock", AlphaTru64::m5_mutex_lockFunc),
+ /* 2 */ SyscallDesc("m5_mutex_trylock", AlphaTru64::m5_mutex_trylockFunc),
+ /* 3 */ SyscallDesc("m5_mutex_unlock", AlphaTru64::m5_mutex_unlockFunc),
+ /* 4 */ SyscallDesc("m5_cond_signal", AlphaTru64::m5_cond_signalFunc),
+ /* 5 */ SyscallDesc("m5_cond_broadcast", AlphaTru64::m5_cond_broadcastFunc),
+ /* 6 */ SyscallDesc("m5_cond_wait", AlphaTru64::m5_cond_waitFunc),
+ /* 7 */ SyscallDesc("m5_thread_exit", AlphaTru64::m5_thread_exitFunc),
+ /* 8 */ SyscallDesc("kern_invalid", unimplementedFunc),
+ /* 9 */ SyscallDesc("kern_invalid", unimplementedFunc),
+ /* 10 */ SyscallDesc("task_self", unimplementedFunc),
+ /* 11 */ SyscallDesc("thread_reply", unimplementedFunc),
+ /* 12 */ SyscallDesc("task_notify", unimplementedFunc),
+ /* 13 */ SyscallDesc("thread_self", unimplementedFunc),
+ /* 14 */ SyscallDesc("kern_invalid", unimplementedFunc),
+ /* 15 */ SyscallDesc("kern_invalid", unimplementedFunc),
+ /* 16 */ SyscallDesc("kern_invalid", unimplementedFunc),
+ /* 17 */ SyscallDesc("kern_invalid", unimplementedFunc),
+ /* 18 */ SyscallDesc("kern_invalid", unimplementedFunc),
+ /* 19 */ SyscallDesc("kern_invalid", unimplementedFunc),
+ /* 20 */ SyscallDesc("msg_send_trap", unimplementedFunc),
+ /* 21 */ SyscallDesc("msg_receive_trap", unimplementedFunc),
+ /* 22 */ SyscallDesc("msg_rpc_trap", unimplementedFunc),
+ /* 23 */ SyscallDesc("kern_invalid", unimplementedFunc),
+ /* 24 */ SyscallDesc("nxm_block", AlphaTru64::nxm_blockFunc),
+ /* 25 */ SyscallDesc("nxm_unblock", AlphaTru64::nxm_unblockFunc),
+ /* 26 */ SyscallDesc("kern_invalid", unimplementedFunc),
+ /* 27 */ SyscallDesc("kern_invalid", unimplementedFunc),
+ /* 28 */ SyscallDesc("kern_invalid", unimplementedFunc),
+ /* 29 */ SyscallDesc("nxm_thread_destroy", unimplementedFunc),
+ /* 30 */ SyscallDesc("lw_wire", unimplementedFunc),
+ /* 31 */ SyscallDesc("lw_unwire", unimplementedFunc),
+ /* 32 */ SyscallDesc("nxm_thread_create", AlphaTru64::nxm_thread_createFunc),
+ /* 33 */ SyscallDesc("nxm_task_init", AlphaTru64::nxm_task_initFunc),
+ /* 34 */ SyscallDesc("kern_invalid", unimplementedFunc),
+ /* 35 */ SyscallDesc("nxm_idle", AlphaTru64::nxm_idleFunc),
+ /* 36 */ SyscallDesc("nxm_wakeup_idle", unimplementedFunc),
+ /* 37 */ SyscallDesc("nxm_set_pthid", unimplementedFunc),
+ /* 38 */ SyscallDesc("nxm_thread_kill", unimplementedFunc),
+ /* 39 */ SyscallDesc("nxm_thread_block", AlphaTru64::nxm_thread_blockFunc),
+ /* 40 */ SyscallDesc("nxm_thread_wakeup", unimplementedFunc),
+ /* 41 */ SyscallDesc("init_process", unimplementedFunc),
+ /* 42 */ SyscallDesc("nxm_get_binding", unimplementedFunc),
+ /* 43 */ SyscallDesc("map_fd", unimplementedFunc),
+ /* 44 */ SyscallDesc("nxm_resched", unimplementedFunc),
+ /* 45 */ SyscallDesc("nxm_set_cancel", unimplementedFunc),
+ /* 46 */ SyscallDesc("nxm_set_binding", unimplementedFunc),
+ /* 47 */ SyscallDesc("stack_create", AlphaTru64::stack_createFunc),
+ /* 48 */ SyscallDesc("nxm_get_state", unimplementedFunc),
+ /* 49 */ SyscallDesc("nxm_thread_suspend", unimplementedFunc),
+ /* 50 */ SyscallDesc("nxm_thread_resume", unimplementedFunc),
+ /* 51 */ SyscallDesc("nxm_signal_check", unimplementedFunc),
+ /* 52 */ SyscallDesc("htg_unix_syscall", unimplementedFunc),
+ /* 53 */ SyscallDesc("kern_invalid", unimplementedFunc),
+ /* 54 */ SyscallDesc("kern_invalid", unimplementedFunc),
+ /* 55 */ SyscallDesc("host_self", unimplementedFunc),
+ /* 56 */ SyscallDesc("host_priv_self", unimplementedFunc),
+ /* 57 */ SyscallDesc("kern_invalid", unimplementedFunc),
+ /* 58 */ SyscallDesc("kern_invalid", unimplementedFunc),
+ /* 59 */ SyscallDesc("swtch_pri", AlphaTru64::swtch_priFunc),
+ /* 60 */ SyscallDesc("swtch", unimplementedFunc),
+ /* 61 */ SyscallDesc("thread_switch", unimplementedFunc),
+ /* 62 */ SyscallDesc("semop_fast", unimplementedFunc),
+ /* 63 */ SyscallDesc("nxm_pshared_init", unimplementedFunc),
+ /* 64 */ SyscallDesc("nxm_pshared_block", unimplementedFunc),
+ /* 65 */ SyscallDesc("nxm_pshared_unblock", unimplementedFunc),
+ /* 66 */ SyscallDesc("nxm_pshared_destroy", unimplementedFunc),
+ /* 67 */ SyscallDesc("nxm_swtch_pri", AlphaTru64::swtch_priFunc),
+ /* 68 */ SyscallDesc("lw_syscall", unimplementedFunc),
+ /* 69 */ SyscallDesc("kern_invalid", unimplementedFunc),
+ /* 70 */ SyscallDesc("mach_sctimes_0", unimplementedFunc),
+ /* 71 */ SyscallDesc("mach_sctimes_1", unimplementedFunc),
+ /* 72 */ SyscallDesc("mach_sctimes_2", unimplementedFunc),
+ /* 73 */ SyscallDesc("mach_sctimes_3", unimplementedFunc),
+ /* 74 */ SyscallDesc("mach_sctimes_4", unimplementedFunc),
+ /* 75 */ SyscallDesc("mach_sctimes_5", unimplementedFunc),
+ /* 76 */ SyscallDesc("mach_sctimes_6", unimplementedFunc),
+ /* 77 */ SyscallDesc("mach_sctimes_7", unimplementedFunc),
+ /* 78 */ SyscallDesc("mach_sctimes_8", unimplementedFunc),
+ /* 79 */ SyscallDesc("mach_sctimes_9", unimplementedFunc),
+ /* 80 */ SyscallDesc("mach_sctimes_10", unimplementedFunc),
+ /* 81 */ SyscallDesc("mach_sctimes_11", unimplementedFunc),
+ /* 82 */ SyscallDesc("mach_sctimes_port_alloc_dealloc", unimplementedFunc)
+};
+
+SyscallDesc*
+AlphaTru64Process::getDesc(int callnum)
+{
+ if (callnum < -Num_Mach_Syscall_Descs || callnum > Num_Syscall_Descs)
+ return NULL;
+
+ if (callnum < 0)
+ return &machSyscallDescs[-callnum];
+ else
+ return &syscallDescs[callnum];
+}
+
+
+AlphaTru64Process::AlphaTru64Process(const std::string &name,
+ ObjectFile *objFile,
+ System *system,
+ int stdin_fd,
+ int stdout_fd,
+ int stderr_fd,
+ std::vector<std::string> &argv,
+ std::vector<std::string> &envp)
+ : AlphaLiveProcess(name, objFile, system, stdin_fd, stdout_fd,
+ stderr_fd, argv, envp),
+ Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc)),
+ Num_Mach_Syscall_Descs(sizeof(machSyscallDescs) / sizeof(SyscallDesc))
+{
+}
diff --git a/src/arch/alpha/tru64/process.hh b/src/arch/alpha/tru64/process.hh
new file mode 100644
index 000000000..1cde4cac0
--- /dev/null
+++ b/src/arch/alpha/tru64/process.hh
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2003-2004 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ALPHA_TRU64_PROCESS_HH__
+#define __ALPHA_TRU64_PROCESS_HH__
+
+#include "arch/alpha/process.hh"
+
+namespace AlphaISA {
+/// A process with emulated Alpha Tru64 syscalls.
+class AlphaTru64Process : public AlphaLiveProcess
+{
+ public:
+ /// Constructor.
+ AlphaTru64Process(const std::string &name,
+ ObjectFile *objFile,
+ System *system,
+ int stdin_fd, int stdout_fd, int stderr_fd,
+ std::vector<std::string> &argv,
+ std::vector<std::string> &envp);
+
+ /// Array of syscall descriptors, indexed by call number.
+ static SyscallDesc syscallDescs[];
+
+ /// Array of mach syscall descriptors, indexed by call number.
+ static SyscallDesc machSyscallDescs[];
+
+ const int Num_Syscall_Descs;
+ const int Num_Mach_Syscall_Descs;
+
+ virtual SyscallDesc* getDesc(int callnum);
+};
+
+} // namespace AlphaISA
+
+#endif // __ALPHA_TRU64_PROCESS_HH__
diff --git a/src/arch/alpha/tru64/system.cc b/src/arch/alpha/tru64/system.cc
new file mode 100644
index 000000000..2ad06d679
--- /dev/null
+++ b/src/arch/alpha/tru64/system.cc
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "arch/alpha/tru64/system.hh"
+#include "arch/isa_traits.hh"
+#include "arch/vtophys.hh"
+#include "base/loader/symtab.hh"
+#include "base/trace.hh"
+#include "cpu/base.hh"
+#include "cpu/exec_context.hh"
+#include "kern/tru64/tru64_events.hh"
+#include "kern/system_events.hh"
+#include "mem/physical.hh"
+#include "mem/port.hh"
+#include "sim/builder.hh"
+
+using namespace std;
+
+Tru64AlphaSystem::Tru64AlphaSystem(Tru64AlphaSystem::Params *p)
+ : AlphaSystem(p)
+{
+ Addr addr = 0;
+ if (kernelSymtab->findAddress("enable_async_printf", addr)) {
+ virtPort.write(addr, (uint32_t)0);
+ }
+
+#ifdef DEBUG
+ kernelPanicEvent = addKernelFuncEvent<BreakPCEvent>("panic");
+ if (!kernelPanicEvent)
+ panic("could not find kernel symbol \'panic\'");
+#endif
+
+ badaddrEvent = addKernelFuncEvent<BadAddrEvent>("badaddr");
+ if (!badaddrEvent)
+ panic("could not find kernel symbol \'badaddr\'");
+
+ skipPowerStateEvent =
+ addKernelFuncEvent<SkipFuncEvent>("tl_v48_capture_power_state");
+ skipScavengeBootEvent =
+ addKernelFuncEvent<SkipFuncEvent>("pmap_scavenge_boot");
+
+#if TRACING_ON
+ printfEvent = addKernelFuncEvent<PrintfEvent>("printf");
+ debugPrintfEvent = addKernelFuncEvent<DebugPrintfEvent>("m5printf");
+ debugPrintfrEvent = addKernelFuncEvent<DebugPrintfrEvent>("m5printfr");
+ dumpMbufEvent = addKernelFuncEvent<DumpMbufEvent>("m5_dump_mbuf");
+#endif
+}
+
+Tru64AlphaSystem::~Tru64AlphaSystem()
+{
+#ifdef DEBUG
+ delete kernelPanicEvent;
+#endif
+ delete badaddrEvent;
+ delete skipPowerStateEvent;
+ delete skipScavengeBootEvent;
+#if TRACING_ON
+ delete printfEvent;
+ delete debugPrintfEvent;
+ delete debugPrintfrEvent;
+ delete dumpMbufEvent;
+#endif
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(Tru64AlphaSystem)
+
+ Param<Tick> boot_cpu_frequency;
+ SimObjectParam<PhysicalMemory *> physmem;
+
+ Param<string> kernel;
+ Param<string> console;
+ Param<string> pal;
+
+ Param<string> boot_osflags;
+ Param<string> readfile;
+ Param<unsigned int> init_param;
+
+ Param<uint64_t> system_type;
+ Param<uint64_t> system_rev;
+
+ Param<bool> bin;
+ VectorParam<string> binned_fns;
+
+END_DECLARE_SIM_OBJECT_PARAMS(Tru64AlphaSystem)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(Tru64AlphaSystem)
+
+ INIT_PARAM(boot_cpu_frequency, "frequency of the boot cpu"),
+ INIT_PARAM(physmem, "phsyical memory"),
+ INIT_PARAM(kernel, "file that contains the kernel code"),
+ INIT_PARAM(console, "file that contains the console code"),
+ INIT_PARAM(pal, "file that contains palcode"),
+ INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot",
+ "a"),
+ INIT_PARAM_DFLT(readfile, "file to read startup script from", ""),
+ INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0),
+ INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 12),
+ INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 2<<1),
+ INIT_PARAM_DFLT(bin, "is this system to be binned", false),
+ INIT_PARAM(binned_fns, "functions to be broken down and binned")
+
+END_INIT_SIM_OBJECT_PARAMS(Tru64AlphaSystem)
+
+CREATE_SIM_OBJECT(Tru64AlphaSystem)
+{
+ AlphaSystem::Params *p = new AlphaSystem::Params;
+ p->name = getInstanceName();
+ p->boot_cpu_frequency = boot_cpu_frequency;
+ p->physmem = physmem;
+ p->kernel_path = kernel;
+ p->console_path = console;
+ p->palcode = pal;
+ p->boot_osflags = boot_osflags;
+ p->init_param = init_param;
+ p->readfile = readfile;
+ p->system_type = system_type;
+ p->system_rev = system_rev;
+ p->bin = bin;
+ p->binned_fns = binned_fns;
+ p->bin_int = false;
+
+ return new Tru64AlphaSystem(p);
+}
+
+REGISTER_SIM_OBJECT("Tru64AlphaSystem", Tru64AlphaSystem)
diff --git a/src/arch/alpha/tru64/system.hh b/src/arch/alpha/tru64/system.hh
new file mode 100644
index 000000000..0e0cc1bc8
--- /dev/null
+++ b/src/arch/alpha/tru64/system.hh
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ARCH_ALPHA_TRU64_SYSTEM_HH__
+#define __ARCH_ALPHA_TRU64_SYSTEM_HH__
+
+#include "arch/alpha/system.hh"
+#include "arch/isa_traits.hh"
+#include "sim/system.hh"
+
+class ExecContext;
+
+class BreakPCEvent;
+class BadAddrEvent;
+class SkipFuncEvent;
+class PrintfEvent;
+class DebugPrintfEvent;
+class DebugPrintfrEvent;
+class DumpMbufEvent;
+class AlphaArguments;
+
+class Tru64AlphaSystem : public AlphaSystem
+{
+ private:
+#ifdef DEBUG
+ /** Event to halt the simulator if the kernel calls panic() */
+ BreakPCEvent *kernelPanicEvent;
+#endif
+
+ BadAddrEvent *badaddrEvent;
+ SkipFuncEvent *skipPowerStateEvent;
+ SkipFuncEvent *skipScavengeBootEvent;
+ PrintfEvent *printfEvent;
+ DebugPrintfEvent *debugPrintfEvent;
+ DebugPrintfrEvent *debugPrintfrEvent;
+ DumpMbufEvent *dumpMbufEvent;
+
+ public:
+ Tru64AlphaSystem(Params *p);
+ ~Tru64AlphaSystem();
+
+ static void Printf(AlphaArguments args);
+ static void DumpMbuf(AlphaArguments args);
+};
+
+#endif // __ARCH_ALPHA_TRU64_SYSTEM_HH__
diff --git a/src/arch/alpha/tru64/tru64.cc b/src/arch/alpha/tru64/tru64.cc
new file mode 100644
index 000000000..4a3e653c1
--- /dev/null
+++ b/src/arch/alpha/tru64/tru64.cc
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "arch/alpha/tru64/tru64.hh"
+
+// open(2) flags translation table
+OpenFlagTransTable AlphaTru64::openFlagTable[] = {
+#ifdef _MSC_VER
+ { AlphaTru64::TGT_O_RDONLY, _O_RDONLY },
+ { AlphaTru64::TGT_O_WRONLY, _O_WRONLY },
+ { AlphaTru64::TGT_O_RDWR, _O_RDWR },
+ { AlphaTru64::TGT_O_APPEND, _O_APPEND },
+ { AlphaTru64::TGT_O_CREAT, _O_CREAT },
+ { AlphaTru64::TGT_O_TRUNC, _O_TRUNC },
+ { AlphaTru64::TGT_O_EXCL, _O_EXCL },
+#ifdef _O_NONBLOCK
+ { AlphaTru64::TGT_O_NONBLOCK, _O_NONBLOCK },
+#endif
+#ifdef _O_NOCTTY
+ { AlphaTru64::TGT_O_NOCTTY, _O_NOCTTY },
+#endif
+#ifdef _O_SYNC
+ { AlphaTru64::TGT_O_SYNC, _O_SYNC },
+#endif
+#else /* !_MSC_VER */
+ { AlphaTru64::TGT_O_RDONLY, O_RDONLY },
+ { AlphaTru64::TGT_O_WRONLY, O_WRONLY },
+ { AlphaTru64::TGT_O_RDWR, O_RDWR },
+ { AlphaTru64::TGT_O_APPEND, O_APPEND },
+ { AlphaTru64::TGT_O_CREAT, O_CREAT },
+ { AlphaTru64::TGT_O_TRUNC, O_TRUNC },
+ { AlphaTru64::TGT_O_EXCL, O_EXCL },
+ { AlphaTru64::TGT_O_NONBLOCK, O_NONBLOCK },
+ { AlphaTru64::TGT_O_NOCTTY, O_NOCTTY },
+#ifdef O_SYNC
+ { AlphaTru64::TGT_O_SYNC, O_SYNC },
+#endif
+#endif /* _MSC_VER */
+};
+
+const int AlphaTru64::NUM_OPEN_FLAGS =
+ (sizeof(AlphaTru64::openFlagTable)/sizeof(AlphaTru64::openFlagTable[0]));
+
+
+
diff --git a/src/arch/alpha/tru64/tru64.hh b/src/arch/alpha/tru64/tru64.hh
new file mode 100644
index 000000000..19343ba23
--- /dev/null
+++ b/src/arch/alpha/tru64/tru64.hh
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ALPHA_ALPHA_TRU64_HH
+#define __ALPHA_ALPHA_TRU64_HH
+
+#include "kern/tru64/tru64.hh"
+
+class AlphaTru64 : public Tru64
+{
+
+ public:
+ /// This table maps the target open() flags to the corresponding
+ /// host open() flags.
+ static OpenFlagTransTable openFlagTable[];
+
+ /// Number of entries in openFlagTable[].
+ static const int NUM_OPEN_FLAGS;
+
+ //@{
+ /// open(2) flag values.
+ static const int TGT_O_RDONLY = 00000000; //!< O_RDONLY
+ static const int TGT_O_WRONLY = 00000001; //!< O_WRONLY
+ static const int TGT_O_RDWR = 00000002; //!< O_RDWR
+ static const int TGT_O_NONBLOCK = 00000004; //!< O_NONBLOCK
+ static const int TGT_O_APPEND = 00000010; //!< O_APPEND
+ static const int TGT_O_CREAT = 00001000; //!< O_CREAT
+ static const int TGT_O_TRUNC = 00002000; //!< O_TRUNC
+ static const int TGT_O_EXCL = 00004000; //!< O_EXCL
+ static const int TGT_O_NOCTTY = 00010000; //!< O_NOCTTY
+ static const int TGT_O_SYNC = 00040000; //!< O_SYNC
+ static const int TGT_O_DRD = 00100000; //!< O_DRD
+ static const int TGT_O_DIRECTIO = 00200000; //!< O_DIRECTIO
+ static const int TGT_O_CACHE = 00400000; //!< O_CACHE
+ static const int TGT_O_DSYNC = 02000000; //!< O_DSYNC
+ static const int TGT_O_RSYNC = 04000000; //!< O_RSYNC
+ //@}
+
+ /// For mmap().
+ static const unsigned TGT_MAP_ANONYMOUS = 0x10;
+
+ //@{
+ /// For getsysinfo().
+ static const unsigned GSI_PLATFORM_NAME = 103; //!< platform name as string
+ static const unsigned GSI_CPU_INFO = 59; //!< CPU information
+ static const unsigned GSI_PROC_TYPE = 60; //!< get proc_type
+ static const unsigned GSI_MAX_CPU = 30; //!< max # cpu's on this machine
+ static const unsigned GSI_CPUS_IN_BOX = 55; //!< number of CPUs in system
+ static const unsigned GSI_PHYSMEM = 19; //!< Physical memory in KB
+ static const unsigned GSI_CLK_TCK = 42; //!< clock freq in Hz
+ //@}
+
+ //@{
+ /// For getrusage().
+ static const int TGT_RUSAGE_THREAD = 1;
+ static const int TGT_RUSAGE_SELF = 0;
+ static const int TGT_RUSAGE_CHILDREN = -1;
+ //@}
+
+ //@{
+ /// For setsysinfo().
+ static const unsigned SSI_IEEE_FP_CONTROL = 14; //!< ieee_set_fp_control()
+ //@}
+
+ //@{
+ /// ioctl() command codes.
+ static const unsigned TIOCGETP = 0x40067408;
+ static const unsigned TIOCSETP = 0x80067409;
+ static const unsigned TIOCSETN = 0x8006740a;
+ static const unsigned TIOCSETC = 0x80067411;
+ static const unsigned TIOCGETC = 0x40067412;
+ static const unsigned FIONREAD = 0x4004667f;
+ static const unsigned TIOCISATTY = 0x2000745e;
+ static const unsigned TIOCGETS = 0x402c7413;
+ static const unsigned TIOCGETA = 0x40127417;
+ //@}
+
+ //@{
+ /// For table().
+ static const int TBL_SYSINFO = 12;
+ //@}
+
+ /// Resource enumeration for getrlimit().
+ enum rlimit_resources {
+ TGT_RLIMIT_CPU = 0,
+ TGT_RLIMIT_FSIZE = 1,
+ TGT_RLIMIT_DATA = 2,
+ TGT_RLIMIT_STACK = 3,
+ TGT_RLIMIT_CORE = 4,
+ TGT_RLIMIT_RSS = 5,
+ TGT_RLIMIT_NOFILE = 6,
+ TGT_RLIMIT_AS = 7,
+ TGT_RLIMIT_VMEM = 7,
+ TGT_RLIMIT_NPROC = 8,
+ TGT_RLIMIT_MEMLOCK = 9,
+ TGT_RLIMIT_LOCKS = 10
+ };
+};
+
+
+
+#endif
diff --git a/src/arch/alpha/types.hh b/src/arch/alpha/types.hh
new file mode 100644
index 000000000..d4cb482d8
--- /dev/null
+++ b/src/arch/alpha/types.hh
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ARCH_ALPHA_TYPES_HH__
+#define __ARCH_ALPHA_TYPES_HH__
+
+#include "sim/host.hh"
+
+namespace AlphaISA
+{
+
+ typedef uint32_t MachInst;
+ typedef uint64_t ExtMachInst;
+ typedef uint8_t RegIndex;
+
+ typedef uint64_t IntReg;
+
+ // floating point register file entry type
+ typedef double FloatReg;
+ typedef uint64_t FloatRegBits;
+
+ // control register file contents
+ typedef uint64_t MiscReg;
+
+ typedef union {
+ IntReg intreg;
+ FloatReg fpreg;
+ MiscReg ctrlreg;
+ } AnyReg;
+
+ enum annotes {
+ ANNOTE_NONE = 0,
+ // An impossible number for instruction annotations
+ ITOUCH_ANNOTE = 0xffffffff,
+ };
+
+} // namespace AlphaISA
+
+#endif
diff --git a/src/arch/alpha/utility.hh b/src/arch/alpha/utility.hh
new file mode 100644
index 000000000..6cc916307
--- /dev/null
+++ b/src/arch/alpha/utility.hh
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ARCH_ALPHA_UTILITY_HH__
+#define __ARCH_ALPHA_UTILITY_HH__
+
+#include "config/full_system.hh"
+#include "arch/alpha/types.hh"
+#include "arch/alpha/constants.hh"
+#include "arch/alpha/regfile.hh"
+#include "base/misc.hh"
+
+namespace AlphaISA
+{
+
+ static inline ExtMachInst
+ makeExtMI(MachInst inst, const uint64_t &pc) {
+#if FULL_SYSTEM
+ ExtMachInst ext_inst = inst;
+ if (pc && 0x1)
+ return ext_inst|=(static_cast<ExtMachInst>(pc & 0x1) << 32);
+ else
+ return ext_inst;
+#else
+ return ExtMachInst(inst);
+#endif
+ }
+
+ inline bool isCallerSaveIntegerRegister(unsigned int reg) {
+ panic("register classification not implemented");
+ return (reg >= 1 && reg <= 8 || reg >= 22 && reg <= 25 || reg == 27);
+ }
+
+ inline bool isCalleeSaveIntegerRegister(unsigned int reg) {
+ panic("register classification not implemented");
+ return (reg >= 9 && reg <= 15);
+ }
+
+ inline bool isCallerSaveFloatRegister(unsigned int reg) {
+ panic("register classification not implemented");
+ return false;
+ }
+
+ inline bool isCalleeSaveFloatRegister(unsigned int reg) {
+ panic("register classification not implemented");
+ return false;
+ }
+
+ inline Addr alignAddress(const Addr &addr,
+ unsigned int nbytes) {
+ return (addr & ~(nbytes - 1));
+ }
+
+ // Instruction address compression hooks
+ inline Addr realPCToFetchPC(const Addr &addr) {
+ return addr;
+ }
+
+ inline Addr fetchPCToRealPC(const Addr &addr) {
+ return addr;
+ }
+
+ // the size of "fetched" instructions (not necessarily the size
+ // of real instructions for PISA)
+ inline size_t fetchInstSize() {
+ return sizeof(MachInst);
+ }
+
+ inline MachInst makeRegisterCopy(int dest, int src) {
+ panic("makeRegisterCopy not implemented");
+ return 0;
+ }
+
+ // Machine operations
+
+ void saveMachineReg(AnyReg &savereg, const RegFile &reg_file,
+ int regnum);
+
+ void restoreMachineReg(RegFile &regs, const AnyReg &reg,
+ int regnum);
+
+ /**
+ * Function to insure ISA semantics about 0 registers.
+ * @param xc The execution context.
+ */
+ template <class XC>
+ void zeroRegisters(XC *xc);
+
+#if FULL_SYSTEM
+ // Alpha IPR register accessors
+ inline bool PcPAL(Addr addr) { return addr & 0x1; }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Translation stuff
+ //
+
+ inline Addr PteAddr(Addr a) { return (a & PteMask) << PteShift; }
+
+ // User Virtual
+ inline bool IsUSeg(Addr a) { return USegBase <= a && a <= USegEnd; }
+
+ // Kernel Direct Mapped
+ inline bool IsK0Seg(Addr a) { return K0SegBase <= a && a <= K0SegEnd; }
+ inline Addr K0Seg2Phys(Addr addr) { return addr & ~K0SegBase; }
+
+ // Kernel Virtual
+ inline bool IsK1Seg(Addr a) { return K1SegBase <= a && a <= K1SegEnd; }
+
+ inline Addr
+ TruncPage(Addr addr)
+ { return addr & ~(PageBytes - 1); }
+
+ inline Addr
+ RoundPage(Addr addr)
+ { return (addr + PageBytes - 1) & ~(PageBytes - 1); }
+
+ void initCPU(ExecContext *xc, int cpuId);
+ void initIPRs(ExecContext *xc, int cpuId);
+
+ /**
+ * Function to check for and process any interrupts.
+ * @param xc The execution context.
+ */
+ template <class XC>
+ void processInterrupts(XC *xc);
+#endif
+
+} // namespace AlphaISA
+
+#endif
diff --git a/src/arch/alpha/vtophys.cc b/src/arch/alpha/vtophys.cc
new file mode 100644
index 000000000..41e9b80a3
--- /dev/null
+++ b/src/arch/alpha/vtophys.cc
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string>
+
+#include "arch/alpha/ev5.hh"
+#include "arch/alpha/vtophys.hh"
+#include "base/chunk_generator.hh"
+#include "base/trace.hh"
+#include "cpu/exec_context.hh"
+#include "mem/vport.hh"
+
+using namespace std;
+using namespace AlphaISA;
+
+AlphaISA::PageTableEntry
+AlphaISA::kernel_pte_lookup(FunctionalPort *mem, Addr ptbr, AlphaISA::VAddr vaddr)
+{
+ Addr level1_pte = ptbr + vaddr.level1();
+ AlphaISA::PageTableEntry level1 = mem->read<uint64_t>(level1_pte);
+ if (!level1.valid()) {
+ DPRINTF(VtoPhys, "level 1 PTE not valid, va = %#\n", vaddr);
+ return 0;
+ }
+
+ Addr level2_pte = level1.paddr() + vaddr.level2();
+ AlphaISA::PageTableEntry level2 = mem->read<uint64_t>(level2_pte);
+ if (!level2.valid()) {
+ DPRINTF(VtoPhys, "level 2 PTE not valid, va = %#x\n", vaddr);
+ return 0;
+ }
+
+ Addr level3_pte = level2.paddr() + vaddr.level3();
+ AlphaISA::PageTableEntry level3 = mem->read<uint64_t>(level3_pte);
+ if (!level3.valid()) {
+ DPRINTF(VtoPhys, "level 3 PTE not valid, va = %#x\n", vaddr);
+ return 0;
+ }
+ return level3;
+}
+
+Addr
+AlphaISA::vtophys(Addr vaddr)
+{
+ Addr paddr = 0;
+ if (AlphaISA::IsUSeg(vaddr))
+ DPRINTF(VtoPhys, "vtophys: invalid vaddr %#x", vaddr);
+ else if (AlphaISA::IsK0Seg(vaddr))
+ paddr = AlphaISA::K0Seg2Phys(vaddr);
+ else
+ panic("vtophys: ptbr is not set on virtual lookup");
+
+ DPRINTF(VtoPhys, "vtophys(%#x) -> %#x\n", vaddr, paddr);
+
+ return paddr;
+}
+
+Addr
+AlphaISA::vtophys(ExecContext *xc, Addr addr)
+{
+ AlphaISA::VAddr vaddr = addr;
+ Addr ptbr = xc->readMiscReg(AlphaISA::IPR_PALtemp20);
+ Addr paddr = 0;
+ //@todo Andrew couldn't remember why he commented some of this code
+ //so I put it back in. Perhaps something to do with gdb debugging?
+ if (AlphaISA::PcPAL(vaddr) && (vaddr < EV5::PalMax)) {
+ paddr = vaddr & ~ULL(1);
+ } else {
+ if (AlphaISA::IsK0Seg(vaddr)) {
+ paddr = AlphaISA::K0Seg2Phys(vaddr);
+ } else if (!ptbr) {
+ paddr = vaddr;
+ } else {
+ AlphaISA::PageTableEntry pte =
+ kernel_pte_lookup(xc->getPhysPort(), ptbr, vaddr);
+ if (pte.valid())
+ paddr = pte.paddr() | vaddr.offset();
+ }
+ }
+
+
+ DPRINTF(VtoPhys, "vtophys(%#x) -> %#x\n", vaddr, paddr);
+
+ return paddr;
+}
+
+
+void
+AlphaISA::CopyOut(ExecContext *xc, void *dest, Addr src, size_t cplen)
+{
+ uint8_t *dst = (uint8_t *)dest;
+ VirtualPort *vp = xc->getVirtPort(xc);
+
+ vp->readBlob(src, dst, cplen);
+
+ xc->delVirtPort(vp);
+
+}
+
+void
+AlphaISA::CopyIn(ExecContext *xc, Addr dest, void *source, size_t cplen)
+{
+ uint8_t *src = (uint8_t *)source;
+ VirtualPort *vp = xc->getVirtPort(xc);
+
+ vp->writeBlob(dest, src, cplen);
+
+ xc->delVirtPort(vp);
+}
+
+void
+AlphaISA::CopyStringOut(ExecContext *xc, char *dst, Addr vaddr, size_t maxlen)
+{
+ int len = 0;
+ VirtualPort *vp = xc->getVirtPort(xc);
+
+ do {
+ vp->readBlob(vaddr++, (uint8_t*)dst++, 1);
+ len++;
+ } while (len < maxlen && dst[len] != 0 );
+
+ xc->delVirtPort(vp);
+ dst[len] = 0;
+}
+
+void
+AlphaISA::CopyStringIn(ExecContext *xc, char *src, Addr vaddr)
+{
+ VirtualPort *vp = xc->getVirtPort(xc);
+ for (ChunkGenerator gen(vaddr, strlen(src), AlphaISA::PageBytes); !gen.done();
+ gen.next())
+ {
+ vp->writeBlob(gen.addr(), (uint8_t*)src, gen.size());
+ src += gen.size();
+ }
+ xc->delVirtPort(vp);
+}
diff --git a/src/arch/alpha/vtophys.hh b/src/arch/alpha/vtophys.hh
new file mode 100644
index 000000000..7ab14bc5b
--- /dev/null
+++ b/src/arch/alpha/vtophys.hh
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ARCH_ALPHA_VTOPHYS_H__
+#define __ARCH_ALPHA_VTOPHYS_H__
+
+#include "arch/alpha/isa_traits.hh"
+
+class ExecContext;
+class FunctionalPort;
+
+namespace AlphaISA {
+
+PageTableEntry
+kernel_pte_lookup(FunctionalPort *mem, Addr ptbr, AlphaISA::VAddr vaddr);
+
+Addr vtophys(Addr vaddr);
+Addr vtophys(ExecContext *xc, Addr vaddr);
+
+void CopyOut(ExecContext *xc, void *dst, Addr src, size_t len);
+void CopyIn(ExecContext *xc, Addr dst, void *src, size_t len);
+void CopyStringOut(ExecContext *xc, char *dst, Addr vaddr, size_t maxlen);
+void CopyStringIn(ExecContext *xc, char *src, Addr vaddr);
+
+};
+#endif // __ARCH_ALPHA_VTOPHYS_H__
+
diff --git a/src/arch/isa_parser.py b/src/arch/isa_parser.py
new file mode 100755
index 000000000..c0758da50
--- /dev/null
+++ b/src/arch/isa_parser.py
@@ -0,0 +1,1810 @@
+# Copyright (c) 2003-2005 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import os
+import sys
+import re
+import string
+import traceback
+# get type names
+from types import *
+
+# Prepend the directory where the PLY lex & yacc modules are found
+# to the search path. Assumes we're compiling in a subdirectory
+# of 'build' in the current tree.
+sys.path[0:0] = [os.environ['M5_PLY']]
+
+import lex
+import yacc
+
+#####################################################################
+#
+# Lexer
+#
+# The PLY lexer module takes two things as input:
+# - A list of token names (the string list 'tokens')
+# - A regular expression describing a match for each token. The
+# regexp for token FOO can be provided in two ways:
+# - as a string variable named t_FOO
+# - as the doc string for a function named t_FOO. In this case,
+# the function is also executed, allowing an action to be
+# associated with each token match.
+#
+#####################################################################
+
+# Reserved words. These are listed separately as they are matched
+# using the same regexp as generic IDs, but distinguished in the
+# t_ID() function. The PLY documentation suggests this approach.
+reserved = (
+ 'BITFIELD', 'DECODE', 'DECODER', 'DEFAULT', 'DEF', 'EXEC', 'FORMAT',
+ 'HEADER', 'LET', 'NAMESPACE', 'OPERAND_TYPES', 'OPERANDS',
+ 'OUTPUT', 'SIGNED', 'TEMPLATE'
+ )
+
+# List of tokens. The lex module requires this.
+tokens = reserved + (
+ # identifier
+ 'ID',
+
+ # integer literal
+ 'INTLIT',
+
+ # string literal
+ 'STRLIT',
+
+ # code literal
+ 'CODELIT',
+
+ # ( ) [ ] { } < > , ; : :: *
+ 'LPAREN', 'RPAREN',
+ 'LBRACKET', 'RBRACKET',
+ 'LBRACE', 'RBRACE',
+ 'LESS', 'GREATER', 'EQUALS',
+ 'COMMA', 'SEMI', 'COLON', 'DBLCOLON',
+ 'ASTERISK',
+
+ # C preprocessor directives
+ 'CPPDIRECTIVE'
+
+# The following are matched but never returned. commented out to
+# suppress PLY warning
+ # newfile directive
+# 'NEWFILE',
+
+ # endfile directive
+# 'ENDFILE'
+)
+
+# Regular expressions for token matching
+t_LPAREN = r'\('
+t_RPAREN = r'\)'
+t_LBRACKET = r'\['
+t_RBRACKET = r'\]'
+t_LBRACE = r'\{'
+t_RBRACE = r'\}'
+t_LESS = r'\<'
+t_GREATER = r'\>'
+t_EQUALS = r'='
+t_COMMA = r','
+t_SEMI = r';'
+t_COLON = r':'
+t_DBLCOLON = r'::'
+t_ASTERISK = r'\*'
+
+# Identifiers and reserved words
+reserved_map = { }
+for r in reserved:
+ reserved_map[r.lower()] = r
+
+def t_ID(t):
+ r'[A-Za-z_]\w*'
+ t.type = reserved_map.get(t.value,'ID')
+ return t
+
+# Integer literal
+def t_INTLIT(t):
+ r'(0x[\da-fA-F]+)|\d+'
+ try:
+ t.value = int(t.value,0)
+ except ValueError:
+ error(t.lineno, 'Integer value "%s" too large' % t.value)
+ t.value = 0
+ return t
+
+# String literal. Note that these use only single quotes, and
+# can span multiple lines.
+def t_STRLIT(t):
+ r"(?m)'([^'])+'"
+ # strip off quotes
+ t.value = t.value[1:-1]
+ t.lineno += t.value.count('\n')
+ return t
+
+
+# "Code literal"... like a string literal, but delimiters are
+# '{{' and '}}' so they get formatted nicely under emacs c-mode
+def t_CODELIT(t):
+ r"(?m)\{\{([^\}]|}(?!\}))+\}\}"
+ # strip off {{ & }}
+ t.value = t.value[2:-2]
+ t.lineno += t.value.count('\n')
+ return t
+
+def t_CPPDIRECTIVE(t):
+ r'^\#[^\#].*\n'
+ t.lineno += t.value.count('\n')
+ return t
+
+def t_NEWFILE(t):
+ r'^\#\#newfile\s+"[\w/.-]*"'
+ fileNameStack.push((t.value[11:-1], t.lineno))
+ t.lineno = 0
+
+def t_ENDFILE(t):
+ r'^\#\#endfile'
+ (old_filename, t.lineno) = fileNameStack.pop()
+
+#
+# The functions t_NEWLINE, t_ignore, and t_error are
+# special for the lex module.
+#
+
+# Newlines
+def t_NEWLINE(t):
+ r'\n+'
+ t.lineno += t.value.count('\n')
+
+# Comments
+def t_comment(t):
+ r'//.*'
+
+# Completely ignored characters
+t_ignore = ' \t\x0c'
+
+# Error handler
+def t_error(t):
+ error(t.lineno, "illegal character '%s'" % t.value[0])
+ t.skip(1)
+
+# Build the lexer
+lex.lex()
+
+#####################################################################
+#
+# Parser
+#
+# Every function whose name starts with 'p_' defines a grammar rule.
+# The rule is encoded in the function's doc string, while the
+# function body provides the action taken when the rule is matched.
+# The argument to each function is a list of the values of the
+# rule's symbols: t[0] for the LHS, and t[1..n] for the symbols
+# on the RHS. For tokens, the value is copied from the t.value
+# attribute provided by the lexer. For non-terminals, the value
+# is assigned by the producing rule; i.e., the job of the grammar
+# rule function is to set the value for the non-terminal on the LHS
+# (by assigning to t[0]).
+#####################################################################
+
+# The LHS of the first grammar rule is used as the start symbol
+# (in this case, 'specification'). Note that this rule enforces
+# that there will be exactly one namespace declaration, with 0 or more
+# global defs/decls before and after it. The defs & decls before
+# the namespace decl will be outside the namespace; those after
+# will be inside. The decoder function is always inside the namespace.
+def p_specification(t):
+ 'specification : opt_defs_and_outputs name_decl opt_defs_and_outputs decode_block'
+ global_code = t[1]
+ isa_name = t[2]
+ namespace = isa_name + "Inst"
+ # wrap the decode block as a function definition
+ t[4].wrap_decode_block('''
+StaticInstPtr
+%(isa_name)s::decodeInst(%(isa_name)s::ExtMachInst machInst)
+{
+ using namespace %(namespace)s;
+''' % vars(), '}')
+ # both the latter output blocks and the decode block are in the namespace
+ namespace_code = t[3] + t[4]
+ # pass it all back to the caller of yacc.parse()
+ t[0] = (isa_name, namespace, global_code, namespace_code)
+
+# ISA name declaration looks like "namespace <foo>;"
+def p_name_decl(t):
+ 'name_decl : NAMESPACE ID SEMI'
+ t[0] = t[2]
+
+# 'opt_defs_and_outputs' is a possibly empty sequence of
+# def and/or output statements.
+def p_opt_defs_and_outputs_0(t):
+ 'opt_defs_and_outputs : empty'
+ t[0] = GenCode()
+
+def p_opt_defs_and_outputs_1(t):
+ 'opt_defs_and_outputs : defs_and_outputs'
+ t[0] = t[1]
+
+def p_defs_and_outputs_0(t):
+ 'defs_and_outputs : def_or_output'
+ t[0] = t[1]
+
+def p_defs_and_outputs_1(t):
+ 'defs_and_outputs : defs_and_outputs def_or_output'
+ t[0] = t[1] + t[2]
+
+# The list of possible definition/output statements.
+def p_def_or_output(t):
+ '''def_or_output : def_format
+ | def_bitfield
+ | def_template
+ | def_operand_types
+ | def_operands
+ | output_header
+ | output_decoder
+ | output_exec
+ | global_let'''
+ t[0] = t[1]
+
+# Output blocks 'output <foo> {{...}}' (C++ code blocks) are copied
+# directly to the appropriate output section.
+
+
+# Protect any non-dict-substitution '%'s in a format string
+# (i.e. those not followed by '(')
+def protect_non_subst_percents(s):
+ return re.sub(r'%(?!\()', '%%', s)
+
+# Massage output block by substituting in template definitions and bit
+# operators. We handle '%'s embedded in the string that don't
+# indicate template substitutions (or CPU-specific symbols, which get
+# handled in GenCode) by doubling them first so that the format
+# operation will reduce them back to single '%'s.
+def process_output(s):
+ s = protect_non_subst_percents(s)
+ # protects cpu-specific symbols too
+ s = protect_cpu_symbols(s)
+ return substBitOps(s % templateMap)
+
+def p_output_header(t):
+ 'output_header : OUTPUT HEADER CODELIT SEMI'
+ t[0] = GenCode(header_output = process_output(t[3]))
+
+def p_output_decoder(t):
+ 'output_decoder : OUTPUT DECODER CODELIT SEMI'
+ t[0] = GenCode(decoder_output = process_output(t[3]))
+
+def p_output_exec(t):
+ 'output_exec : OUTPUT EXEC CODELIT SEMI'
+ t[0] = GenCode(exec_output = process_output(t[3]))
+
+# global let blocks 'let {{...}}' (Python code blocks) are executed
+# directly when seen. Note that these execute in a special variable
+# context 'exportContext' to prevent the code from polluting this
+# script's namespace.
+def p_global_let(t):
+ 'global_let : LET CODELIT SEMI'
+ updateExportContext()
+ try:
+ exec fixPythonIndentation(t[2]) in exportContext
+ except Exception, exc:
+ error(t.lineno(1),
+ 'error: %s in global let block "%s".' % (exc, t[2]))
+ t[0] = GenCode() # contributes nothing to the output C++ file
+
+# Define the mapping from operand type extensions to C++ types and bit
+# widths (stored in operandTypeMap).
+def p_def_operand_types(t):
+ 'def_operand_types : DEF OPERAND_TYPES CODELIT SEMI'
+ try:
+ userDict = eval('{' + t[3] + '}')
+ except Exception, exc:
+ error(t.lineno(1),
+ 'error: %s in def operand_types block "%s".' % (exc, t[3]))
+ buildOperandTypeMap(userDict, t.lineno(1))
+ t[0] = GenCode() # contributes nothing to the output C++ file
+
+# Define the mapping from operand names to operand classes and other
+# traits. Stored in operandNameMap.
+def p_def_operands(t):
+ 'def_operands : DEF OPERANDS CODELIT SEMI'
+ if not globals().has_key('operandTypeMap'):
+ error(t.lineno(1),
+ 'error: operand types must be defined before operands')
+ try:
+ userDict = eval('{' + t[3] + '}')
+ except Exception, exc:
+ error(t.lineno(1),
+ 'error: %s in def operands block "%s".' % (exc, t[3]))
+ buildOperandNameMap(userDict, t.lineno(1))
+ t[0] = GenCode() # contributes nothing to the output C++ file
+
+# A bitfield definition looks like:
+# 'def [signed] bitfield <ID> [<first>:<last>]'
+# This generates a preprocessor macro in the output file.
+def p_def_bitfield_0(t):
+ 'def_bitfield : DEF opt_signed BITFIELD ID LESS INTLIT COLON INTLIT GREATER SEMI'
+ expr = 'bits(machInst, %2d, %2d)' % (t[6], t[8])
+ if (t[2] == 'signed'):
+ expr = 'sext<%d>(%s)' % (t[6] - t[8] + 1, expr)
+ hash_define = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr)
+ t[0] = GenCode(header_output = hash_define)
+
+# alternate form for single bit: 'def [signed] bitfield <ID> [<bit>]'
+def p_def_bitfield_1(t):
+ 'def_bitfield : DEF opt_signed BITFIELD ID LESS INTLIT GREATER SEMI'
+ expr = 'bits(machInst, %2d, %2d)' % (t[6], t[6])
+ if (t[2] == 'signed'):
+ expr = 'sext<%d>(%s)' % (1, expr)
+ hash_define = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr)
+ t[0] = GenCode(header_output = hash_define)
+
+def p_opt_signed_0(t):
+ 'opt_signed : SIGNED'
+ t[0] = t[1]
+
+def p_opt_signed_1(t):
+ 'opt_signed : empty'
+ t[0] = ''
+
+# Global map variable to hold templates
+templateMap = {}
+
+def p_def_template(t):
+ 'def_template : DEF TEMPLATE ID CODELIT SEMI'
+ templateMap[t[3]] = Template(t[4])
+ t[0] = GenCode()
+
+# An instruction format definition looks like
+# "def format <fmt>(<params>) {{...}};"
+def p_def_format(t):
+ 'def_format : DEF FORMAT ID LPAREN param_list RPAREN CODELIT SEMI'
+ (id, params, code) = (t[3], t[5], t[7])
+ defFormat(id, params, code, t.lineno(1))
+ t[0] = GenCode()
+
+# The formal parameter list for an instruction format is a possibly
+# empty list of comma-separated parameters. Positional (standard,
+# non-keyword) parameters must come first, followed by keyword
+# parameters, followed by a '*foo' parameter that gets excess
+# positional arguments (as in Python). Each of these three parameter
+# categories is optional.
+#
+# Note that we do not support the '**foo' parameter for collecting
+# otherwise undefined keyword args. Otherwise the parameter list is
+# (I believe) identical to what is supported in Python.
+#
+# The param list generates a tuple, where the first element is a list of
+# the positional params and the second element is a dict containing the
+# keyword params.
+def p_param_list_0(t):
+ 'param_list : positional_param_list COMMA nonpositional_param_list'
+ t[0] = t[1] + t[3]
+
+def p_param_list_1(t):
+ '''param_list : positional_param_list
+ | nonpositional_param_list'''
+ t[0] = t[1]
+
+def p_positional_param_list_0(t):
+ 'positional_param_list : empty'
+ t[0] = []
+
+def p_positional_param_list_1(t):
+ 'positional_param_list : ID'
+ t[0] = [t[1]]
+
+def p_positional_param_list_2(t):
+ 'positional_param_list : positional_param_list COMMA ID'
+ t[0] = t[1] + [t[3]]
+
+def p_nonpositional_param_list_0(t):
+ 'nonpositional_param_list : keyword_param_list COMMA excess_args_param'
+ t[0] = t[1] + t[3]
+
+def p_nonpositional_param_list_1(t):
+ '''nonpositional_param_list : keyword_param_list
+ | excess_args_param'''
+ t[0] = t[1]
+
+def p_keyword_param_list_0(t):
+ 'keyword_param_list : keyword_param'
+ t[0] = [t[1]]
+
+def p_keyword_param_list_1(t):
+ 'keyword_param_list : keyword_param_list COMMA keyword_param'
+ t[0] = t[1] + [t[3]]
+
+def p_keyword_param(t):
+ 'keyword_param : ID EQUALS expr'
+ t[0] = t[1] + ' = ' + t[3].__repr__()
+
+def p_excess_args_param(t):
+ 'excess_args_param : ASTERISK ID'
+ # Just concatenate them: '*ID'. Wrap in list to be consistent
+ # with positional_param_list and keyword_param_list.
+ t[0] = [t[1] + t[2]]
+
+# End of format definition-related rules.
+##############
+
+#
+# A decode block looks like:
+# decode <field1> [, <field2>]* [default <inst>] { ... }
+#
+def p_decode_block(t):
+ 'decode_block : DECODE ID opt_default LBRACE decode_stmt_list RBRACE'
+ default_defaults = defaultStack.pop()
+ codeObj = t[5]
+ # use the "default defaults" only if there was no explicit
+ # default statement in decode_stmt_list
+ if not codeObj.has_decode_default:
+ codeObj += default_defaults
+ codeObj.wrap_decode_block('switch (%s) {\n' % t[2], '}\n')
+ t[0] = codeObj
+
+# The opt_default statement serves only to push the "default defaults"
+# onto defaultStack. This value will be used by nested decode blocks,
+# and used and popped off when the current decode_block is processed
+# (in p_decode_block() above).
+def p_opt_default_0(t):
+ 'opt_default : empty'
+ # no default specified: reuse the one currently at the top of the stack
+ defaultStack.push(defaultStack.top())
+ # no meaningful value returned
+ t[0] = None
+
+def p_opt_default_1(t):
+ 'opt_default : DEFAULT inst'
+ # push the new default
+ codeObj = t[2]
+ codeObj.wrap_decode_block('\ndefault:\n', 'break;\n')
+ defaultStack.push(codeObj)
+ # no meaningful value returned
+ t[0] = None
+
+def p_decode_stmt_list_0(t):
+ 'decode_stmt_list : decode_stmt'
+ t[0] = t[1]
+
+def p_decode_stmt_list_1(t):
+ 'decode_stmt_list : decode_stmt decode_stmt_list'
+ if (t[1].has_decode_default and t[2].has_decode_default):
+ error(t.lineno(1), 'Two default cases in decode block')
+ t[0] = t[1] + t[2]
+
+#
+# Decode statement rules
+#
+# There are four types of statements allowed in a decode block:
+# 1. Format blocks 'format <foo> { ... }'
+# 2. Nested decode blocks
+# 3. Instruction definitions.
+# 4. C preprocessor directives.
+
+
+# Preprocessor directives found in a decode statement list are passed
+# through to the output, replicated to all of the output code
+# streams. This works well for ifdefs, so we can ifdef out both the
+# declarations and the decode cases generated by an instruction
+# definition. Handling them as part of the grammar makes it easy to
+# keep them in the right place with respect to the code generated by
+# the other statements.
+def p_decode_stmt_cpp(t):
+ 'decode_stmt : CPPDIRECTIVE'
+ t[0] = GenCode(t[1], t[1], t[1], t[1])
+
+# A format block 'format <foo> { ... }' sets the default instruction
+# format used to handle instruction definitions inside the block.
+# This format can be overridden by using an explicit format on the
+# instruction definition or with a nested format block.
+def p_decode_stmt_format(t):
+ 'decode_stmt : FORMAT push_format_id LBRACE decode_stmt_list RBRACE'
+ # The format will be pushed on the stack when 'push_format_id' is
+ # processed (see below). Once the parser has recognized the full
+ # production (though the right brace), we're done with the format,
+ # so now we can pop it.
+ formatStack.pop()
+ t[0] = t[4]
+
+# This rule exists so we can set the current format (& push the stack)
+# when we recognize the format name part of the format block.
+def p_push_format_id(t):
+ 'push_format_id : ID'
+ try:
+ formatStack.push(formatMap[t[1]])
+ t[0] = ('', '// format %s' % t[1])
+ except KeyError:
+ error(t.lineno(1), 'instruction format "%s" not defined.' % t[1])
+
+# Nested decode block: if the value of the current field matches the
+# specified constant, do a nested decode on some other field.
+def p_decode_stmt_decode(t):
+ 'decode_stmt : case_label COLON decode_block'
+ label = t[1]
+ codeObj = t[3]
+ # just wrap the decoding code from the block as a case in the
+ # outer switch statement.
+ codeObj.wrap_decode_block('\n%s:\n' % label)
+ codeObj.has_decode_default = (label == 'default')
+ t[0] = codeObj
+
+# Instruction definition (finally!).
+def p_decode_stmt_inst(t):
+ 'decode_stmt : case_label COLON inst SEMI'
+ label = t[1]
+ codeObj = t[3]
+ codeObj.wrap_decode_block('\n%s:' % label, 'break;\n')
+ codeObj.has_decode_default = (label == 'default')
+ t[0] = codeObj
+
+# The case label is either a list of one or more constants or 'default'
+def p_case_label_0(t):
+ 'case_label : intlit_list'
+ t[0] = ': '.join(map(lambda a: 'case %#x' % a, t[1]))
+
+def p_case_label_1(t):
+ 'case_label : DEFAULT'
+ t[0] = 'default'
+
+#
+# The constant list for a decode case label must be non-empty, but may have
+# one or more comma-separated integer literals in it.
+#
+def p_intlit_list_0(t):
+ 'intlit_list : INTLIT'
+ t[0] = [t[1]]
+
+def p_intlit_list_1(t):
+ 'intlit_list : intlit_list COMMA INTLIT'
+ t[0] = t[1]
+ t[0].append(t[3])
+
+# Define an instruction using the current instruction format (specified
+# by an enclosing format block).
+# "<mnemonic>(<args>)"
+def p_inst_0(t):
+ 'inst : ID LPAREN arg_list RPAREN'
+ # Pass the ID and arg list to the current format class to deal with.
+ currentFormat = formatStack.top()
+ codeObj = currentFormat.defineInst(t[1], t[3], t.lineno(1))
+ args = ','.join(map(str, t[3]))
+ args = re.sub('(?m)^', '//', args)
+ args = re.sub('^//', '', args)
+ comment = '\n// %s::%s(%s)\n' % (currentFormat.id, t[1], args)
+ codeObj.prepend_all(comment)
+ t[0] = codeObj
+
+# Define an instruction using an explicitly specified format:
+# "<fmt>::<mnemonic>(<args>)"
+def p_inst_1(t):
+ 'inst : ID DBLCOLON ID LPAREN arg_list RPAREN'
+ try:
+ format = formatMap[t[1]]
+ except KeyError:
+ error(t.lineno(1), 'instruction format "%s" not defined.' % t[1])
+ codeObj = format.defineInst(t[3], t[5], t.lineno(1))
+ comment = '\n// %s::%s(%s)\n' % (t[1], t[3], t[5])
+ codeObj.prepend_all(comment)
+ t[0] = codeObj
+
+# The arg list generates a tuple, where the first element is a list of
+# the positional args and the second element is a dict containing the
+# keyword args.
+def p_arg_list_0(t):
+ 'arg_list : positional_arg_list COMMA keyword_arg_list'
+ t[0] = ( t[1], t[3] )
+
+def p_arg_list_1(t):
+ 'arg_list : positional_arg_list'
+ t[0] = ( t[1], {} )
+
+def p_arg_list_2(t):
+ 'arg_list : keyword_arg_list'
+ t[0] = ( [], t[1] )
+
+def p_positional_arg_list_0(t):
+ 'positional_arg_list : empty'
+ t[0] = []
+
+def p_positional_arg_list_1(t):
+ 'positional_arg_list : expr'
+ t[0] = [t[1]]
+
+def p_positional_arg_list_2(t):
+ 'positional_arg_list : positional_arg_list COMMA expr'
+ t[0] = t[1] + [t[3]]
+
+def p_keyword_arg_list_0(t):
+ 'keyword_arg_list : keyword_arg'
+ t[0] = t[1]
+
+def p_keyword_arg_list_1(t):
+ 'keyword_arg_list : keyword_arg_list COMMA keyword_arg'
+ t[0] = t[1]
+ t[0].update(t[3])
+
+def p_keyword_arg(t):
+ 'keyword_arg : ID EQUALS expr'
+ t[0] = { t[1] : t[3] }
+
+#
+# Basic expressions. These constitute the argument values of
+# "function calls" (i.e. instruction definitions in the decode block)
+# and default values for formal parameters of format functions.
+#
+# Right now, these are either strings, integers, or (recursively)
+# lists of exprs (using Python square-bracket list syntax). Note that
+# bare identifiers are trated as string constants here (since there
+# isn't really a variable namespace to refer to).
+#
+def p_expr_0(t):
+ '''expr : ID
+ | INTLIT
+ | STRLIT
+ | CODELIT'''
+ t[0] = t[1]
+
+def p_expr_1(t):
+ '''expr : LBRACKET list_expr RBRACKET'''
+ t[0] = t[2]
+
+def p_list_expr_0(t):
+ 'list_expr : expr'
+ t[0] = [t[1]]
+
+def p_list_expr_1(t):
+ 'list_expr : list_expr COMMA expr'
+ t[0] = t[1] + [t[3]]
+
+def p_list_expr_2(t):
+ 'list_expr : empty'
+ t[0] = []
+
+#
+# Empty production... use in other rules for readability.
+#
+def p_empty(t):
+ 'empty :'
+ pass
+
+# Parse error handler. Note that the argument here is the offending
+# *token*, not a grammar symbol (hence the need to use t.value)
+def p_error(t):
+ if t:
+ error(t.lineno, "syntax error at '%s'" % t.value)
+ else:
+ error(0, "unknown syntax error", True)
+
+# END OF GRAMMAR RULES
+#
+# Now build the parser.
+yacc.yacc()
+
+
+#####################################################################
+#
+# Support Classes
+#
+#####################################################################
+
+# Expand template with CPU-specific references into a dictionary with
+# an entry for each CPU model name. The entry key is the model name
+# and the corresponding value is the template with the CPU-specific
+# refs substituted for that model.
+def expand_cpu_symbols_to_dict(template):
+ # Protect '%'s that don't go with CPU-specific terms
+ t = re.sub(r'%(?!\(CPU_)', '%%', template)
+ result = {}
+ for cpu in cpu_models:
+ result[cpu.name] = t % cpu.strings
+ return result
+
+# *If* the template has CPU-specific references, return a single
+# string containing a copy of the template for each CPU model with the
+# corresponding values substituted in. If the template has no
+# CPU-specific references, it is returned unmodified.
+def expand_cpu_symbols_to_string(template):
+ if template.find('%(CPU_') != -1:
+ return reduce(lambda x,y: x+y,
+ expand_cpu_symbols_to_dict(template).values())
+ else:
+ return template
+
+# Protect CPU-specific references by doubling the corresponding '%'s
+# (in preparation for substituting a different set of references into
+# the template).
+def protect_cpu_symbols(template):
+ return re.sub(r'%(?=\(CPU_)', '%%', template)
+
+###############
+# GenCode class
+#
+# The GenCode class encapsulates generated code destined for various
+# output files. The header_output and decoder_output attributes are
+# strings containing code destined for decoder.hh and decoder.cc
+# respectively. The decode_block attribute contains code to be
+# incorporated in the decode function itself (that will also end up in
+# decoder.cc). The exec_output attribute is a dictionary with a key
+# for each CPU model name; the value associated with a particular key
+# is the string of code for that CPU model's exec.cc file. The
+# has_decode_default attribute is used in the decode block to allow
+# explicit default clauses to override default default clauses.
+
+class GenCode:
+ # Constructor. At this point we substitute out all CPU-specific
+ # symbols. For the exec output, these go into the per-model
+ # dictionary. For all other output types they get collapsed into
+ # a single string.
+ def __init__(self,
+ header_output = '', decoder_output = '', exec_output = '',
+ decode_block = '', has_decode_default = False):
+ self.header_output = expand_cpu_symbols_to_string(header_output)
+ self.decoder_output = expand_cpu_symbols_to_string(decoder_output)
+ if isinstance(exec_output, dict):
+ self.exec_output = exec_output
+ elif isinstance(exec_output, str):
+ # If the exec_output arg is a single string, we replicate
+ # it for each of the CPU models, substituting and
+ # %(CPU_foo)s params appropriately.
+ self.exec_output = expand_cpu_symbols_to_dict(exec_output)
+ self.decode_block = expand_cpu_symbols_to_string(decode_block)
+ self.has_decode_default = has_decode_default
+
+ # Override '+' operator: generate a new GenCode object that
+ # concatenates all the individual strings in the operands.
+ def __add__(self, other):
+ exec_output = {}
+ for cpu in cpu_models:
+ n = cpu.name
+ exec_output[n] = self.exec_output[n] + other.exec_output[n]
+ return GenCode(self.header_output + other.header_output,
+ self.decoder_output + other.decoder_output,
+ exec_output,
+ self.decode_block + other.decode_block,
+ self.has_decode_default or other.has_decode_default)
+
+ # Prepend a string (typically a comment) to all the strings.
+ def prepend_all(self, pre):
+ self.header_output = pre + self.header_output
+ self.decoder_output = pre + self.decoder_output
+ self.decode_block = pre + self.decode_block
+ for cpu in cpu_models:
+ self.exec_output[cpu.name] = pre + self.exec_output[cpu.name]
+
+ # Wrap the decode block in a pair of strings (e.g., 'case foo:'
+ # and 'break;'). Used to build the big nested switch statement.
+ def wrap_decode_block(self, pre, post = ''):
+ self.decode_block = pre + indent(self.decode_block) + post
+
+################
+# Format object.
+#
+# A format object encapsulates an instruction format. It must provide
+# a defineInst() method that generates the code for an instruction
+# definition.
+
+exportContextSymbols = ('InstObjParams', 'CodeBlock',
+ 'makeList', 're', 'string')
+
+exportContext = {}
+
+def updateExportContext():
+ exportContext.update(exportDict(*exportContextSymbols))
+ exportContext.update(templateMap)
+
+def exportDict(*symNames):
+ return dict([(s, eval(s)) for s in symNames])
+
+
+class Format:
+ def __init__(self, id, params, code):
+ # constructor: just save away arguments
+ self.id = id
+ self.params = params
+ label = 'def format ' + id
+ self.user_code = compile(fixPythonIndentation(code), label, 'exec')
+ param_list = string.join(params, ", ")
+ f = '''def defInst(_code, _context, %s):
+ my_locals = vars().copy()
+ exec _code in _context, my_locals
+ return my_locals\n''' % param_list
+ c = compile(f, label + ' wrapper', 'exec')
+ exec c
+ self.func = defInst
+
+ def defineInst(self, name, args, lineno):
+ context = {}
+ updateExportContext()
+ context.update(exportContext)
+ context.update({ 'name': name, 'Name': string.capitalize(name) })
+ try:
+ vars = self.func(self.user_code, context, *args[0], **args[1])
+ except Exception, exc:
+ error(lineno, 'error defining "%s": %s.' % (name, exc))
+ for k in vars.keys():
+ if k not in ('header_output', 'decoder_output',
+ 'exec_output', 'decode_block'):
+ del vars[k]
+ return GenCode(**vars)
+
+# Special null format to catch an implicit-format instruction
+# definition outside of any format block.
+class NoFormat:
+ def __init__(self):
+ self.defaultInst = ''
+
+ def defineInst(self, name, args, lineno):
+ error(lineno,
+ 'instruction definition "%s" with no active format!' % name)
+
+# This dictionary maps format name strings to Format objects.
+formatMap = {}
+
+# Define a new format
+def defFormat(id, params, code, lineno):
+ # make sure we haven't already defined this one
+ if formatMap.get(id, None) != None:
+ error(lineno, 'format %s redefined.' % id)
+ # create new object and store in global map
+ formatMap[id] = Format(id, params, code)
+
+
+##############
+# Stack: a simple stack object. Used for both formats (formatStack)
+# and default cases (defaultStack). Simply wraps a list to give more
+# stack-like syntax and enable initialization with an argument list
+# (as opposed to an argument that's a list).
+
+class Stack(list):
+ def __init__(self, *items):
+ list.__init__(self, items)
+
+ def push(self, item):
+ self.append(item);
+
+ def top(self):
+ return self[-1]
+
+# The global format stack.
+formatStack = Stack(NoFormat())
+
+# The global default case stack.
+defaultStack = Stack( None )
+
+# Global stack that tracks current file and line number.
+# Each element is a tuple (filename, lineno) that records the
+# *current* filename and the line number in the *previous* file where
+# it was included.
+fileNameStack = Stack()
+
+###################
+# Utility functions
+
+#
+# Indent every line in string 's' by two spaces
+# (except preprocessor directives).
+# Used to make nested code blocks look pretty.
+#
+def indent(s):
+ return re.sub(r'(?m)^(?!#)', ' ', s)
+
+#
+# Munge a somewhat arbitrarily formatted piece of Python code
+# (e.g. from a format 'let' block) into something whose indentation
+# will get by the Python parser.
+#
+# The two keys here are that Python will give a syntax error if
+# there's any whitespace at the beginning of the first line, and that
+# all lines at the same lexical nesting level must have identical
+# indentation. Unfortunately the way code literals work, an entire
+# let block tends to have some initial indentation. Rather than
+# trying to figure out what that is and strip it off, we prepend 'if
+# 1:' to make the let code the nested block inside the if (and have
+# the parser automatically deal with the indentation for us).
+#
+# We don't want to do this if (1) the code block is empty or (2) the
+# first line of the block doesn't have any whitespace at the front.
+
+def fixPythonIndentation(s):
+ # get rid of blank lines first
+ s = re.sub(r'(?m)^\s*\n', '', s);
+ if (s != '' and re.match(r'[ \t]', s[0])):
+ s = 'if 1:\n' + s
+ return s
+
+# Error handler. Just call exit. Output formatted to work under
+# Emacs compile-mode. Optional 'print_traceback' arg, if set to True,
+# prints a Python stack backtrace too (can be handy when trying to
+# debug the parser itself).
+def error(lineno, string, print_traceback = False):
+ spaces = ""
+ for (filename, line) in fileNameStack[0:-1]:
+ print spaces + "In file included from " + filename + ":"
+ spaces += " "
+ # Print a Python stack backtrace if requested.
+ if (print_traceback):
+ traceback.print_exc()
+ if lineno != 0:
+ line_str = "%d:" % lineno
+ else:
+ line_str = ""
+ sys.exit(spaces + "%s:%s %s" % (fileNameStack[-1][0], line_str, string))
+
+
+#####################################################################
+#
+# Bitfield Operator Support
+#
+#####################################################################
+
+bitOp1ArgRE = re.compile(r'<\s*(\w+)\s*:\s*>')
+
+bitOpWordRE = re.compile(r'(?<![\w\.])([\w\.]+)<\s*(\w+)\s*:\s*(\w+)\s*>')
+bitOpExprRE = re.compile(r'\)<\s*(\w+)\s*:\s*(\w+)\s*>')
+
+def substBitOps(code):
+ # first convert single-bit selectors to two-index form
+ # i.e., <n> --> <n:n>
+ code = bitOp1ArgRE.sub(r'<\1:\1>', code)
+ # simple case: selector applied to ID (name)
+ # i.e., foo<a:b> --> bits(foo, a, b)
+ code = bitOpWordRE.sub(r'bits(\1, \2, \3)', code)
+ # if selector is applied to expression (ending in ')'),
+ # we need to search backward for matching '('
+ match = bitOpExprRE.search(code)
+ while match:
+ exprEnd = match.start()
+ here = exprEnd - 1
+ nestLevel = 1
+ while nestLevel > 0:
+ if code[here] == '(':
+ nestLevel -= 1
+ elif code[here] == ')':
+ nestLevel += 1
+ here -= 1
+ if here < 0:
+ sys.exit("Didn't find '('!")
+ exprStart = here+1
+ newExpr = r'bits(%s, %s, %s)' % (code[exprStart:exprEnd+1],
+ match.group(1), match.group(2))
+ code = code[:exprStart] + newExpr + code[match.end():]
+ match = bitOpExprRE.search(code)
+ return code
+
+
+####################
+# Template objects.
+#
+# Template objects are format strings that allow substitution from
+# the attribute spaces of other objects (e.g. InstObjParams instances).
+
+class Template:
+ def __init__(self, t):
+ self.template = t
+
+ def subst(self, d):
+ # Start with the template namespace. Make a copy since we're
+ # going to modify it.
+ myDict = templateMap.copy()
+ # if the argument is a dictionary, we just use it.
+ if isinstance(d, dict):
+ myDict.update(d)
+ # if the argument is an object, we use its attribute map.
+ elif hasattr(d, '__dict__'):
+ myDict.update(d.__dict__)
+ else:
+ raise TypeError, "Template.subst() arg must be or have dictionary"
+ # Protect non-Python-dict substitutions (e.g. if there's a printf
+ # in the templated C++ code)
+ template = protect_non_subst_percents(self.template)
+ # CPU-model-specific substitutions are handled later (in GenCode).
+ template = protect_cpu_symbols(template)
+ return template % myDict
+
+ # Convert to string. This handles the case when a template with a
+ # CPU-specific term gets interpolated into another template or into
+ # an output block.
+ def __str__(self):
+ return expand_cpu_symbols_to_string(self.template)
+
+#####################################################################
+#
+# Code Parser
+#
+# The remaining code is the support for automatically extracting
+# instruction characteristics from pseudocode.
+#
+#####################################################################
+
+# Force the argument to be a list. Useful for flags, where a caller
+# can specify a singleton flag or a list of flags. Also usful for
+# converting tuples to lists so they can be modified.
+def makeList(arg):
+ if isinstance(arg, list):
+ return arg
+ elif isinstance(arg, tuple):
+ return list(arg)
+ elif not arg:
+ return []
+ else:
+ return [ arg ]
+
+# Generate operandTypeMap from the user's 'def operand_types'
+# statement.
+def buildOperandTypeMap(userDict, lineno):
+ global operandTypeMap
+ operandTypeMap = {}
+ for (ext, (desc, size)) in userDict.iteritems():
+ if desc == 'signed int':
+ ctype = 'int%d_t' % size
+ is_signed = 1
+ elif desc == 'unsigned int':
+ ctype = 'uint%d_t' % size
+ is_signed = 0
+ elif desc == 'float':
+ is_signed = 1 # shouldn't really matter
+ if size == 32:
+ ctype = 'float'
+ elif size == 64:
+ ctype = 'double'
+ if ctype == '':
+ error(lineno, 'Unrecognized type description "%s" in userDict')
+ operandTypeMap[ext] = (size, ctype, is_signed)
+
+#
+#
+#
+# Base class for operand descriptors. An instance of this class (or
+# actually a class derived from this one) represents a specific
+# operand for a code block (e.g, "Rc.sq" as a dest). Intermediate
+# derived classes encapsulates the traits of a particular operand type
+# (e.g., "32-bit integer register").
+#
+class Operand(object):
+ def __init__(self, full_name, ext, is_src, is_dest):
+ self.full_name = full_name
+ self.ext = ext
+ self.is_src = is_src
+ self.is_dest = is_dest
+ # The 'effective extension' (eff_ext) is either the actual
+ # extension, if one was explicitly provided, or the default.
+ if ext:
+ self.eff_ext = ext
+ else:
+ self.eff_ext = self.dflt_ext
+
+ (self.size, self.ctype, self.is_signed) = operandTypeMap[self.eff_ext]
+
+ # note that mem_acc_size is undefined for non-mem operands...
+ # template must be careful not to use it if it doesn't apply.
+ if self.isMem():
+ self.mem_acc_size = self.makeAccSize()
+ self.mem_acc_type = self.ctype
+
+ # Finalize additional fields (primarily code fields). This step
+ # is done separately since some of these fields may depend on the
+ # register index enumeration that hasn't been performed yet at the
+ # time of __init__().
+ def finalize(self):
+ self.flags = self.getFlags()
+ self.constructor = self.makeConstructor()
+ self.op_decl = self.makeDecl()
+
+ if self.is_src:
+ self.op_rd = self.makeRead()
+ self.op_src_decl = self.makeDecl()
+ else:
+ self.op_rd = ''
+ self.op_src_decl = ''
+
+ if self.is_dest:
+ self.op_wb = self.makeWrite()
+ self.op_dest_decl = self.makeDecl()
+ else:
+ self.op_wb = ''
+ self.op_dest_decl = ''
+
+ def isMem(self):
+ return 0
+
+ def isReg(self):
+ return 0
+
+ def isFloatReg(self):
+ return 0
+
+ def isIntReg(self):
+ return 0
+
+ def isControlReg(self):
+ return 0
+
+ def getFlags(self):
+ # note the empty slice '[:]' gives us a copy of self.flags[0]
+ # instead of a reference to it
+ my_flags = self.flags[0][:]
+ if self.is_src:
+ my_flags += self.flags[1]
+ if self.is_dest:
+ my_flags += self.flags[2]
+ return my_flags
+
+ def makeDecl(self):
+ # Note that initializations in the declarations are solely
+ # to avoid 'uninitialized variable' errors from the compiler.
+ return self.ctype + ' ' + self.base_name + ' = 0;\n';
+
+class IntRegOperand(Operand):
+ def isReg(self):
+ return 1
+
+ def isIntReg(self):
+ return 1
+
+ def makeConstructor(self):
+ c = ''
+ if self.is_src:
+ c += '\n\t_srcRegIdx[%d] = %s;' % \
+ (self.src_reg_idx, self.reg_spec)
+ if self.is_dest:
+ c += '\n\t_destRegIdx[%d] = %s;' % \
+ (self.dest_reg_idx, self.reg_spec)
+ return c
+
+ def makeRead(self):
+ if (self.ctype == 'float' or self.ctype == 'double'):
+ error(0, 'Attempt to read integer register as FP')
+ if (self.size == self.dflt_size):
+ return '%s = xc->readIntReg(this, %d);\n' % \
+ (self.base_name, self.src_reg_idx)
+ else:
+ return '%s = bits(xc->readIntReg(this, %d), %d, 0);\n' % \
+ (self.base_name, self.src_reg_idx, self.size-1)
+
+ def makeWrite(self):
+ if (self.ctype == 'float' or self.ctype == 'double'):
+ error(0, 'Attempt to write integer register as FP')
+ if (self.size != self.dflt_size and self.is_signed):
+ final_val = 'sext<%d>(%s)' % (self.size, self.base_name)
+ else:
+ final_val = self.base_name
+ wb = '''
+ {
+ %s final_val = %s;
+ xc->setIntReg(this, %d, final_val);\n
+ if (traceData) { traceData->setData(final_val); }
+ }''' % (self.dflt_ctype, final_val, self.dest_reg_idx)
+ return wb
+
+class FloatRegOperand(Operand):
+ def isReg(self):
+ return 1
+
+ def isFloatReg(self):
+ return 1
+
+ def makeConstructor(self):
+ c = ''
+ if self.is_src:
+ c += '\n\t_srcRegIdx[%d] = %s + FP_Base_DepTag;' % \
+ (self.src_reg_idx, self.reg_spec)
+ if self.is_dest:
+ c += '\n\t_destRegIdx[%d] = %s + FP_Base_DepTag;' % \
+ (self.dest_reg_idx, self.reg_spec)
+ return c
+
+ def makeRead(self):
+ bit_select = 0
+ width = 0;
+ if (self.ctype == 'float'):
+ func = 'readFloatReg'
+ width = 32;
+ elif (self.ctype == 'double'):
+ func = 'readFloatReg'
+ width = 64;
+ else:
+ func = 'readFloatRegBits'
+ if (self.ctype == 'uint32_t'):
+ width = 32;
+ elif (self.ctype == 'uint64_t'):
+ width = 64;
+ if (self.size != self.dflt_size):
+ bit_select = 1
+ if width:
+ base = 'xc->%s(this, %d, %d)' % \
+ (func, self.src_reg_idx, width)
+ else:
+ base = 'xc->%s(this, %d)' % \
+ (func, self.src_reg_idx)
+ if bit_select:
+ return '%s = bits(%s, %d, 0);\n' % \
+ (self.base_name, base, self.size-1)
+ else:
+ return '%s = %s;\n' % (self.base_name, base)
+
+ def makeWrite(self):
+ final_val = self.base_name
+ final_ctype = self.ctype
+ widthSpecifier = ''
+ width = 0
+ if (self.ctype == 'float'):
+ width = 32
+ func = 'setFloatReg'
+ elif (self.ctype == 'double'):
+ width = 64
+ func = 'setFloatReg'
+ elif (self.ctype == 'uint32_t'):
+ func = 'setFloatRegBits'
+ width = 32
+ elif (self.ctype == 'uint64_t'):
+ func = 'setFloatRegBits'
+ width = 64
+ else:
+ func = 'setFloatRegBits'
+ final_ctype = 'uint%d_t' % self.dflt_size
+ if (self.size != self.dflt_size and self.is_signed):
+ final_val = 'sext<%d>(%s)' % (self.size, self.base_name)
+ if width:
+ widthSpecifier = ', %d' % width
+ wb = '''
+ {
+ %s final_val = %s;
+ xc->%s(this, %d, final_val%s);\n
+ if (traceData) { traceData->setData(final_val); }
+ }''' % (final_ctype, final_val, func, self.dest_reg_idx,
+ widthSpecifier)
+ return wb
+
+class ControlRegOperand(Operand):
+ def isReg(self):
+ return 1
+
+ def isControlReg(self):
+ return 1
+
+ def makeConstructor(self):
+ c = ''
+ if self.is_src:
+ c += '\n\t_srcRegIdx[%d] = %s;' % \
+ (self.src_reg_idx, self.reg_spec)
+ if self.is_dest:
+ c += '\n\t_destRegIdx[%d] = %s;' % \
+ (self.dest_reg_idx, self.reg_spec)
+ return c
+
+ def makeRead(self):
+ bit_select = 0
+ if (self.ctype == 'float' or self.ctype == 'double'):
+ error(0, 'Attempt to read control register as FP')
+ base = 'xc->readMiscReg(%s)' % self.reg_spec
+ if self.size == self.dflt_size:
+ return '%s = %s;\n' % (self.base_name, base)
+ else:
+ return '%s = bits(%s, %d, 0);\n' % \
+ (self.base_name, base, self.size-1)
+
+ def makeWrite(self):
+ if (self.ctype == 'float' or self.ctype == 'double'):
+ error(0, 'Attempt to write control register as FP')
+ wb = 'xc->setMiscReg(%s, %s);\n' % (self.reg_spec, self.base_name)
+ wb += 'if (traceData) { traceData->setData(%s); }' % \
+ self.base_name
+ return wb
+
+class MemOperand(Operand):
+ def isMem(self):
+ return 1
+
+ def makeConstructor(self):
+ return ''
+
+ def makeDecl(self):
+ # Note that initializations in the declarations are solely
+ # to avoid 'uninitialized variable' errors from the compiler.
+ # Declare memory data variable.
+ c = '%s %s = 0;\n' % (self.ctype, self.base_name)
+ return c
+
+ def makeRead(self):
+ return ''
+
+ def makeWrite(self):
+ return ''
+
+ # Return the memory access size *in bits*, suitable for
+ # forming a type via "uint%d_t". Divide by 8 if you want bytes.
+ def makeAccSize(self):
+ return self.size
+
+
+class NPCOperand(Operand):
+ def makeConstructor(self):
+ return ''
+
+ def makeRead(self):
+ return '%s = xc->readNextPC();\n' % self.base_name
+
+ def makeWrite(self):
+ return 'xc->setNextPC(%s);\n' % self.base_name
+
+class NNPCOperand(Operand):
+ def makeConstructor(self):
+ return ''
+
+ def makeRead(self):
+ return '%s = xc->readNextNPC();\n' % self.base_name
+
+ def makeWrite(self):
+ return 'xc->setNextNPC(%s);\n' % self.base_name
+
+def buildOperandNameMap(userDict, lineno):
+ global operandNameMap
+ operandNameMap = {}
+ for (op_name, val) in userDict.iteritems():
+ (base_cls_name, dflt_ext, reg_spec, flags, sort_pri) = val
+ (dflt_size, dflt_ctype, dflt_is_signed) = operandTypeMap[dflt_ext]
+ # Canonical flag structure is a triple of lists, where each list
+ # indicates the set of flags implied by this operand always, when
+ # used as a source, and when used as a dest, respectively.
+ # For simplicity this can be initialized using a variety of fairly
+ # obvious shortcuts; we convert these to canonical form here.
+ if not flags:
+ # no flags specified (e.g., 'None')
+ flags = ( [], [], [] )
+ elif isinstance(flags, str):
+ # a single flag: assumed to be unconditional
+ flags = ( [ flags ], [], [] )
+ elif isinstance(flags, list):
+ # a list of flags: also assumed to be unconditional
+ flags = ( flags, [], [] )
+ elif isinstance(flags, tuple):
+ # it's a tuple: it should be a triple,
+ # but each item could be a single string or a list
+ (uncond_flags, src_flags, dest_flags) = flags
+ flags = (makeList(uncond_flags),
+ makeList(src_flags), makeList(dest_flags))
+ # Accumulate attributes of new operand class in tmp_dict
+ tmp_dict = {}
+ for attr in ('dflt_ext', 'reg_spec', 'flags', 'sort_pri',
+ 'dflt_size', 'dflt_ctype', 'dflt_is_signed'):
+ tmp_dict[attr] = eval(attr)
+ tmp_dict['base_name'] = op_name
+ # New class name will be e.g. "IntReg_Ra"
+ cls_name = base_cls_name + '_' + op_name
+ # Evaluate string arg to get class object. Note that the
+ # actual base class for "IntReg" is "IntRegOperand", i.e. we
+ # have to append "Operand".
+ try:
+ base_cls = eval(base_cls_name + 'Operand')
+ except NameError:
+ error(lineno,
+ 'error: unknown operand base class "%s"' % base_cls_name)
+ # The following statement creates a new class called
+ # <cls_name> as a subclass of <base_cls> with the attributes
+ # in tmp_dict, just as if we evaluated a class declaration.
+ operandNameMap[op_name] = type(cls_name, (base_cls,), tmp_dict)
+
+ # Define operand variables.
+ operands = userDict.keys()
+
+ operandsREString = (r'''
+ (?<![\w\.]) # neg. lookbehind assertion: prevent partial matches
+ ((%s)(?:\.(\w+))?) # match: operand with optional '.' then suffix
+ (?![\w\.]) # neg. lookahead assertion: prevent partial matches
+ '''
+ % string.join(operands, '|'))
+
+ global operandsRE
+ operandsRE = re.compile(operandsREString, re.MULTILINE|re.VERBOSE)
+
+ # Same as operandsREString, but extension is mandatory, and only two
+ # groups are returned (base and ext, not full name as above).
+ # Used for subtituting '_' for '.' to make C++ identifiers.
+ operandsWithExtREString = (r'(?<![\w\.])(%s)\.(\w+)(?![\w\.])'
+ % string.join(operands, '|'))
+
+ global operandsWithExtRE
+ operandsWithExtRE = re.compile(operandsWithExtREString, re.MULTILINE)
+
+
+class OperandList:
+
+ # Find all the operands in the given code block. Returns an operand
+ # descriptor list (instance of class OperandList).
+ def __init__(self, code):
+ self.items = []
+ self.bases = {}
+ # delete comments so we don't match on reg specifiers inside
+ code = commentRE.sub('', code)
+ # search for operands
+ next_pos = 0
+ while 1:
+ match = operandsRE.search(code, next_pos)
+ if not match:
+ # no more matches: we're done
+ break
+ op = match.groups()
+ # regexp groups are operand full name, base, and extension
+ (op_full, op_base, op_ext) = op
+ # if the token following the operand is an assignment, this is
+ # a destination (LHS), else it's a source (RHS)
+ is_dest = (assignRE.match(code, match.end()) != None)
+ is_src = not is_dest
+ # see if we've already seen this one
+ op_desc = self.find_base(op_base)
+ if op_desc:
+ if op_desc.ext != op_ext:
+ error(0, 'Inconsistent extensions for operand %s' % \
+ op_base)
+ op_desc.is_src = op_desc.is_src or is_src
+ op_desc.is_dest = op_desc.is_dest or is_dest
+ else:
+ # new operand: create new descriptor
+ op_desc = operandNameMap[op_base](op_full, op_ext,
+ is_src, is_dest)
+ self.append(op_desc)
+ # start next search after end of current match
+ next_pos = match.end()
+ self.sort()
+ # enumerate source & dest register operands... used in building
+ # constructor later
+ self.numSrcRegs = 0
+ self.numDestRegs = 0
+ self.numFPDestRegs = 0
+ self.numIntDestRegs = 0
+ self.memOperand = None
+ for op_desc in self.items:
+ if op_desc.isReg():
+ if op_desc.is_src:
+ op_desc.src_reg_idx = self.numSrcRegs
+ self.numSrcRegs += 1
+ if op_desc.is_dest:
+ op_desc.dest_reg_idx = self.numDestRegs
+ self.numDestRegs += 1
+ if op_desc.isFloatReg():
+ self.numFPDestRegs += 1
+ elif op_desc.isIntReg():
+ self.numIntDestRegs += 1
+ elif op_desc.isMem():
+ if self.memOperand:
+ error(0, "Code block has more than one memory operand.")
+ self.memOperand = op_desc
+ # now make a final pass to finalize op_desc fields that may depend
+ # on the register enumeration
+ for op_desc in self.items:
+ op_desc.finalize()
+
+ def __len__(self):
+ return len(self.items)
+
+ def __getitem__(self, index):
+ return self.items[index]
+
+ def append(self, op_desc):
+ self.items.append(op_desc)
+ self.bases[op_desc.base_name] = op_desc
+
+ def find_base(self, base_name):
+ # like self.bases[base_name], but returns None if not found
+ # (rather than raising exception)
+ return self.bases.get(base_name)
+
+ # internal helper function for concat[Some]Attr{Strings|Lists}
+ def __internalConcatAttrs(self, attr_name, filter, result):
+ for op_desc in self.items:
+ if filter(op_desc):
+ result += getattr(op_desc, attr_name)
+ return result
+
+ # return a single string that is the concatenation of the (string)
+ # values of the specified attribute for all operands
+ def concatAttrStrings(self, attr_name):
+ return self.__internalConcatAttrs(attr_name, lambda x: 1, '')
+
+ # like concatAttrStrings, but only include the values for the operands
+ # for which the provided filter function returns true
+ def concatSomeAttrStrings(self, filter, attr_name):
+ return self.__internalConcatAttrs(attr_name, filter, '')
+
+ # return a single list that is the concatenation of the (list)
+ # values of the specified attribute for all operands
+ def concatAttrLists(self, attr_name):
+ return self.__internalConcatAttrs(attr_name, lambda x: 1, [])
+
+ # like concatAttrLists, but only include the values for the operands
+ # for which the provided filter function returns true
+ def concatSomeAttrLists(self, filter, attr_name):
+ return self.__internalConcatAttrs(attr_name, filter, [])
+
+ def sort(self):
+ self.items.sort(lambda a, b: a.sort_pri - b.sort_pri)
+
+# Regular expression object to match C++ comments
+# (used in findOperands())
+commentRE = re.compile(r'//.*\n')
+
+# Regular expression object to match assignment statements
+# (used in findOperands())
+assignRE = re.compile(r'\s*=(?!=)', re.MULTILINE)
+
+# Munge operand names in code string to make legal C++ variable names.
+# This means getting rid of the type extension if any.
+# (Will match base_name attribute of Operand object.)
+def substMungedOpNames(code):
+ return operandsWithExtRE.sub(r'\1', code)
+
+def joinLists(t):
+ return map(string.join, t)
+
+def makeFlagConstructor(flag_list):
+ if len(flag_list) == 0:
+ return ''
+ # filter out repeated flags
+ flag_list.sort()
+ i = 1
+ while i < len(flag_list):
+ if flag_list[i] == flag_list[i-1]:
+ del flag_list[i]
+ else:
+ i += 1
+ pre = '\n\tflags['
+ post = '] = true;'
+ code = pre + string.join(flag_list, post + pre) + post
+ return code
+
+class CodeBlock:
+ def __init__(self, code):
+ self.orig_code = code
+ self.operands = OperandList(code)
+ self.code = substMungedOpNames(substBitOps(code))
+ self.constructor = self.operands.concatAttrStrings('constructor')
+ self.constructor += \
+ '\n\t_numSrcRegs = %d;' % self.operands.numSrcRegs
+ self.constructor += \
+ '\n\t_numDestRegs = %d;' % self.operands.numDestRegs
+ self.constructor += \
+ '\n\t_numFPDestRegs = %d;' % self.operands.numFPDestRegs
+ self.constructor += \
+ '\n\t_numIntDestRegs = %d;' % self.operands.numIntDestRegs
+
+ self.op_decl = self.operands.concatAttrStrings('op_decl')
+
+ is_src = lambda op: op.is_src
+ is_dest = lambda op: op.is_dest
+
+ self.op_src_decl = \
+ self.operands.concatSomeAttrStrings(is_src, 'op_src_decl')
+ self.op_dest_decl = \
+ self.operands.concatSomeAttrStrings(is_dest, 'op_dest_decl')
+
+ self.op_rd = self.operands.concatAttrStrings('op_rd')
+ self.op_wb = self.operands.concatAttrStrings('op_wb')
+
+ self.flags = self.operands.concatAttrLists('flags')
+
+ if self.operands.memOperand:
+ self.mem_acc_size = self.operands.memOperand.mem_acc_size
+ self.mem_acc_type = self.operands.memOperand.mem_acc_type
+
+ # Make a basic guess on the operand class (function unit type).
+ # These are good enough for most cases, and will be overridden
+ # later otherwise.
+ if 'IsStore' in self.flags:
+ self.op_class = 'MemWriteOp'
+ elif 'IsLoad' in self.flags or 'IsPrefetch' in self.flags:
+ self.op_class = 'MemReadOp'
+ elif 'IsFloating' in self.flags:
+ self.op_class = 'FloatAddOp'
+ else:
+ self.op_class = 'IntAluOp'
+
+# Assume all instruction flags are of the form 'IsFoo'
+instFlagRE = re.compile(r'Is.*')
+
+# OpClass constants end in 'Op' except No_OpClass
+opClassRE = re.compile(r'.*Op|No_OpClass')
+
+class InstObjParams:
+ def __init__(self, mnem, class_name, base_class = '',
+ code = None, opt_args = [], *extras):
+ self.mnemonic = mnem
+ self.class_name = class_name
+ self.base_class = base_class
+ if code:
+ #If the user already made a CodeBlock, pick the parts from it
+ if isinstance(code, CodeBlock):
+ origCode = code.orig_code
+ codeBlock = code
+ else:
+ origCode = code
+ codeBlock = CodeBlock(code)
+ compositeCode = '\n'.join([origCode] +
+ [pair[1] for pair in extras])
+ compositeBlock = CodeBlock(compositeCode)
+ for code_attr in compositeBlock.__dict__.keys():
+ setattr(self, code_attr, getattr(compositeBlock, code_attr))
+ for (key, snippet) in extras:
+ setattr(self, key, CodeBlock(snippet).code)
+ self.code = codeBlock.code
+ self.orig_code = origCode
+ else:
+ self.constructor = ''
+ self.flags = []
+ # Optional arguments are assumed to be either StaticInst flags
+ # or an OpClass value. To avoid having to import a complete
+ # list of these values to match against, we do it ad-hoc
+ # with regexps.
+ for oa in opt_args:
+ if instFlagRE.match(oa):
+ self.flags.append(oa)
+ elif opClassRE.match(oa):
+ self.op_class = oa
+ else:
+ error(0, 'InstObjParams: optional arg "%s" not recognized '
+ 'as StaticInst::Flag or OpClass.' % oa)
+
+ # add flag initialization to contructor here to include
+ # any flags added via opt_args
+ self.constructor += makeFlagConstructor(self.flags)
+
+ # if 'IsFloating' is set, add call to the FP enable check
+ # function (which should be provided by isa_desc via a declare)
+ if 'IsFloating' in self.flags:
+ self.fp_enable_check = 'fault = checkFpEnableFault(xc);'
+ else:
+ self.fp_enable_check = ''
+
+#######################
+#
+# Output file template
+#
+
+file_template = '''
+/*
+ * DO NOT EDIT THIS FILE!!!
+ *
+ * It was automatically generated from the ISA description in %(filename)s
+ */
+
+%(includes)s
+
+%(global_output)s
+
+namespace %(namespace)s {
+
+%(namespace_output)s
+
+} // namespace %(namespace)s
+
+%(decode_function)s
+'''
+
+
+# Update the output file only if the new contents are different from
+# the current contents. Minimizes the files that need to be rebuilt
+# after minor changes.
+def update_if_needed(file, contents):
+ update = False
+ if os.access(file, os.R_OK):
+ f = open(file, 'r')
+ old_contents = f.read()
+ f.close()
+ if contents != old_contents:
+ print 'Updating', file
+ os.remove(file) # in case it's write-protected
+ update = True
+ else:
+ print 'File', file, 'is unchanged'
+ else:
+ print 'Generating', file
+ update = True
+ if update:
+ f = open(file, 'w')
+ f.write(contents)
+ f.close()
+
+# This regular expression matches '##include' directives
+includeRE = re.compile(r'^\s*##include\s+"(?P<filename>[\w/.-]*)".*$',
+ re.MULTILINE)
+
+# Function to replace a matched '##include' directive with the
+# contents of the specified file (with nested ##includes replaced
+# recursively). 'matchobj' is an re match object (from a match of
+# includeRE) and 'dirname' is the directory relative to which the file
+# path should be resolved.
+def replace_include(matchobj, dirname):
+ fname = matchobj.group('filename')
+ full_fname = os.path.normpath(os.path.join(dirname, fname))
+ contents = '##newfile "%s"\n%s\n##endfile\n' % \
+ (full_fname, read_and_flatten(full_fname))
+ return contents
+
+# Read a file and recursively flatten nested '##include' files.
+def read_and_flatten(filename):
+ current_dir = os.path.dirname(filename)
+ try:
+ contents = open(filename).read()
+ except IOError:
+ error(0, 'Error including file "%s"' % filename)
+ fileNameStack.push((filename, 0))
+ # Find any includes and include them
+ contents = includeRE.sub(lambda m: replace_include(m, current_dir),
+ contents)
+ fileNameStack.pop()
+ return contents
+
+#
+# Read in and parse the ISA description.
+#
+def parse_isa_desc(isa_desc_file, output_dir):
+ # Read file and (recursively) all included files into a string.
+ # PLY requires that the input be in a single string so we have to
+ # do this up front.
+ isa_desc = read_and_flatten(isa_desc_file)
+
+ # Initialize filename stack with outer file.
+ fileNameStack.push((isa_desc_file, 0))
+
+ # Parse it.
+ (isa_name, namespace, global_code, namespace_code) = yacc.parse(isa_desc)
+
+ # grab the last three path components of isa_desc_file to put in
+ # the output
+ filename = '/'.join(isa_desc_file.split('/')[-3:])
+
+ # generate decoder.hh
+ includes = '#include "base/bitfield.hh" // for bitfield support'
+ global_output = global_code.header_output
+ namespace_output = namespace_code.header_output
+ decode_function = ''
+ update_if_needed(output_dir + '/decoder.hh', file_template % vars())
+
+ # generate decoder.cc
+ includes = '#include "decoder.hh"'
+ global_output = global_code.decoder_output
+ namespace_output = namespace_code.decoder_output
+ # namespace_output += namespace_code.decode_block
+ decode_function = namespace_code.decode_block
+ update_if_needed(output_dir + '/decoder.cc', file_template % vars())
+
+ # generate per-cpu exec files
+ for cpu in cpu_models:
+ includes = '#include "decoder.hh"\n'
+ includes += cpu.includes
+ global_output = global_code.exec_output[cpu.name]
+ namespace_output = namespace_code.exec_output[cpu.name]
+ decode_function = ''
+ update_if_needed(output_dir + '/' + cpu.filename,
+ file_template % vars())
+
+# global list of CpuModel objects (see cpu_models.py)
+cpu_models = []
+
+# Called as script: get args from command line.
+# Args are: <path to cpu_models.py> <isa desc file> <output dir> <cpu models>
+if __name__ == '__main__':
+ execfile(sys.argv[1]) # read in CpuModel definitions
+ cpu_models = [CpuModel.dict[cpu] for cpu in sys.argv[4:]]
+ parse_isa_desc(sys.argv[2], sys.argv[3])
diff --git a/src/arch/isa_specific.hh b/src/arch/isa_specific.hh
new file mode 100644
index 000000000..91c9ffb68
--- /dev/null
+++ b/src/arch/isa_specific.hh
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ARCH_ISA_SPECIFIC_HH__
+#define __ARCH_ISA_SPECIFIC_HH__
+
+//This file provides a mechanism for other source code to bring in
+//files from the ISA being compiled with
+
+//These are constants so you can selective compile code based on the isa
+//To use them, do something like
+//
+//#if THE_ISA == YOUR_FAVORITE_ISA
+// conditional_code
+//#endif
+//
+//Note that this is how this file sets up the other isa "hooks"
+
+//These macros have numerical values because otherwise the preprocessor
+//would treat them as 0 in comparisons.
+#define ALPHA_ISA 21064
+#define SPARC_ISA 42
+#define MIPS_ISA 34000
+
+//These tell the preprocessor where to find the files of a particular
+//ISA, and set the "TheISA" macro for use elsewhere.
+#if THE_ISA == ALPHA_ISA
+ #define TheISA AlphaISA
+#elif THE_ISA == SPARC_ISA
+ #define TheISA SparcISA
+#elif THE_ISA == MIPS_ISA
+ #define TheISA MipsISA
+#else
+ #error "THE_ISA not set"
+#endif
+
+#endif
diff --git a/src/arch/mips/SConscript b/src/arch/mips/SConscript
new file mode 100644
index 000000000..ef1ef25d6
--- /dev/null
+++ b/src/arch/mips/SConscript
@@ -0,0 +1,83 @@
+# -*- mode:python -*-
+
+# Copyright (c) 2004-2005 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import os
+import sys
+from os.path import isdir
+
+# Import build environment variable from SConstruct.
+Import('env')
+
+###################################################
+#
+# Define needed sources.
+#
+###################################################
+
+# Base sources used by all configurations.
+base_sources = Split('''
+ faults.cc
+ isa_traits.cc
+ ''')
+
+# Full-system sources
+full_system_sources = Split('''
+ memory.cc
+ arguments.cc
+ mips34k.cc
+ osfpal.cc
+ stacktrace.cc
+ vtophys.cc
+ ''')
+
+# Syscall emulation (non-full-system) sources
+syscall_emulation_sources = Split('''
+ linux/linux.cc
+ linux/process.cc
+ process.cc
+ ''')
+
+# Set up complete list of sources based on configuration.
+sources = base_sources
+
+if env['FULL_SYSTEM']:
+ sources += full_system_sources
+else:
+ sources += syscall_emulation_sources
+
+# Convert file names to SCons File objects. This takes care of the
+# path relative to the top of the directory tree.
+sources = [File(s) for s in sources]
+
+# Add in files generated by the ISA description.
+isa_desc_files = env.ISADesc('isa/main.isa')
+# Only non-header files need to be compiled.
+isa_desc_sources = [f for f in isa_desc_files if not f.path.endswith('.hh')]
+sources += isa_desc_sources
+
+Return('sources')
diff --git a/src/arch/mips/faults.cc b/src/arch/mips/faults.cc
new file mode 100644
index 000000000..1b31dfa69
--- /dev/null
+++ b/src/arch/mips/faults.cc
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "arch/mips/faults.hh"
+#include "cpu/exec_context.hh"
+#include "cpu/base.hh"
+#include "base/trace.hh"
+
+namespace MipsISA
+{
+
+FaultName MachineCheckFault::_name = "Machine Check";
+FaultVect MachineCheckFault::_vect = 0x0401;
+FaultStat MachineCheckFault::_count;
+
+FaultName AlignmentFault::_name = "Alignment";
+FaultVect AlignmentFault::_vect = 0x0301;
+FaultStat AlignmentFault::_count;
+
+FaultName ResetFault::_name = "reset";
+FaultVect ResetFault::_vect = 0x0001;
+FaultStat ResetFault::_count;
+
+FaultName ArithmeticFault::_name = "arith";
+FaultVect ArithmeticFault::_vect = 0x0501;
+FaultStat ArithmeticFault::_count;
+
+FaultName InterruptFault::_name = "interrupt";
+FaultVect InterruptFault::_vect = 0x0101;
+FaultStat InterruptFault::_count;
+
+FaultName NDtbMissFault::_name = "dtb_miss_single";
+FaultVect NDtbMissFault::_vect = 0x0201;
+FaultStat NDtbMissFault::_count;
+
+FaultName PDtbMissFault::_name = "dtb_miss_double";
+FaultVect PDtbMissFault::_vect = 0x0281;
+FaultStat PDtbMissFault::_count;
+
+FaultName DtbPageFault::_name = "dfault";
+FaultVect DtbPageFault::_vect = 0x0381;
+FaultStat DtbPageFault::_count;
+
+FaultName DtbAcvFault::_name = "dfault";
+FaultVect DtbAcvFault::_vect = 0x0381;
+FaultStat DtbAcvFault::_count;
+
+FaultName ItbMissFault::_name = "itbmiss";
+FaultVect ItbMissFault::_vect = 0x0181;
+FaultStat ItbMissFault::_count;
+
+FaultName ItbPageFault::_name = "itbmiss";
+FaultVect ItbPageFault::_vect = 0x0181;
+FaultStat ItbPageFault::_count;
+
+FaultName ItbAcvFault::_name = "iaccvio";
+FaultVect ItbAcvFault::_vect = 0x0081;
+FaultStat ItbAcvFault::_count;
+
+FaultName UnimplementedOpcodeFault::_name = "opdec";
+FaultVect UnimplementedOpcodeFault::_vect = 0x0481;
+FaultStat UnimplementedOpcodeFault::_count;
+
+FaultName FloatEnableFault::_name = "fen";
+FaultVect FloatEnableFault::_vect = 0x0581;
+FaultStat FloatEnableFault::_count;
+
+FaultName PalFault::_name = "pal";
+FaultVect PalFault::_vect = 0x2001;
+FaultStat PalFault::_count;
+
+FaultName IntegerOverflowFault::_name = "intover";
+FaultVect IntegerOverflowFault::_vect = 0x0501;
+FaultStat IntegerOverflowFault::_count;
+
+#if FULL_SYSTEM
+
+void MipsFault::invoke(ExecContext * xc)
+{
+ FaultBase::invoke(xc);
+ countStat()++;
+
+ // exception restart address
+ if (setRestartAddress() || !xc->inPalMode())
+ xc->setMiscReg(MipsISA::IPR_EXC_ADDR, xc->readPC());
+
+ if (skipFaultingInstruction()) {
+ // traps... skip faulting instruction.
+ xc->setMiscReg(MipsISA::IPR_EXC_ADDR,
+ xc->readMiscReg(MipsISA::IPR_EXC_ADDR) + 4);
+ }
+
+ xc->setPC(xc->readMiscReg(MipsISA::IPR_PAL_BASE) + vect());
+ xc->setNextPC(xc->readPC() + sizeof(MachInst));
+}
+
+void ArithmeticFault::invoke(ExecContext * xc)
+{
+ FaultBase::invoke(xc);
+ panic("Arithmetic traps are unimplemented!");
+}
+
+#endif
+
+} // namespace MipsISA
+
diff --git a/src/arch/mips/faults.hh b/src/arch/mips/faults.hh
new file mode 100644
index 000000000..0bdabe29e
--- /dev/null
+++ b/src/arch/mips/faults.hh
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MIPS_FAULTS_HH__
+#define __MIPS_FAULTS_HH__
+
+#include "sim/faults.hh"
+
+// The design of the "name" and "vect" functions is in sim/faults.hh
+
+namespace MipsISA
+{
+
+typedef const Addr FaultVect;
+
+class MipsFault : public FaultBase
+{
+ protected:
+ virtual bool skipFaultingInstruction() {return false;}
+ virtual bool setRestartAddress() {return true;}
+ public:
+#if FULL_SYSTEM
+ void invoke(ExecContext * xc);
+#endif
+ virtual FaultVect vect() = 0;
+ virtual FaultStat & countStat() = 0;
+};
+
+class MachineCheckFault : public MipsFault
+{
+ private:
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+ bool isMachineCheckFault() {return true;}
+};
+
+class AlignmentFault : public MipsFault
+{
+ private:
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+ bool isAlignmentFault() {return true;}
+};
+
+static inline Fault genMachineCheckFault()
+{
+ return new MachineCheckFault;
+}
+
+static inline Fault genAlignmentFault()
+{
+ return new AlignmentFault;
+}
+
+class ResetFault : public MipsFault
+{
+ private:
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+};
+
+class ArithmeticFault : public MipsFault
+{
+ protected:
+ bool skipFaultingInstruction() {return true;}
+ private:
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+#if FULL_SYSTEM
+ void invoke(ExecContext * xc);
+#endif
+};
+
+class InterruptFault : public MipsFault
+{
+ protected:
+ bool setRestartAddress() {return false;}
+ private:
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+};
+
+class NDtbMissFault : public MipsFault
+{
+ private:
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+};
+
+class PDtbMissFault : public MipsFault
+{
+ private:
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+};
+
+class DtbPageFault : public MipsFault
+{
+ private:
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+};
+
+class DtbAcvFault : public MipsFault
+{
+ private:
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+};
+
+class ItbMissFault : public MipsFault
+{
+ private:
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+};
+
+class ItbPageFault : public MipsFault
+{
+ private:
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+};
+
+class ItbAcvFault : public MipsFault
+{
+ private:
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+};
+
+class UnimplementedOpcodeFault : public MipsFault
+{
+ private:
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+};
+
+class FloatEnableFault : public MipsFault
+{
+ private:
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+};
+
+class PalFault : public MipsFault
+{
+ protected:
+ bool skipFaultingInstruction() {return true;}
+ private:
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+};
+
+class IntegerOverflowFault : public MipsFault
+{
+ private:
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+};
+
+} // MipsISA namespace
+
+#endif // __FAULTS_HH__
diff --git a/src/arch/mips/isa/base.isa b/src/arch/mips/isa/base.isa
new file mode 100644
index 000000000..b2a31c018
--- /dev/null
+++ b/src/arch/mips/isa/base.isa
@@ -0,0 +1,88 @@
+// -*- mode:c++ -*-
+
+////////////////////////////////////////////////////////////////////
+//
+// Base class for MIPS instructions, and some support functions
+//
+
+//Outputs to decoder.hh
+output header {{
+
+ using namespace MipsISA;
+
+
+ /**
+ * Base class for all MIPS static instructions.
+ */
+ class MipsStaticInst : public StaticInst
+ {
+ protected:
+
+ /// Make MipsISA register dependence tags directly visible in
+ /// this class and derived classes. Maybe these should really
+ /// live here and not in the MipsISA namespace.
+ /*enum DependenceTags {
+ FP_Base_DepTag = MipsISA::FP_Base_DepTag,
+ Fpcr_DepTag = MipsISA::Fpcr_DepTag,
+ Uniq_DepTag = MipsISA::Uniq_DepTag,
+ IPR_Base_DepTag = MipsISA::IPR_Base_DepTag
+ };*/
+
+ // Constructor
+ MipsStaticInst(const char *mnem, MachInst _machInst, OpClass __opClass)
+ : StaticInst(mnem, _machInst, __opClass)
+ {
+ }
+
+ /// Print a register name for disassembly given the unique
+ /// dependence tag number (FP or int).
+ void printReg(std::ostream &os, int reg) const;
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+
+}};
+
+//Ouputs to decoder.cc
+output decoder {{
+
+ void MipsStaticInst::printReg(std::ostream &os, int reg) const
+ {
+ if (reg < FP_Base_DepTag) {
+ ccprintf(os, "r%d", reg);
+ }
+ else {
+ ccprintf(os, "f%d", reg - FP_Base_DepTag);
+ }
+ }
+
+ std::string MipsStaticInst::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+ std::stringstream ss;
+
+ ccprintf(ss, "%-10s ", mnemonic);
+
+ if(_numDestRegs > 0){
+ printReg(ss, _destRegIdx[0]);
+ }
+
+ if(_numSrcRegs > 0) {
+ ss << ",";
+ printReg(ss, _srcRegIdx[0]);
+ }
+
+ if(_numSrcRegs > 1) {
+ ss << ",";
+ printReg(ss, _srcRegIdx[1]);
+ }
+
+
+ if(mnemonic == "sll" || mnemonic == "sra"){
+ ccprintf(ss,", %d",SA);
+ }
+
+ return ss.str();
+ }
+
+}};
+
diff --git a/src/arch/mips/isa/bitfields.isa b/src/arch/mips/isa/bitfields.isa
new file mode 100644
index 000000000..e1124a591
--- /dev/null
+++ b/src/arch/mips/isa/bitfields.isa
@@ -0,0 +1,71 @@
+// -*- mode:c++ -*-
+
+////////////////////////////////////////////////////////////////////
+//
+// Bitfield definitions.
+//
+
+def bitfield OPCODE <31:26>;
+def bitfield OPCODE_HI <31:29>;
+def bitfield OPCODE_LO <28:26>;
+
+def bitfield REGIMM <20:16>;
+def bitfield REGIMM_HI <20:19>;
+def bitfield REGIMM_LO <18:16>;
+
+def bitfield FUNCTION < 5: 0>;
+def bitfield FUNCTION_HI < 5: 3>;
+def bitfield FUNCTION_LO < 2: 0>;
+
+// Integer operate format
+def bitfield RT <20:16>;
+def bitfield RT_HI <20:19>;
+def bitfield RT_LO <18:16>;
+
+def bitfield RS <25:21>;
+def bitfield RS_MSB <25:25>;
+def bitfield RS_HI <25:24>;
+def bitfield RS_LO <23:21>;
+def bitfield RS_SRL <25:22>;
+
+def bitfield RD <15:11>;
+
+def bitfield INTIMM <15: 0>; // integer immediate (literal)
+
+// Floating-point operate format
+def bitfield FMT <25:21>;
+def bitfield FR <25:21>;
+def bitfield FT <20:16>;
+def bitfield FS <15:11>;
+def bitfield FD <10:6>;
+
+def bitfield ND <17:17>;
+def bitfield TF <16:16>;
+def bitfield MOVCI <16:16>;
+def bitfield MOVCF <16:16>;
+def bitfield SRL <21:21>;
+def bitfield SRLV < 6: 6>;
+def bitfield SA <10: 6>;
+
+// Floating Point Condition Codes
+def bitfield CC <10:8>;
+def bitfield BRANCH_CC <20:18>;
+
+// CP0 Register Select
+def bitfield SEL < 2: 0>;
+
+// Interrupts
+def bitfield SC < 5: 5>;
+
+// Branch format
+def bitfield OFFSET <15: 0>; // displacement
+
+// Jmp format
+def bitfield JMPTARG <25: 0>;
+def bitfield HINT <10: 6>;
+
+def bitfield SYSCALLCODE <25: 6>;
+def bitfield TRAPCODE <15:13>;
+
+// M5 instructions
+def bitfield M5FUNC <7:0>;
diff --git a/src/arch/mips/isa/decoder.isa b/src/arch/mips/isa/decoder.isa
new file mode 100644
index 000000000..1454aba39
--- /dev/null
+++ b/src/arch/mips/isa/decoder.isa
@@ -0,0 +1,1688 @@
+ // -*- mode:c++ -*-
+
+////////////////////////////////////////////////////////////////////
+//
+// The actual MIPS32 ISA decoder
+// -----------------------------
+// The following instructions are specified in the MIPS32 ISA
+// Specification. Decoding closely follows the style specified
+// in the MIPS32 ISAthe specification document starting with Table
+// A-2 (document available @ www.mips.com)
+//
+//@todo: Distinguish "unknown/future" use insts from "reserved"
+// ones
+decode OPCODE_HI default Unknown::unknown() {
+
+ // Derived From ... Table A-2 MIPS32 ISA Manual
+ 0x0: decode OPCODE_LO {
+
+ 0x0: decode FUNCTION_HI {
+ 0x0: decode FUNCTION_LO {
+ 0x1: decode MOVCI {
+ format BasicOp {
+ 0: movf({{ if (getFPConditionCode(FCSR, CC) == 0) Rd = Rs}});
+ 1: movt({{ if (getFPConditionCode(FCSR, CC) == 1) Rd = Rs}});
+ }
+ }
+
+ format BasicOp {
+
+ //Table A-3 Note: "1. Specific encodings of the rt, rd, and sa fields
+ //are used to distinguish among the SLL, NOP, SSNOP and EHB functions.
+ 0x0: decode RS {
+ 0x0: decode RT { //fix Nop traditional vs. Nop converted disassembly later
+ 0x0: decode RD default Nop::nop(){
+ 0x0: decode SA {
+ 0x1: ssnop({{ ; }}); //really sll r0,r0,1
+ 0x3: ehb({{ ; }}); //really sll r0,r0,3
+ }
+ }
+
+ default: sll({{ Rd = Rt.uw << SA; }});
+ }
+
+ }
+
+ 0x2: decode RS_SRL {
+ 0x0:decode SRL {
+ 0: srl({{ Rd = Rt.uw >> SA; }});
+
+ //Hardcoded assuming 32-bit ISA, probably need parameter here
+ 1: rotr({{ Rd = (Rt.uw << (32 - SA)) | (Rt.uw >> SA);}});
+ }
+ }
+
+ 0x3: decode RS {
+ 0x0: sra({{
+ uint32_t temp = Rt >> SA;
+
+ if ( (Rt & 0x80000000) > 0 ) {
+ uint32_t mask = 0x80000000;
+ for(int i=0; i < SA; i++) {
+ temp |= mask;
+ mask = mask >> 1;
+ }
+ }
+
+ Rd = temp;
+ }});
+ }
+
+ 0x4: sllv({{ Rd = Rt.uw << Rs<4:0>; }});
+
+ 0x6: decode SRLV {
+ 0: srlv({{ Rd = Rt.uw >> Rs<4:0>; }});
+
+ //Hardcoded assuming 32-bit ISA, probably need parameter here
+ 1: rotrv({{ Rd = (Rt.uw << (32 - Rs<4:0>)) | (Rt.uw >> Rs<4:0>);}});
+ }
+
+ 0x7: srav({{
+ int shift_amt = Rs<4:0>;
+
+ uint32_t temp = Rt >> shift_amt;
+
+ if ( (Rt & 0x80000000) > 0 ) {
+ uint32_t mask = 0x80000000;
+ for(int i=0; i < shift_amt; i++) {
+ temp |= mask;
+ mask = mask >> 1;
+ }
+ }
+
+ Rd = temp;
+ }});
+ }
+ }
+
+ 0x1: decode FUNCTION_LO {
+
+ //Table A-3 Note: "Specific encodings of the hint field are used
+ //to distinguish JR from JR.HB and JALR from JALR.HB"
+ format Jump {
+ 0x0: decode HINT {
+ 0:jr({{ NNPC = Rs & ~1; }},IsReturn);
+
+ 1:jr_hb({{ NNPC = Rs & ~1; clear_exe_inst_hazards(); }},IsReturn);
+ }
+
+ 0x1: decode HINT {
+ 0: jalr({{ Rd = NNPC; NNPC = Rs; }},IsCall,IsReturn);
+
+ 1: jalr_hb({{ Rd = NNPC; NNPC = Rs; clear_exe_inst_hazards();}},IsCall,IsReturn);
+ }
+ }
+
+ format BasicOp {
+ 0x2: movz({{ if (Rt == 0) Rd = Rs; }});
+ 0x3: movn({{ if (Rt != 0) Rd = Rs; }});
+ }
+
+ format BasicOp {
+ 0x4: syscall({{ xc->syscall(R2); }},IsNonSpeculative);
+ 0x5: break({{ panic("Not implemented break yet"); }},IsNonSpeculative);
+ 0x7: sync({{ panic("Not implemented sync yet"); }},IsNonSpeculative);
+ }
+ }
+
+ 0x2: decode FUNCTION_LO {
+ format BasicOp {
+ 0x0: mfhi({{ Rd = HI; }});
+ 0x1: mthi({{ HI = Rs; }});
+ 0x2: mflo({{ Rd = LO; }});
+ 0x3: mtlo({{ LO = Rs; }});
+ }
+ }
+
+ 0x3: decode FUNCTION_LO {
+ format IntOp {
+ 0x0: mult({{
+ int64_t temp1 = Rs.sd * Rt.sd;
+ HI = temp1<63:32>;
+ LO = temp1<31:0>;
+ }});
+
+ 0x1: multu({{
+ uint64_t temp1 = Rs.ud * Rt.ud;
+ HI = temp1<63:32>;
+ LO = temp1<31:0>;
+ }});
+
+ 0x2: div({{
+ HI = Rs.sd % Rt.sd;
+ LO = Rs.sd / Rt.sd;
+ }});
+
+ 0x3: divu({{
+ HI = Rs.ud % Rt.ud;
+ LO = Rs.ud / Rt.ud;
+ }});
+ }
+ }
+
+ 0x4: decode HINT {
+ 0x0: decode FUNCTION_LO {
+ format IntOp {
+ 0x0: add({{ Rd.sw = Rs.sw + Rt.sw; /*Trap on Overflow*/}});
+ 0x1: addu({{ Rd.sw = Rs.sw + Rt.sw;}});
+ 0x2: sub({{ Rd.sw = Rs.sw - Rt.sw; /*Trap on Overflow*/}});
+ 0x3: subu({{ Rd.sw = Rs.sw - Rt.sw;}});
+ 0x4: and({{ Rd = Rs & Rt;}});
+ 0x5: or({{ Rd = Rs | Rt;}});
+ 0x6: xor({{ Rd = Rs ^ Rt;}});
+ 0x7: nor({{ Rd = ~(Rs | Rt);}});
+ }
+ }
+ }
+
+ 0x5: decode HINT {
+ 0x0: decode FUNCTION_LO {
+ format IntOp{
+ 0x2: slt({{ Rd.sw = ( Rs.sw < Rt.sw ) ? 1 : 0}});
+ 0x3: sltu({{ Rd.uw = ( Rs.uw < Rt.uw ) ? 1 : 0}});
+ }
+ }
+ }
+
+ 0x6: decode FUNCTION_LO {
+ format Trap {
+ 0x0: tge({{ cond = (Rs.sw >= Rt.sw); }});
+ 0x1: tgeu({{ cond = (Rs.uw >= Rt.uw); }});
+ 0x2: tlt({{ cond = (Rs.sw < Rt.sw); }});
+ 0x3: tltu({{ cond = (Rs.uw >= Rt.uw); }});
+ 0x4: teq({{ cond = (Rs.sw == Rt.sw); }});
+ 0x6: tne({{ cond = (Rs.sw != Rt.sw); }});
+ }
+ }
+ }
+
+ 0x1: decode REGIMM_HI {
+ 0x0: decode REGIMM_LO {
+ format Branch {
+ 0x0: bltz({{ cond = (Rs.sw < 0); }});
+ 0x1: bgez({{ cond = (Rs.sw >= 0); }});
+ }
+
+ format BranchLikely {
+ 0x2: bltzl({{ cond = (Rs.sw < 0); }});
+ 0x3: bgezl({{ cond = (Rs.sw >= 0); }});
+ }
+ }
+
+ 0x1: decode REGIMM_LO {
+ format Trap {
+ 0x0: tgei( {{ cond = (Rs.sw >= INTIMM); }});
+ 0x1: tgeiu({{ cond = (Rs.uw >= INTIMM); }});
+ 0x2: tlti( {{ cond = (Rs.sw < INTIMM); }});
+ 0x3: tltiu({{ cond = (Rs.uw < INTIMM); }});
+ 0x4: teqi( {{ cond = (Rs.sw == INTIMM);}});
+ 0x6: tnei( {{ cond = (Rs.sw != INTIMM);}});
+ }
+ }
+
+ 0x2: decode REGIMM_LO {
+ format Branch {
+ 0x0: bltzal({{ cond = (Rs.sw < 0); }}, IsCall,IsReturn);
+ 0x1: bgezal({{ cond = (Rs.sw >= 0); }}, IsCall,IsReturn);
+ }
+
+ format BranchLikely {
+ 0x2: bltzall({{ cond = (Rs.sw < 0); }}, IsCall, IsReturn);
+ 0x3: bgezall({{ cond = (Rs.sw >= 0); }}, IsCall, IsReturn);
+ }
+ }
+
+ 0x3: decode REGIMM_LO {
+ format WarnUnimpl {
+ 0x7: synci();
+ }
+ }
+ }
+
+ format Jump {
+ 0x2: j({{ NNPC = (NPC & 0xF0000000) | (JMPTARG << 2);}});
+
+ 0x3: jal({{ NNPC = (NPC & 0xF0000000) | (JMPTARG << 2); }},IsCall,IsReturn);
+ }
+
+ format Branch {
+ 0x4: beq({{ cond = (Rs.sw == Rt.sw); }});
+ 0x5: bne({{ cond = (Rs.sw != Rt.sw); }});
+ 0x6: decode RT {
+ 0x0: blez({{ cond = (Rs.sw <= 0); }});
+ }
+
+ 0x7: decode RT {
+ 0x0: bgtz({{ cond = (Rs.sw > 0); }});
+ }
+ }
+ }
+
+ 0x1: decode OPCODE_LO {
+ format IntOp {
+ 0x0: addi({{ Rt.sw = Rs.sw + imm; /*Trap If Overflow*/}});
+ 0x1: addiu({{ Rt.sw = Rs.sw + imm;}});
+ 0x2: slti({{ Rt.sw = ( Rs.sw < imm) ? 1 : 0 }});
+ 0x3: sltiu({{ Rt.uw = ( Rs.uw < (uint32_t)sextImm ) ? 1 : 0 }});
+ 0x4: andi({{ Rt.sw = Rs.sw & zextImm;}});
+ 0x5: ori({{ Rt.sw = Rs.sw | zextImm;}});
+ 0x6: xori({{ Rt.sw = Rs.sw ^ zextImm;}});
+
+ 0x7: decode RS {
+ 0x0: lui({{ Rt = imm << 16}});
+ }
+ }
+ }
+
+ 0x2: decode OPCODE_LO {
+
+ //Table A-11 MIPS32 COP0 Encoding of rs Field
+ 0x0: decode RS_MSB {
+ 0x0: decode RS {
+ format System {
+ 0x0: mfc0({{
+ //uint64_t reg_num = Rd.uw;
+
+ Rt = xc->readMiscReg(RD << 5 | SEL);
+ }});
+
+ 0x4: mtc0({{
+ //uint64_t reg_num = Rd.uw;
+
+ xc->setMiscReg(RD << 5 | SEL,Rt);
+ }});
+
+ 0x8: mftr({{
+ //The contents of the coprocessor 0 register specified by the
+ //combination of rd and sel are loaded into general register
+ //rt. Note that not all coprocessor 0 registers support the
+ //sel field. In those instances, the sel field must be zero.
+
+ //MT Code Needed Here
+
+ }});
+
+ 0xC: mttr({{
+ //The contents of the coprocessor 0 register specified by the
+ //combination of rd and sel are loaded into general register
+ //rt. Note that not all coprocessor 0 registers support the
+ //sel field. In those instances, the sel field must be zero.
+
+ //MT Code Needed Here
+ }});
+
+
+ 0xA: rdpgpr({{
+ //Accessing Previous Shadow Set Register Number
+ //uint64_t prev = xc->readMiscReg(SRSCtl)/*[PSS]*/;
+ //uint64_t reg_num = Rt.uw;
+
+ //Rd = xc->regs.IntRegFile[prev];
+ //Rd = xc->shadowIntRegFile[prev][reg_num];
+ }});
+
+ 0xB: decode RD {
+
+ 0x0: decode SC {
+ 0x0: dvpe({{
+ Rt.sw = xc->readMiscReg(MVPControl);
+ xc->setMiscReg(MVPControl,0);
+ }});
+
+ 0x1: evpe({{
+ Rt.sw = xc->readMiscReg(MVPControl);
+ xc->setMiscReg(MVPControl,1);
+ }});
+ }
+
+ 0x1: decode SC {
+ 0x0: dmt({{
+ Rt.sw = xc->readMiscReg(VPEControl);
+ xc->setMiscReg(VPEControl,0);
+ }});
+
+ 0x1: emt({{
+ Rt.sw = xc->readMiscReg(VPEControl);
+ xc->setMiscReg(VPEControl,1);
+ }});
+ }
+
+ 0xC: decode SC {
+ 0x0: di({{
+ Rt.sw = xc->readMiscReg(Status);
+ xc->setMiscReg(Status,0);
+ }});
+
+ 0x1: ei({{
+ Rt.sw = xc->readMiscReg(Status);
+ xc->setMiscReg(Status,1);
+ }});
+ }
+ }
+
+ 0xE: wrpgpr({{
+ //Accessing Previous Shadow Set Register Number
+ //uint64_t prev = xc->readMiscReg(SRSCtl/*[PSS]*/);
+ //uint64_t reg_num = Rd.uw;
+
+ //xc->regs.IntRegFile[prev];
+ //xc->shadowIntRegFile[prev][reg_num] = Rt;
+ }});
+ }
+ }
+
+ //Table A-12 MIPS32 COP0 Encoding of Function Field When rs=CO
+ 0x1: decode FUNCTION {
+ format System {
+ 0x01: tlbr({{ }});
+ 0x02: tlbwi({{ }});
+ 0x06: tlbwr({{ }});
+ 0x08: tlbp({{ }});
+ }
+
+ format WarnUnimpl {
+ 0x18: eret();
+ 0x1F: deret();
+ 0x20: wait();
+ }
+ }
+ }
+
+ //Table A-13 MIPS32 COP1 Encoding of rs Field
+ 0x1: decode RS_MSB {
+
+ 0x0: decode RS_HI {
+ 0x0: decode RS_LO {
+ format FloatOp {
+ 0x0: mfc1 ({{ Rt.uw = Fs.uw<31:0>; }});
+ 0x3: mfhc1({{ Rt.uw = Fs.ud<63:32>;}});
+ 0x4: mtc1 ({{ Fs.uw = Rt.uw; }});
+ 0x7: mthc1({{
+ uint64_t fs_hi = Rt.uw;
+ uint64_t fs_lo = Fs.ud & 0x0000FFFF;
+ Fs.ud = fs_hi << 32 | fs_lo;
+ }});
+ }
+
+ format System {
+ 0x2: cfc1({{
+ switch (FS)
+ {
+ case 0:
+ Rt = FIR;
+ break;
+ case 25:
+ Rt = 0 | (FCSR & 0xFE000000) >> 24 | (FCSR & 0x00800000) >> 23;
+ break;
+ case 26:
+ Rt = 0 | (FCSR & 0x0003F07C);
+ break;
+ case 28:
+ Rt = 0 | (FCSR & 0x00000F80) | (FCSR & 0x01000000) >> 21 | (FCSR & 0x00000003);
+ break;
+ case 31:
+ Rt = FCSR;
+ break;
+ default:
+ panic("FP Control Value (%d) Not Available. Ignoring Access to"
+ "Floating Control Status Register",FS);
+ }
+ }});
+
+ 0x6: ctc1({{
+ switch (FS)
+ {
+ case 25:
+ FCSR = 0 | (Rt.uw<7:1> << 25) // move 31...25
+ | (FCSR & 0x01000000) // bit 24
+ | (FCSR & 0x004FFFFF);// bit 22...0
+ break;
+
+ case 26:
+ FCSR = 0 | (FCSR & 0xFFFC0000) // move 31...18
+ | Rt.uw<17:12> << 12 // bit 17...12
+ | (FCSR & 0x00000F80) << 7// bit 11...7
+ | Rt.uw<6:2> << 2 // bit 6...2
+ | (FCSR & 0x00000002); // bit 1...0
+ break;
+
+ case 28:
+ FCSR = 0 | (FCSR & 0xFE000000) // move 31...25
+ | Rt.uw<2:2> << 24 // bit 24
+ | (FCSR & 0x00FFF000) << 23// bit 23...12
+ | Rt.uw<11:7> << 7 // bit 24
+ | (FCSR & 0x000007E)
+ | Rt.uw<1:0>;// bit 22...0
+ break;
+
+ case 31:
+ FCSR = Rt.uw;
+ break;
+
+ default:
+ panic("FP Control Value (%d) Not Available. Ignoring Access to"
+ "Floating Control Status Register", FS);
+ }
+ }});
+ }
+ }
+
+ 0x1: decode ND {
+ 0x0: decode TF {
+ format Branch {
+ 0x0: bc1f({{ cond = (getFPConditionCode(FCSR,CC) == 0); }});
+ 0x1: bc1t({{ cond = (getFPConditionCode(FCSR,CC) == 1); }});
+ }
+ }
+
+ 0x1: decode TF {
+ format BranchLikely {
+ 0x0: bc1fl({{ cond = (getFPConditionCode(FCSR,CC) == 0); }});
+ 0x1: bc1tl({{ cond = (getFPConditionCode(FCSR,CC) == 1); }});
+ }
+ }
+ }
+ }
+
+ 0x1: decode RS_HI {
+ 0x2: decode RS_LO {
+
+ //Table A-14 MIPS32 COP1 Encoding of Function Field When rs=S
+ //(( single-word ))
+ 0x0: decode FUNCTION_HI {
+ 0x0: decode FUNCTION_LO {
+ format FloatOp {
+ 0x0: add_s({{ Fd.sf = Fs.sf + Ft.sf;}});
+ 0x1: sub_s({{ Fd.sf = Fs.sf - Ft.sf;}});
+ 0x2: mul_s({{ Fd.sf = Fs.sf * Ft.sf;}});
+ 0x3: div_s({{ Fd.sf = Fs.sf / Ft.sf;}});
+ 0x4: sqrt_s({{ Fd.sf = sqrt(Fs.sf);}});
+ 0x5: abs_s({{ Fd.sf = fabs(Fs.sf);}});
+ 0x6: mov_s({{ Fd.sf = Fs.sf;}});
+ 0x7: neg_s({{ Fd.sf = -1 * Fs.sf;}});
+ }
+ }
+
+ 0x1: decode FUNCTION_LO {
+ format Float64Op {
+ 0x0: round_l_s({{
+ Fd.ud = fpConvert(roundFP(Fs.sf,0), SINGLE_TO_LONG);
+ }});
+
+ 0x1: trunc_l_s({{
+ Fd.ud = fpConvert(truncFP(Fs.sf), SINGLE_TO_LONG);
+ }});
+
+ 0x2: ceil_l_s({{
+ Fd.ud = fpConvert(ceil(Fs.sf), SINGLE_TO_LONG);
+ }});
+
+ 0x3: floor_l_s({{
+ Fd.ud = fpConvert(floor(Fs.sf), SINGLE_TO_LONG);
+ }});
+ }
+
+ format FloatOp {
+ 0x4: round_w_s({{
+ Fd.uw = fpConvert(roundFP(Fs.sf,0), SINGLE_TO_WORD);
+ }});
+
+ 0x5: trunc_w_s({{
+ Fd.uw = fpConvert(truncFP(Fs.sf), SINGLE_TO_WORD);
+ }});
+
+ 0x6: ceil_w_s({{
+ Fd.uw = fpConvert(ceil(Fs.sf), SINGLE_TO_WORD);
+ }});
+
+ 0x7: floor_w_s({{
+ Fd.uw = fpConvert(floor(Fs.sf), SINGLE_TO_WORD);
+ }});
+ }
+ }
+
+ 0x2: decode FUNCTION_LO {
+ 0x1: decode MOVCF {
+ format FloatOp {
+ 0x0: movf_s({{if (getFPConditionCode(FCSR,CC) == 0) Fd = Fs;}});
+ 0x1: movt_s({{if (getFPConditionCode(FCSR,CC) == 1) Fd = Fs;}});
+ }
+ }
+
+ format FloatOp {
+ 0x2: movz_s({{ if (Rt == 0) Fd = Fs; }});
+ 0x3: movn_s({{ if (Rt != 0) Fd = Fs; }});
+ 0x5: recip_s({{ Fd = 1 / Fs; }});
+ 0x6: rsqrt_s({{ Fd = 1 / sqrt(Fs);}});
+ }
+ }
+
+ 0x4: decode FUNCTION_LO {
+
+ format FloatConvertOp {
+ 0x1: cvt_d_s({{
+ Fd.ud = fpConvert(Fs.sf, SINGLE_TO_DOUBLE);
+ }});
+
+ 0x4: cvt_w_s({{
+ Fd.uw = fpConvert(Fs.sf, SINGLE_TO_WORD);
+ }});
+ }
+
+ format FloatConvertOp {
+ 0x5: cvt_l_s({{
+ Fd.ud = fpConvert(Fs.sf, SINGLE_TO_LONG);
+ }});
+
+ 0x6: cvt_ps_st({{
+ Fd.ud = (uint64_t)Fs.uw << 32 | (uint64_t)Ft.uw;
+ }});
+ }
+ }
+
+ 0x6: decode FUNCTION_LO {
+ format FloatCompareOp {
+ 0x0: c_f_s({{ cond = 0; }});
+
+ 0x1: c_un_s({{
+ if (isnan(Fs.sf) || isnan(Ft.sf))
+ cond = 1;
+ else
+ cond = 0;
+ }});
+
+ 0x2: c_eq_s({{
+ if (isnan(Fs.sf) || isnan(Ft.sf))
+ cond = 0;
+ else
+ cond = (Fs.sf == Ft.sf);
+ }});
+
+ 0x3: c_ueq_s({{
+ if (isnan(Fs.sf) || isnan(Ft.sf))
+ cond = 1;
+ else
+ cond = (Fs.sf == Ft.sf);
+ }});
+
+ 0x4: c_olt_s({{
+ if (isnan(Fs.sf) || isnan(Ft.sf))
+ cond = 0;
+ else
+ cond = (Fs.sf < Ft.sf);
+ }});
+
+ 0x5: c_ult_s({{
+ if (isnan(Fs.sf) || isnan(Ft.sf))
+ cond = 1;
+ else
+ cond = (Fs.sf < Ft.sf);
+ }});
+
+ 0x6: c_ole_s({{
+ if (isnan(Fs.sf) || isnan(Ft.sf))
+ cond = 0;
+ else
+ cond = (Fs.sf <= Ft.sf);
+ }});
+
+ 0x7: c_ule_s({{
+ if (isnan(Fs.sf) || isnan(Ft.sf))
+ cond = 1;
+ else
+ cond = (Fs.sf <= Ft.sf);
+ }});
+ }
+ }
+
+ 0x7: decode FUNCTION_LO {
+ format FloatCompareWithXcptOp {
+ 0x0: c_sf_s({{ cond = 0; }});
+
+ 0x1: c_ngle_s({{
+ if (isnan(Fs.sf) || isnan(Ft.sf))
+ cond = 1;
+ else
+ cond = 0;
+ }});
+
+ 0x2: c_seq_s({{
+ if (isnan(Fs.sf) || isnan(Ft.sf))
+ cond = 0;
+ else
+ cond = (Fs.sf == Ft.sf);
+ }});
+
+ 0x3: c_ngl_s({{
+ if (isnan(Fs.sf) || isnan(Ft.sf))
+ cond = 1;
+ else
+ cond = (Fs.sf == Ft.sf);
+ }});
+
+ 0x4: c_lt_s({{
+ if (isnan(Fs.sf) || isnan(Ft.sf))
+ cond = 0;
+ else
+ cond = (Fs.sf < Ft.sf);
+ }});
+
+ 0x5: c_nge_s({{
+ if (isnan(Fs.sf) || isnan(Ft.sf))
+ cond = 1;
+ else
+ cond = (Fs.sf < Ft.sf);
+ }});
+
+ 0x6: c_le_s({{
+ if (isnan(Fs.sf) || isnan(Ft.sf))
+ cond = 0;
+ else
+ cond = (Fs.sf <= Ft.sf);
+ }});
+
+ 0x7: c_ngt_s({{
+ if (isnan(Fs.sf) || isnan(Ft.sf))
+ cond = 1;
+ else
+ cond = (Fs.sf <= Ft.sf);
+ }});
+ }
+ }
+ }
+
+ //Table A-15 MIPS32 COP1 Encoding of Function Field When rs=D
+ 0x1: decode FUNCTION_HI {
+ 0x0: decode FUNCTION_LO {
+ format FloatOp {
+ 0x0: add_d({{ Fd.df = Fs.df + Ft.df;}});
+ 0x1: sub_d({{ Fd.df = Fs.df - Ft.df;}});
+ 0x2: mul_d({{ Fd.df = Fs.df * Ft.df;}});
+ 0x3: div_d({{ Fd.df = Fs.df / Ft.df;}});
+ 0x4: sqrt_d({{ Fd.df = sqrt(Fs.df);}});
+ 0x5: abs_d({{ Fd.df = fabs(Fs.df);}});
+ 0x6: mov_d({{ Fd.ud = Fs.ud;}});
+ 0x7: neg_d({{ Fd.df = -1 * Fs.df;}});
+ }
+ }
+
+ 0x1: decode FUNCTION_LO {
+ format FloatOp {
+ 0x0: round_l_d({{
+ Fd.ud = fpConvert(roundFP(Fs.df,0), DOUBLE_TO_LONG);
+ }});
+
+ 0x1: trunc_l_d({{
+ Fd.ud = fpConvert(truncFP(Fs.df), DOUBLE_TO_LONG);
+ }});
+
+ 0x2: ceil_l_d({{
+ Fd.ud = fpConvert(ceil(Fs.df), DOUBLE_TO_LONG);
+ }});
+
+ 0x3: floor_l_d({{
+ Fd.ud = fpConvert(floor(Fs.df), DOUBLE_TO_LONG);
+ }});
+ }
+
+ format FloatOp {
+ 0x4: round_w_d({{
+ Fd.uw = fpConvert(roundFP(Fs.df,0), DOUBLE_TO_WORD);
+ }});
+
+ 0x5: trunc_w_d({{
+ Fd.uw = fpConvert(truncFP(Fs.df), DOUBLE_TO_WORD);
+ }});
+
+ 0x6: ceil_w_d({{
+ Fd.uw = fpConvert(ceil(Fs.df), DOUBLE_TO_WORD);
+ }});
+
+ 0x7: floor_w_d({{
+ Fd.uw = fpConvert(floor(Fs.df), DOUBLE_TO_WORD);
+ }});
+ }
+ }
+
+ 0x2: decode FUNCTION_LO {
+ 0x1: decode MOVCF {
+ format FloatOp {
+ 0x0: movf_d({{if (getFPConditionCode(FCSR,CC) == 0) Fd.df = Fs.df; }});
+ 0x1: movt_d({{if (getFPConditionCode(FCSR,CC) == 1) Fd.df = Fs.df; }});
+ }
+ }
+
+ format BasicOp {
+ 0x2: movz_d({{ if (Rt == 0) Fd.df = Fs.df; }});
+ 0x3: movn_d({{ if (Rt != 0) Fd.df = Fs.df; }});
+ }
+
+ format FloatOp {
+ 0x5: recip_d({{ Fd.df = 1 / Fs.df}});
+ 0x6: rsqrt_d({{ Fd.df = 1 / sqrt(Fs.df) }});
+ }
+ }
+
+ 0x4: decode FUNCTION_LO {
+ format FloatOp {
+ 0x0: cvt_s_d({{
+ Fd.uw = fpConvert(Fs.df, DOUBLE_TO_SINGLE);
+ }});
+
+ 0x4: cvt_w_d({{
+ Fd.uw = fpConvert(Fs.df, DOUBLE_TO_WORD);
+ }});
+
+ 0x5: cvt_l_d({{
+ Fd.ud = fpConvert(Fs.df, DOUBLE_TO_LONG);
+ }});
+ }
+ }
+
+ 0x6: decode FUNCTION_LO {
+ format FloatCompareOp {
+ 0x0: c_f_d({{ cond = 0; }});
+
+ 0x1: c_un_d({{
+ if (isnan(Fs.df) || isnan(Ft.df))
+ cond = 1;
+ else
+ cond = 0;
+ }});
+
+ 0x2: c_eq_d({{
+ if (isnan(Fs.df) || isnan(Ft.df))
+ cond = 0;
+ else
+ cond = (Fs.df == Ft.df);
+ }});
+
+ 0x3: c_ueq_d({{
+ if (isnan(Fs.df) || isnan(Ft.df))
+ cond = 1;
+ else
+ cond = (Fs.df == Ft.df);
+ }});
+
+ 0x4: c_olt_d({{
+ if (isnan(Fs.df) || isnan(Ft.df))
+ cond = 0;
+ else
+ cond = (Fs.df < Ft.df);
+ }});
+
+ 0x5: c_ult_d({{
+ if (isnan(Fs.df) || isnan(Ft.df))
+ cond = 1;
+ else
+ cond = (Fs.df < Ft.df);
+ }});
+
+ 0x6: c_ole_d({{
+ if (isnan(Fs.df) || isnan(Ft.df))
+ cond = 0;
+ else
+ cond = (Fs.df <= Ft.df);
+ }});
+
+ 0x7: c_ule_d({{
+ if (isnan(Fs.df) || isnan(Ft.df))
+ cond = 1;
+ else
+ cond = (Fs.df <= Ft.df);
+ }});
+ }
+ }
+
+ 0x7: decode FUNCTION_LO {
+ format FloatCompareWithXcptOp {
+ 0x0: c_sf_d({{ cond = 0; }});
+
+ 0x1: c_ngle_d({{
+ if (isnan(Fs.df) || isnan(Ft.df))
+ cond = 1;
+ else
+ cond = 0;
+ }});
+
+ 0x2: c_seq_d({{
+ if (isnan(Fs.df) || isnan(Ft.df))
+ cond = 0;
+ else
+ cond = (Fs.df == Ft.df);
+ }});
+
+ 0x3: c_ngl_d({{
+ if (isnan(Fs.df) || isnan(Ft.df))
+ cond = 1;
+ else
+ cond = (Fs.df == Ft.df);
+ }});
+
+ 0x4: c_lt_d({{
+ if (isnan(Fs.df) || isnan(Ft.df))
+ cond = 0;
+ else
+ cond = (Fs.df < Ft.df);
+ }});
+
+ 0x5: c_nge_d({{
+ if (isnan(Fs.df) || isnan(Ft.df))
+ cond = 1;
+ else
+ cond = (Fs.df < Ft.df);
+ }});
+
+ 0x6: c_le_d({{
+ if (isnan(Fs.df) || isnan(Ft.df))
+ cond = 0;
+ else
+ cond = (Fs.df <= Ft.df);
+ }});
+
+ 0x7: c_ngt_d({{
+ if (isnan(Fs.df) || isnan(Ft.df))
+ cond = 1;
+ else
+ cond = (Fs.df <= Ft.df);
+ }});
+ }
+ }
+ }
+
+ //Table A-16 MIPS32 COP1 Encoding of Function Field When rs=W
+ 0x4: decode FUNCTION {
+ format FloatConvertOp {
+ 0x20: cvt_s_w({{
+ Fd.uw = fpConvert(Fs.sf, WORD_TO_SINGLE);
+ }});
+
+ 0x21: cvt_d_w({{
+ Fd.ud = fpConvert(Fs.sf, WORD_TO_DOUBLE);
+ }});
+ }
+
+ format Float64ConvertOp {
+ 0x26: cvt_ps_pw({{
+ Fd.ud = fpConvert(Fs.ud, WORD_TO_PS);
+ }});
+ }
+ }
+
+ //Table A-16 MIPS32 COP1 Encoding of Function Field When rs=L1
+ //Note: "1. Format type L is legal only if 64-bit floating point operations
+ //are enabled."
+ 0x5: decode FUNCTION_HI {
+ format Float64ConvertOp {
+ 0x20: cvt_s_l({{
+ Fd.uw = fpConvert(Fs.ud, LONG_TO_SINGLE);
+ }});
+
+ 0x21: cvt_d_l({{
+ Fd.ud = fpConvert(Fs.ud, LONG_TO_DOUBLE);
+ }});
+
+ 0x26: cvt_ps_l({{
+ Fd.ud = fpConvert(Fs.ud, LONG_TO_PS);
+ }});
+ }
+ }
+
+ //Table A-17 MIPS64 COP1 Encoding of Function Field When rs=PS1
+ //Note: "1. Format type PS is legal only if 64-bit floating point operations
+ //are enabled. "
+ 0x6: decode FUNCTION_HI {
+ 0x0: decode FUNCTION_LO {
+ format Float64Op {
+ 0x0: add_ps({{
+ Fd1.sf = Fs1.sf + Ft2.sf;
+ Fd2.sf = Fs2.sf + Ft2.sf;
+ }});
+
+ 0x1: sub_ps({{
+ Fd1.sf = Fs1.sf - Ft2.sf;
+ Fd2.sf = Fs2.sf - Ft2.sf;
+ }});
+
+ 0x2: mul_ps({{
+ Fd1.sf = Fs1.sf * Ft2.sf;
+ Fd2.sf = Fs2.sf * Ft2.sf;
+ }});
+
+ 0x5: abs_ps({{
+ Fd1.sf = fabs(Fs1.sf);
+ Fd2.sf = fabs(Fs2.sf);
+ }});
+
+ 0x6: mov_ps({{
+ Fd1.sf = Fs1.sf;
+ Fd2.sf = Fs2.sf;
+ }});
+
+ 0x7: neg_ps({{
+ Fd1.sf = -1 * Fs1.sf;
+ Fd2.sf = -1 * Fs2.sf;
+ }});
+ }
+ }
+
+ 0x2: decode FUNCTION_LO {
+ 0x1: decode MOVCF {
+ format Float64Op {
+ 0x0: movf_ps({{
+ if (getFPConditionCode(FCSR, CC) == 0)
+ Fd1 = Fs1;
+ if (getFPConditionCode(FCSR, CC+1) == 0)
+ Fd2 = Fs2;
+ }});
+
+ 0x1: movt_ps({{
+ if (getFPConditionCode(FCSR, CC) == 1)
+ Fd1 = Fs1;
+ if (getFPConditionCode(FCSR, CC+1) == 1)
+ Fd2 = Fs2;
+ }});
+ }
+ }
+
+ format Float64Op {
+ 0x2: movz_ps({{
+ if (getFPConditionCode(FCSR, CC) == 0)
+ Fd1 = Fs1;
+ if (getFPConditionCode(FCSR, CC) == 0)
+ Fd2 = Fs2;
+ }});
+
+ 0x3: movn_ps({{
+ if (getFPConditionCode(FCSR, CC) == 1)
+ Fd1 = Fs1;
+ if (getFPConditionCode(FCSR, CC) == 1)
+ Fd2 = Fs2;
+ }});
+ }
+
+ }
+
+ 0x4: decode FUNCTION_LO {
+ 0x0: Float64Op::cvt_s_pu({{
+ Fd.uw = fpConvert(Fs2.uw, PU_TO_SINGLE);
+ }});
+ }
+
+ 0x5: decode FUNCTION_LO {
+ format Float64Op {
+ 0x0: cvt_s_pl({{
+ Fd.uw = fpConvert(Fs1.uw, PL_TO_SINGLE);
+ }});
+
+ 0x4: pll({{ Fd.ud = (uint64_t) Fs1.uw << 32 | Ft1.uw; }});
+ 0x5: plu({{ Fd.ud = (uint64_t) Fs1.uw << 32 | Ft2.uw; }});
+ 0x6: pul({{ Fd.ud = (uint64_t) Fs2.uw << 32 | Ft1.uw; }});
+ 0x7: puu({{ Fd.ud = (uint64_t) Fs2.uw << 32 | Ft2.uw; }});
+ }
+ }
+
+ 0x6: decode FUNCTION_LO {
+ format FloatPSCompareOp {
+ 0x0: c_f_ps({{ cond1 = 0; cond2 = 0; }});
+
+ 0x1: c_un_ps({{
+ if (isnan(Fs1.sf) || isnan(Ft1.sf))
+ cond1 = 1;
+ else
+ cond1 = 0;
+
+ if (isnan(Fs2.sf) || isnan(Ft2.sf))
+ cond2 = 1;
+ else
+ cond2 = 0;
+
+ }});
+
+ 0x2: c_eq_ps({{
+ if (isnan(Fs1.sf) || isnan(Ft1.sf))
+ cond1 = 0;
+ else
+ cond1 = (Fs1.sf == Ft1.sf);
+
+ if (isnan(Fs2.sf) || isnan(Ft2.sf))
+ cond2 = 0;
+ else
+ cond2 = (Fs2.sf == Ft2.sf);
+ }});
+
+ 0x3: c_ueq_ps({{
+ if (isnan(Fs1.sf) || isnan(Ft1.sf))
+ cond1 = 1;
+ else
+ cond1 = (Fs1.sf == Ft1.sf);
+
+ if (isnan(Fs2.sf) || isnan(Ft2.sf))
+ cond2 = 1;
+ else
+ cond2 = (Fs2.sf == Ft2.sf);
+ }});
+
+ 0x4: c_olt_ps({{
+ if (isnan(Fs1.sf) || isnan(Ft1.sf))
+ cond1 = 0;
+ else
+ cond1 = (Fs1.sf < Ft1.sf);
+
+ if (isnan(Fs2.sf) || isnan(Ft2.sf))
+ cond2 = 0;
+ else
+ cond2 = (Fs2.sf < Ft2.sf);
+ }});
+
+ 0x5: c_ult_ps({{
+ if (isnan(Fs1.sf) || isnan(Ft1.sf))
+ cond1 = 1;
+ else
+ cond1 = (Fs.sf < Ft.sf);
+
+ if (isnan(Fs2.sf) || isnan(Ft2.sf))
+ cond2 = 1;
+ else
+ cond2 = (Fs2.sf < Ft2.sf);
+ }});
+
+ 0x6: c_ole_ps({{
+ if (isnan(Fs.sf) || isnan(Ft.sf))
+ cond1 = 0;
+ else
+ cond1 = (Fs.sf <= Ft.sf);
+
+ if (isnan(Fs2.sf) || isnan(Ft2.sf))
+ cond2 = 0;
+ else
+ cond2 = (Fs2.sf <= Ft2.sf);
+ }});
+
+ 0x7: c_ule_ps({{
+ if (isnan(Fs1.sf) || isnan(Ft1.sf))
+ cond1 = 1;
+ else
+ cond1 = (Fs1.sf <= Ft1.sf);
+
+ if (isnan(Fs2.sf) || isnan(Ft2.sf))
+ cond2 = 1;
+ else
+ cond2 = (Fs2.sf <= Ft2.sf);
+ }});
+ }
+ }
+
+ 0x7: decode FUNCTION_LO {
+ format FloatPSCompareWithXcptOp {
+ 0x0: c_sf_ps({{ cond1 = 0; cond2 = 0; }});
+
+ 0x1: c_ngle_ps({{
+ if (isnan(Fs1.sf) || isnan(Ft1.sf))
+ cond1 = 1;
+ else
+ cond1 = 0;
+
+ if (isnan(Fs2.sf) || isnan(Ft2.sf))
+ cond2 = 1;
+ else
+ cond2 = 0;
+ }});
+
+ 0x2: c_seq_ps({{
+ if (isnan(Fs1.sf) || isnan(Ft1.sf))
+ cond1 = 0;
+ else
+ cond1 = (Fs1.sf == Ft1.sf);
+
+ if (isnan(Fs2.sf) || isnan(Ft2.sf))
+ cond2 = 0;
+ else
+ cond2 = (Fs2.sf == Ft2.sf);
+ }});
+
+ 0x3: c_ngl_ps({{
+ if (isnan(Fs1.sf) || isnan(Ft1.sf))
+ cond1 = 1;
+ else
+ cond1 = (Fs1.sf == Ft1.sf);
+
+ if (isnan(Fs2.sf) || isnan(Ft2.sf))
+ cond2 = 1;
+ else
+ cond2 = (Fs2.sf == Ft2.sf);
+ }});
+
+ 0x4: c_lt_ps({{
+ if (isnan(Fs1.sf) || isnan(Ft1.sf))
+ cond1 = 0;
+ else
+ cond1 = (Fs1.sf < Ft1.sf);
+
+ if (isnan(Fs2.sf) || isnan(Ft2.sf))
+ cond2 = 0;
+ else
+ cond2 = (Fs2.sf < Ft2.sf);
+ }});
+
+ 0x5: c_nge_ps({{
+ if (isnan(Fs1.sf) || isnan(Ft1.sf))
+ cond1 = 1;
+ else
+ cond1 = (Fs1.sf < Ft1.sf);
+
+ if (isnan(Fs2.sf) || isnan(Ft2.sf))
+ cond2 = 1;
+ else
+ cond2 = (Fs2.sf < Ft2.sf);
+ }});
+
+ 0x6: c_le_ps({{
+ if (isnan(Fs1.sf) || isnan(Ft1.sf))
+ cond1 = 0;
+ else
+ cond1 = (Fs1.sf <= Ft1.sf);
+
+ if (isnan(Fs2.sf) || isnan(Ft2.sf))
+ cond2 = 0;
+ else
+ cond2 = (Fs2.sf <= Ft2.sf);
+ }});
+
+ 0x7: c_ngt_ps({{
+ if (isnan(Fs1.sf) || isnan(Ft1.sf))
+ cond1 = 1;
+ else
+ cond1 = (Fs1.sf <= Ft1.sf);
+
+ if (isnan(Fs2.sf) || isnan(Ft2.sf))
+ cond2 = 1;
+ else
+ cond2 = (Fs2.sf <= Ft2.sf);
+ }});
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //Table A-19 MIPS32 COP2 Encoding of rs Field
+ 0x2: decode RS_MSB {
+ 0x0: decode RS_HI {
+ 0x0: decode RS_LO {
+ format WarnUnimpl {
+ 0x0: mfc2();
+ 0x2: cfc2();
+ 0x3: mfhc2();
+ 0x4: mtc2();
+ 0x6: ctc2();
+ 0x7: mftc2();
+ }
+ }
+
+ 0x1: decode ND {
+ 0x0: decode TF {
+ format WarnUnimpl {
+ 0x0: bc2f();
+ 0x1: bc2t();
+ }
+ }
+
+ 0x1: decode TF {
+ format WarnUnimpl {
+ 0x0: bc2fl();
+ 0x1: bc2tl();
+ }
+ }
+ }
+ }
+ }
+
+ //Table A-20 MIPS64 COP1X Encoding of Function Field 1
+ //Note: "COP1X instructions are legal only if 64-bit floating point
+ //operations are enabled."
+ 0x3: decode FUNCTION_HI {
+ 0x0: decode FUNCTION_LO {
+ format LoadFloatMemory {
+ 0x0: lwxc1({{ Ft.uw = Mem.uw;}}, {{ EA = Rs + Rt; }});
+ 0x1: ldxc1({{ Ft.ud = Mem.ud;}}, {{ EA = Rs + Rt; }});
+ 0x5: luxc1({{ Ft.uw = Mem.ud;}}, {{ EA = Rs + Rt; }});
+ }
+ }
+
+ 0x1: decode FUNCTION_LO {
+ format StoreFloatMemory {
+ 0x0: swxc1({{ Mem.uw = Ft.uw;}}, {{ EA = Rs + Rt; }});
+ 0x1: sdxc1({{ Mem.ud = Ft.ud;}}, {{ EA = Rs + Rt; }});
+ 0x5: suxc1({{ Mem.ud = Ft.ud;}}, {{ EA = Rs + Rt; }});
+ }
+
+ 0x7: WarnUnimpl::prefx();
+ }
+
+ format FloatOp {
+ 0x3: WarnUnimpl::alnv_ps();
+
+ format BasicOp {
+ 0x4: decode FUNCTION_LO {
+ 0x0: madd_s({{ Fd.sf = (Fs.sf * Ft.sf) + Fr.sf; }});
+ 0x1: madd_d({{ Fd.df = (Fs.df * Ft.df) + Fr.df; }});
+ 0x6: madd_ps({{
+ Fd1.sf = (Fs1.df * Ft1.df) + Fr1.df;
+ Fd2.sf = (Fs2.df * Ft2.df) + Fr2.df;
+ }});
+ }
+
+ 0x5: decode FUNCTION_LO {
+ 0x0: msub_s({{ Fd.sf = (Fs.sf * Ft.sf) - Fr.sf; }});
+ 0x1: msub_d({{ Fd.df = (Fs.df * Ft.df) - Fr.df; }});
+ 0x6: msub_ps({{
+ Fd1.sf = (Fs1.df * Ft1.df) - Fr1.df;
+ Fd2.sf = (Fs2.df * Ft2.df) - Fr2.df;
+ }});
+ }
+
+ 0x6: decode FUNCTION_LO {
+ 0x0: nmadd_s({{ Fd.sf = (-1 * Fs.sf * Ft.sf) - Fr.sf; }});
+ 0x1: nmadd_d({{ Fd.df = (-1 * Fs.df * Ft.df) + Fr.df; }});
+ 0x6: nmadd_ps({{
+ Fd1.sf = -1 * ((Fs1.df * Ft1.df) + Fr1.df);
+ Fd2.sf = -1 * ((Fs2.df * Ft2.df) + Fr2.df);
+ }});
+ }
+
+ 0x7: decode FUNCTION_LO {
+ 0x0: nmsub_s({{ Fd.sf = (-1 * Fs.sf * Ft.sf) - Fr.sf; }});
+ 0x1: nmsub_d({{ Fd.df = (-1 * Fs.df * Ft.df) - Fr.df; }});
+ 0x6: nmsub_ps({{
+ Fd1.sf = -1 * ((Fs1.df * Ft1.df) - Fr1.df);
+ Fd2.sf = -1 * ((Fs2.df * Ft2.df) - Fr2.df);
+ }});
+ }
+ }
+ }
+ }
+
+ format BranchLikely {
+ 0x4: beql({{ cond = (Rs.sw == 0); }});
+ 0x5: bnel({{ cond = (Rs.sw != 0); }});
+ 0x6: blezl({{ cond = (Rs.sw <= 0); }});
+ 0x7: bgtzl({{ cond = (Rs.sw > 0); }});
+ }
+ }
+
+ 0x3: decode OPCODE_LO default FailUnimpl::reserved() {
+
+ //Table A-5 MIPS32 SPECIAL2 Encoding of Function Field
+ 0x4: decode FUNCTION_HI {
+
+ 0x0: decode FUNCTION_LO {
+ format IntOp {
+ 0x0: madd({{
+ int64_t temp1 = (int64_t) HI << 32 | LO;
+ temp1 = temp1 + (Rs.sw * Rt.sw);
+ HI = temp1<63:32>;
+ LO = temp1<31:0>;
+ }});
+
+ 0x1: maddu({{
+ int64_t temp1 = (int64_t) HI << 32 | LO;
+ temp1 = temp1 + (Rs.uw * Rt.uw);
+ HI = temp1<63:32>;
+ LO = temp1<31:0>;
+ }});
+
+ 0x2: mul({{ Rd.sw = Rs.sw * Rt.sw; }});
+
+ 0x4: msub({{
+ int64_t temp1 = (int64_t) HI << 32 | LO;
+ temp1 = temp1 - (Rs.sw * Rt.sw);
+ HI = temp1<63:32>;
+ LO = temp1<31:0>;
+ }});
+
+ 0x5: msubu({{
+ int64_t temp1 = (int64_t) HI << 32 | LO;
+ temp1 = temp1 - (Rs.uw * Rt.uw);
+ HI = temp1<63:32>;
+ LO = temp1<31:0>;
+ }});
+ }
+ }
+
+ 0x4: decode FUNCTION_LO {
+ format BasicOp {
+ 0x0: clz({{
+ int cnt = 0;
+ uint32_t mask = 0x80000000;
+ for (int i=0; i < 32; i++) {
+ if( (Rs & mask) == 0) {
+ cnt++;
+ } else {
+ break;
+ }
+ }
+ Rd.uw = cnt;
+ }});
+
+ 0x1: clo({{
+ int cnt = 0;
+ uint32_t mask = 0x80000000;
+ for (int i=0; i < 32; i++) {
+ if( (Rs & mask) != 0) {
+ cnt++;
+ } else {
+ break;
+ }
+ }
+ Rd.uw = cnt;
+ }});
+ }
+ }
+
+ 0x7: decode FUNCTION_LO {
+ 0x7: WarnUnimpl::sdbbp();
+ }
+ }
+
+ //Table A-6 MIPS32 SPECIAL3 Encoding of Function Field for Release 2 of the Architecture
+ 0x7: decode FUNCTION_HI {
+
+ 0x0: decode FUNCTION_LO {
+ format FailUnimpl {
+ 0x1: ext();
+ 0x4: ins();
+ }
+ }
+
+ 0x1: decode FUNCTION_LO {
+ format FailUnimpl {
+ 0x0: fork();
+ 0x1: yield();
+ }
+ }
+
+
+ //Table A-10 MIPS32 BSHFL Encoding of sa Field
+ 0x4: decode SA {
+
+ 0x02: FailUnimpl::wsbh();
+
+ format BasicOp {
+ 0x10: seb({{ Rd.sw = Rt.sw<7:0>}});
+ 0x18: seh({{ Rd.sw = Rt.sw<15:0>}});
+ }
+ }
+
+ 0x6: decode FUNCTION_LO {
+ 0x7: FailUnimpl::rdhwr();//{{ /*Rt = xc->hwRegs[RD];*/ }}
+ }
+ }
+ }
+
+ 0x4: decode OPCODE_LO default FailUnimpl::reserved() {
+ format LoadMemory {
+ 0x0: lb({{ Rt.sw = Mem.sb; }});
+ 0x1: lh({{ Rt.sw = Mem.sh; }});
+
+ 0x2: lwl({{
+ uint32_t mem_word = Mem.uw;
+ uint32_t unalign_addr = Rs + disp;
+ uint32_t offset = unalign_addr & 0x00000003;
+#if BYTE_ORDER == BIG_ENDIAN
+ switch(offset)
+ {
+ case 0:
+ Rt = mem_word;
+ break;
+
+ case 1:
+ Rt &= 0x000F;
+ Rt |= (mem_word << 4);
+ break;
+
+ case 2:
+ Rt &= 0x00FF;
+ Rt |= (mem_word << 8);
+ break;
+
+ case 3:
+ Rt &= 0x0FFF;
+ Rt |= (mem_word << 12);
+ break;
+
+ default:
+ panic("lwl: bad offset");
+ }
+#elif BYTE_ORDER == LITTLE_ENDIAN
+ switch(offset)
+ {
+ case 0:
+ Rt &= 0x0FFF;
+ Rt |= (mem_word << 12);
+ break;
+
+ case 1:
+ Rt &= 0x00FF;
+ Rt |= (mem_word << 8);
+ break;
+
+ case 2:
+ Rt &= 0x000F;
+ Rt |= (mem_word << 4);
+ break;
+
+ case 3:
+ Rt = mem_word;
+ break;
+
+ default:
+ panic("lwl: bad offset");
+ }
+#endif
+ }}, {{ EA = (Rs + disp) & ~3; }});
+
+ 0x3: lw({{ Rt.sw = Mem.sw; }});
+ 0x4: lbu({{ Rt.uw = Mem.ub; }});
+ 0x5: lhu({{ Rt.uw = Mem.uh; }});
+ 0x6: lwr({{
+ uint32_t mem_word = Mem.uw;
+ uint32_t unalign_addr = Rs + disp;
+ uint32_t offset = unalign_addr & 0x00000003;
+
+#if BYTE_ORDER == BIG_ENDIAN
+ switch(offset)
+ {
+ case 0: Rt &= 0xFFF0; Rt |= (mem_word >> 12); break;
+ case 1: Rt &= 0xFF00; Rt |= (mem_word >> 8); break;
+ case 2: Rt &= 0xF000; Rt |= (mem_word >> 4); break;
+ case 3: Rt = mem_word; break;
+ default: panic("lwr: bad offset");
+ }
+#elif BYTE_ORDER == LITTLE_ENDIAN
+ switch(offset)
+ {
+ case 0: Rt = mem_word; break;
+ case 1: Rt &= 0xF000; Rt |= (mem_word >> 4); break;
+ case 2: Rt &= 0xFF00; Rt |= (mem_word >> 8); break;
+ case 3: Rt &= 0xFFF0; Rt |= (mem_word >> 12); break;
+ default: panic("lwr: bad offset");
+ }
+#endif
+ }},
+ {{ EA = (Rs + disp) & ~3; }});
+ }
+ }
+
+ 0x5: decode OPCODE_LO default FailUnimpl::reserved() {
+ format StoreMemory {
+ 0x0: sb({{ Mem.ub = Rt<7:0>; }});
+ 0x1: sh({{ Mem.uh = Rt<15:0>; }});
+ 0x2: swl({{
+ uint32_t mem_word = 0;
+ uint32_t aligned_addr = (Rs + disp) & ~3;
+ uint32_t unalign_addr = Rs + disp;
+ uint32_t offset = unalign_addr & 0x00000003;
+
+ DPRINTF(IEW,"Execute: aligned=0x%x unaligned=0x%x\n offset=0x%x",
+ aligned_addr,unalign_addr,offset);
+
+ fault = xc->read(aligned_addr, (uint32_t&)mem_word, memAccessFlags);
+
+#if BYTE_ORDER == BIG_ENDIAN
+ switch(offset)
+ {
+ case 0:
+ Mem = Rt;
+ break;
+
+ case 1:
+ mem_word &= 0xF000;
+ mem_word |= (Rt >> 4);
+ Mem = mem_word;
+ break;
+
+ case 2:
+ mem_word &= 0xFF00;
+ mem_word |= (Rt >> 8);
+ Mem = mem_word;
+ break;
+
+ case 3:
+ mem_word &= 0xFFF0;
+ mem_word |= (Rt >> 12);
+ Mem = mem_word;
+ break;
+
+ default:
+ panic("swl: bad offset");
+ }
+#elif BYTE_ORDER == LITTLE_ENDIAN
+ switch(offset)
+ {
+ case 0:
+ mem_word &= 0xFFF0;
+ mem_word |= (Rt >> 12);
+ Mem = mem_word;
+ break;
+
+ case 1:
+ mem_word &= 0xFF00;
+ mem_word |= (Rt >> 8);
+ Mem = mem_word;
+ break;
+
+ case 2:
+ mem_word &= 0xF000;
+ mem_word |= (Rt >> 4);
+ Mem = mem_word;
+ break;
+
+ case 3:
+ Mem = Rt;
+ break;
+
+ default:
+ panic("swl: bad offset");
+ }
+#endif
+ }},{{ EA = (Rs + disp) & ~3; }},mem_flags = NO_ALIGN_FAULT);
+
+ 0x3: sw({{ Mem.uw = Rt<31:0>; }});
+
+ 0x6: swr({{
+ uint32_t mem_word = 0;
+ uint32_t aligned_addr = (Rs + disp) & ~3;
+ uint32_t unalign_addr = Rs + disp;
+ uint32_t offset = unalign_addr & 0x00000003;
+
+ fault = xc->read(aligned_addr, (uint32_t&)mem_word, memAccessFlags);
+
+#if BYTE_ORDER == BIG_ENDIAN
+ switch(offset)
+ {
+ case 0:
+ mem_word &= 0x0FFF;
+ mem_word |= (Rt << 12);
+ Mem = mem_word;
+ break;
+
+ case 1:
+ mem_word &= 0x00FF;
+ mem_word |= (Rt << 8);
+ Mem = mem_word;
+ break;
+
+ case 2:
+ mem_word &= 0x000F;
+ mem_word |= (Rt << 4);
+ Mem = mem_word;
+ break;
+
+ case 3:
+ Mem = Rt;
+ break;
+
+ default:
+ panic("swr: bad offset");
+ }
+#elif BYTE_ORDER == LITTLE_ENDIAN
+ switch(offset)
+ {
+ case 0:
+ Mem = Rt;
+ break;
+
+ case 1:
+ mem_word &= 0x000F;
+ mem_word |= (Rt << 4);
+ Mem = mem_word;
+ break;
+
+ case 2:
+ mem_word &= 0x00FF;
+ mem_word |= (Rt << 8);
+ Mem = mem_word;
+ break;
+
+ case 3:
+ mem_word &= 0x0FFF;
+ mem_word |= (Rt << 12);
+ Mem = mem_word;
+ break;
+
+ default:
+ panic("swr: bad offset");
+ }
+#endif
+ }},{{ EA = (Rs + disp) & ~3;}},mem_flags = NO_ALIGN_FAULT);
+ }
+
+ format WarnUnimpl {
+ 0x7: cache();
+ }
+
+ }
+
+ 0x6: decode OPCODE_LO default FailUnimpl::reserved() {
+ 0x0: LoadMemory::ll({{Rt.uw = Mem.uw}},mem_flags=LOCKED);
+
+ format LoadFloatMemory {
+ 0x1: lwc1({{ Ft.uw = Mem.uw; }});
+ 0x5: ldc1({{ Ft.ud = Mem.ud; }});
+ }
+ }
+
+
+ 0x7: decode OPCODE_LO default FailUnimpl::reserved() {
+ 0x0: StoreMemory::sc({{ Mem.uw = Rt.uw; Rt.uw = 1; }});
+
+ format StoreFloatMemory {
+ 0x1: swc1({{ Mem.uw = Ft.uw; }});
+ 0x5: sdc1({{ Mem.ud = Ft.ud; }});
+ }
+ }
+}
+
+
diff --git a/src/arch/mips/isa/formats/basic.isa b/src/arch/mips/isa/formats/basic.isa
new file mode 100644
index 000000000..c02af7ddc
--- /dev/null
+++ b/src/arch/mips/isa/formats/basic.isa
@@ -0,0 +1,66 @@
+// -*- mode:c++ -*-
+
+// Declarations for execute() methods.
+def template BasicExecDeclare {{
+ Fault execute(%(CPU_exec_context)s *, Trace::InstRecord *) const;
+}};
+
+// Basic instruction class declaration template.
+def template BasicDeclare {{
+ /**
+ * Static instruction class for "%(mnemonic)s".
+ */
+ class %(class_name)s : public %(base_class)s
+ {
+ public:
+ /// Constructor.
+ %(class_name)s(MachInst machInst);
+ %(BasicExecDeclare)s
+ };
+}};
+
+// Basic instruction class constructor template.
+def template BasicConstructor {{
+ inline %(class_name)s::%(class_name)s(MachInst machInst) : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s)
+ {
+ %(constructor)s;
+ }
+}};
+
+// Basic instruction class execute method template.
+def template BasicExecute {{
+ Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const
+ {
+ Fault fault = NoFault;
+
+ %(fp_enable_check)s;
+ %(op_decl)s;
+ %(op_rd)s;
+ %(code)s;
+
+ if(fault == NoFault)
+ {
+ %(op_wb)s;
+ }
+ return fault;
+ }
+}};
+
+// Basic decode template.
+def template BasicDecode {{
+ return new %(class_name)s(machInst);
+}};
+
+// Basic decode template, passing mnemonic in as string arg to constructor.
+def template BasicDecodeWithMnemonic {{
+ return new %(class_name)s("%(mnemonic)s", machInst);
+}};
+
+// The most basic instruction format... used only for a few misc. insts
+def format BasicOp(code, *flags) {{
+ iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
+}};
diff --git a/src/arch/mips/isa/formats/branch.isa b/src/arch/mips/isa/formats/branch.isa
new file mode 100644
index 000000000..8cfa37a20
--- /dev/null
+++ b/src/arch/mips/isa/formats/branch.isa
@@ -0,0 +1,324 @@
+// -*- mode:c++ -*-
+
+////////////////////////////////////////////////////////////////////
+//
+// Control transfer instructions
+//
+
+output header {{
+
+#include <iostream>
+ using namespace std;
+
+ /**
+ * Base class for instructions whose disassembly is not purely a
+ * function of the machine instruction (i.e., it depends on the
+ * PC). This class overrides the disassemble() method to check
+ * the PC and symbol table values before re-using a cached
+ * disassembly string. This is necessary for branches and jumps,
+ * where the disassembly string includes the target address (which
+ * may depend on the PC and/or symbol table).
+ */
+ class PCDependentDisassembly : public MipsStaticInst
+ {
+ protected:
+ /// Cached program counter from last disassembly
+ mutable Addr cachedPC;
+
+ /// Cached symbol table pointer from last disassembly
+ mutable const SymbolTable *cachedSymtab;
+
+ /// Constructor
+ PCDependentDisassembly(const char *mnem, MachInst _machInst,
+ OpClass __opClass)
+ : MipsStaticInst(mnem, _machInst, __opClass),
+ cachedPC(0), cachedSymtab(0)
+ {
+ }
+
+ const std::string &
+ disassemble(Addr pc, const SymbolTable *symtab) const;
+ };
+
+ /**
+ * Base class for branches (PC-relative control transfers),
+ * conditional or unconditional.
+ */
+ class Branch : public PCDependentDisassembly
+ {
+ protected:
+ /// target address (signed) Displacement .
+ int32_t disp;
+
+ /// Constructor.
+ Branch(const char *mnem, MachInst _machInst, OpClass __opClass)
+ : PCDependentDisassembly(mnem, _machInst, __opClass),
+ disp(OFFSET << 2)
+ {
+ //If Bit 17 is 1 then Sign Extend
+ if ( (disp & 0x00020000) > 0 ) {
+ disp |= 0xFFFE0000;
+ }
+ }
+
+ Addr branchTarget(Addr branchPC) const;
+
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+
+ /**
+ * Base class for branch likely branches (PC-relative control transfers),
+ */
+ class BranchLikely : public PCDependentDisassembly
+ {
+ protected:
+ /// target address (signed) Displacement .
+ int32_t disp;
+
+ /// Constructor.
+ BranchLikely(const char *mnem, MachInst _machInst, OpClass __opClass)
+ : PCDependentDisassembly(mnem, _machInst, __opClass),
+ disp(OFFSET << 2)
+ {
+
+ }
+
+ Addr branchTarget(Addr branchPC) const;
+
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+
+ /**
+ * Base class for jumps (register-indirect control transfers). In
+ * the Mips ISA, these are always unconditional.
+ */
+ class Jump : public PCDependentDisassembly
+ {
+ protected:
+
+ /// Displacement to target address (signed).
+ int32_t disp;
+
+ uint32_t target;
+
+ public:
+ /// Constructor
+ Jump(const char *mnem, MachInst _machInst, OpClass __opClass)
+ : PCDependentDisassembly(mnem, _machInst, __opClass),
+ disp(JMPTARG << 2)
+ {
+ }
+
+ Addr branchTarget(ExecContext *xc) const;
+
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+}};
+
+output decoder {{
+ Addr
+ Branch::branchTarget(Addr branchPC) const
+ {
+ return branchPC + 4 + disp;
+ }
+
+ Addr
+ BranchLikely::branchTarget(Addr branchPC) const
+ {
+ return branchPC + 4 + disp;
+ }
+
+ Addr
+ Jump::branchTarget(ExecContext *xc) const
+ {
+ Addr NPC = xc->readPC() + 4;
+ uint64_t Rb = xc->readIntReg(_srcRegIdx[0]);
+ return (Rb & ~3) | (NPC & 1);
+ }
+
+ const std::string &
+ PCDependentDisassembly::disassemble(Addr pc,
+ const SymbolTable *symtab) const
+ {
+ if (!cachedDisassembly ||
+ pc != cachedPC || symtab != cachedSymtab)
+ {
+ if (cachedDisassembly)
+ delete cachedDisassembly;
+
+ cachedDisassembly =
+ new std::string(generateDisassembly(pc, symtab));
+ cachedPC = pc;
+ cachedSymtab = symtab;
+ }
+
+ return *cachedDisassembly;
+ }
+
+ std::string
+ Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+ std::stringstream ss;
+
+ ccprintf(ss, "%-10s ", mnemonic);
+
+ // There's only one register arg (RA), but it could be
+ // either a source (the condition for conditional
+ // branches) or a destination (the link reg for
+ // unconditional branches)
+ if (_numSrcRegs == 1) {
+ printReg(ss, _srcRegIdx[0]);
+ ss << ",";
+ } else if(_numSrcRegs == 2) {
+ printReg(ss, _srcRegIdx[0]);
+ ss << ",";
+ printReg(ss, _srcRegIdx[1]);
+ ss << ",";
+ }
+
+ Addr target = pc + 4 + disp;
+
+ std::string str;
+ if (symtab && symtab->findSymbol(target, str))
+ ss << str;
+ else
+ ccprintf(ss, "0x%x", target);
+
+ string inst_name = mnemonic;
+
+ if (inst_name.substr(inst_name.length()-2,inst_name.length()) == "al"){
+ ccprintf(ss, " (r31=0x%x)",pc+8);
+ }
+
+ return ss.str();
+ }
+
+ std::string
+ BranchLikely::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+ std::stringstream ss;
+
+ ccprintf(ss, "%-10s ", mnemonic);
+
+ // There's only one register arg (RA), but it could be
+ // either a source (the condition for conditional
+ // branches) or a destination (the link reg for
+ // unconditional branches)
+ if (_numSrcRegs > 0) {
+ printReg(ss, _srcRegIdx[0]);
+ ss << ",";
+ }
+ else if (_numDestRegs > 0) {
+ printReg(ss, _destRegIdx[0]);
+ ss << ",";
+ }
+
+ Addr target = pc + 4 + disp;
+
+ std::string str;
+ if (symtab && symtab->findSymbol(target, str))
+ ss << str;
+ else
+ ccprintf(ss, "0x%x", target);
+
+ return ss.str();
+ }
+
+ std::string
+ Jump::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+ std::stringstream ss;
+
+ ccprintf(ss, "%-10s ", mnemonic);
+
+ if ( mnemonic == "jal" ) {
+ Addr npc = pc + 4;
+ ccprintf(ss,"0x%x",(npc & 0xF0000000) | disp);
+ } else if (_numSrcRegs == 0) {
+ std::string str;
+ if (symtab && symtab->findSymbol(disp, str))
+ ss << str;
+ else
+ ccprintf(ss, "0x%x", disp);
+ } else if (_numSrcRegs == 1) {
+ printReg(ss, _srcRegIdx[0]);
+ } else if(_numSrcRegs == 2) {
+ printReg(ss, _srcRegIdx[0]);
+ ss << ",";
+ printReg(ss, _srcRegIdx[1]);
+ } else {
+ panic(">= 3 Source Registers!!!");
+ }
+
+ return ss.str();
+ }
+}};
+
+def format Branch(code,*flags) {{
+ #Add Link Code if Link instruction
+ strlen = len(name)
+ if name[strlen-2:] == 'al':
+ code += 'R31 = NNPC;\n'
+
+ #Condition code
+ code = 'bool cond;\n' + code
+ code += 'if (cond) {\n'
+ code += ' NNPC = NPC + disp;\n'
+ code += '} else {\n'
+ code += ' NNPC = NNPC;\n'
+ code += '} \n'
+
+ iop = InstObjParams(name, Name, 'Branch', CodeBlock(code),
+ ('IsDirectControl', 'IsCondControl'))
+
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
+}};
+
+
+def format BranchLikely(code,*flags) {{
+ #Add Link Code if Link instruction
+ strlen = len(name)
+ if name[strlen-3:] == 'all':
+ code += 'R31 = NNPC;\n'
+
+ #Condition code
+ code = 'bool cond;\n' + code
+ code += 'if (cond) {'
+ code += 'NNPC = NPC + disp;\n'
+ code += '} \n'
+
+
+ iop = InstObjParams(name, Name, 'Branch', CodeBlock(code),
+ ('IsDirectControl', 'IsCondControl','IsCondDelaySlot'))
+
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
+}};
+
+def format Jump(code,*flags) {{
+ #Add Link Code if Link instruction
+ strlen = len(name)
+ if strlen > 1 and name[1:] == 'al':
+ code = 'R31 = NNPC;\n' + code
+
+
+ iop = InstObjParams(name, Name, 'Jump', CodeBlock(code),\
+ ('IsIndirectControl', 'IsUncondControl'))
+
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
+}};
+
+
+
+
diff --git a/src/arch/mips/isa/formats/formats.isa b/src/arch/mips/isa/formats/formats.isa
new file mode 100644
index 000000000..7d493ffae
--- /dev/null
+++ b/src/arch/mips/isa/formats/formats.isa
@@ -0,0 +1,35 @@
+// -*- mode:c++ -*-
+
+//Templates from this format are used later
+//Include the basic format
+##include "basic.isa"
+
+//Include the basic format
+##include "noop.isa"
+
+//Include utility functions
+##include "util.isa"
+
+//Include the cop0 formats
+##include "cop0.isa"
+
+//Include the integer formats
+##include "int.isa"
+
+//Include the floatOp format
+##include "fp.isa"
+
+//Include the mem format
+##include "mem.isa"
+
+//Include the trap format
+##include "trap.isa"
+
+//Include the branch format
+##include "branch.isa"
+
+//Include the noop format
+##include "unimp.isa"
+
+//Include the noop format
+##include "unknown.isa"
diff --git a/src/arch/mips/isa/formats/fp.isa b/src/arch/mips/isa/formats/fp.isa
new file mode 100644
index 000000000..9f2c24755
--- /dev/null
+++ b/src/arch/mips/isa/formats/fp.isa
@@ -0,0 +1,109 @@
+// -*- mode:c++ -*-
+
+////////////////////////////////////////////////////////////////////
+//
+// Floating Point operate instructions
+//
+
+output header {{
+ /**
+ * Base class for FP operations.
+ */
+ class FPOp : public MipsStaticInst
+ {
+ protected:
+
+ /// Constructor
+ FPOp(const char *mnem, MachInst _machInst, OpClass __opClass) : MipsStaticInst(mnem, _machInst, __opClass)
+ {
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+}};
+
+output decoder {{
+ std::string FPOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+ return "Disassembly of integer instruction\n";
+ }
+}};
+
+
+// Primary format for float operate instructions:
+def format FloatOp(code, *flags) {{
+ iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
+}};
+
+def format FloatCompareOp(code, *flags) {{
+ code = 'bool cond;\n' + code
+ code += 'FCSR = makeCCVector(FCSR, CC,cond);\n'
+ iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
+}};
+
+def format FloatCompareWithXcptOp(code, *flags) {{
+ code = 'bool cond;\n' + code
+ code += 'FCSR = makeCCVector(FCSR, CC,cond);\n'
+ iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
+}};
+
+def format FloatConvertOp(code, *flags) {{
+ iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
+}};
+
+// Primary format for float64 operate instructions:
+def format Float64Op(code, *flags) {{
+ iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
+}};
+
+def format Float64ConvertOp(code, *flags) {{
+ code = 'bool cond;\n' + code
+ code += 'FCSR = makeCCVector(FCSR, CC,cond);\n'
+ iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
+}};
+
+def format FloatPSCompareOp(code, *flags) {{
+ code = 'bool cond1;\nbool cond2;\n' + code
+ code += 'FCSR = makeCCVector(FCSR, CC+1, cond1);\n'
+ code += 'FCSR = makeCCVector(FCSR, CC, cond2);\n'
+ iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
+}};
+
+def format FloatPSCompareWithXcptOp(code, *flags) {{
+ code = 'bool cond1;\nbool cond2;\n' + code
+ code += 'FCSR = makeCCVector(FCSR, CC+1, cond1);\n'
+ code += 'FCSR = makeCCVector(FCSR, CC, cond2);\n'
+ iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
+}};
diff --git a/src/arch/mips/isa/formats/int.isa b/src/arch/mips/isa/formats/int.isa
new file mode 100644
index 000000000..7d38b9ff5
--- /dev/null
+++ b/src/arch/mips/isa/formats/int.isa
@@ -0,0 +1,131 @@
+// -*- mode:c++ -*-
+
+////////////////////////////////////////////////////////////////////
+//
+// Integer operate instructions
+//
+
+//Outputs to decoder.hh
+output header {{
+#include <iostream>
+ using namespace std;
+ /**
+ * Base class for integer operations.
+ */
+ class IntOp : public MipsStaticInst
+ {
+ protected:
+
+ /// Constructor
+ IntOp(const char *mnem, MachInst _machInst, OpClass __opClass) :
+ MipsStaticInst(mnem, _machInst, __opClass)
+ {
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+
+ class IntImmOp : public MipsStaticInst
+ {
+ protected:
+
+ int16_t imm;
+ int32_t sextImm;
+ uint32_t zextImm;
+
+ /// Constructor
+ IntImmOp(const char *mnem, MachInst _machInst, OpClass __opClass) :
+ MipsStaticInst(mnem, _machInst, __opClass),imm(INTIMM),
+ sextImm(INTIMM),zextImm(0x0000FFFF & INTIMM)
+ {
+ //If Bit 15 is 1 then Sign Extend
+ int32_t temp = sextImm & 0x00008000;
+ if (temp > 0 && mnemonic != "lui") {
+ sextImm |= 0xFFFF0000;
+ }
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+
+
+ };
+
+}};
+
+//Outputs to decoder.cc
+output decoder {{
+ std::string IntOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+ std::stringstream ss;
+
+ ccprintf(ss, "%-10s ", mnemonic);
+
+ // just print the first dest... if there's a second one,
+ // it's generally implicit
+ if (_numDestRegs > 0) {
+ printReg(ss, _destRegIdx[0]);
+ ss << ",";
+ }
+
+ // just print the first two source regs... if there's
+ // a third one, it's a read-modify-write dest (Rc),
+ // e.g. for CMOVxx
+ if (_numSrcRegs > 0) {
+ printReg(ss, _srcRegIdx[0]);
+ }
+
+ if (_numSrcRegs > 1) {
+ ss << ",";
+ printReg(ss, _srcRegIdx[1]);
+ }
+
+ return ss.str();
+ }
+
+ std::string IntImmOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+ std::stringstream ss;
+
+ ccprintf(ss, "%-10s ", mnemonic);
+
+ if (_numDestRegs > 0) {
+ printReg(ss, _destRegIdx[0]);
+ }
+
+ ss << ",";
+
+ if (_numSrcRegs > 0) {
+ printReg(ss, _srcRegIdx[0]);
+ ss << ",";
+ }
+
+ if( mnemonic == "lui")
+ ccprintf(ss, "%08p ", sextImm);
+ else
+ ss << (int) sextImm;
+
+ return ss.str();
+ }
+
+}};
+
+//Used by decoder.isa
+def format IntOp(code, *opt_flags) {{
+ orig_code = code
+ cblk = CodeBlock(code)
+
+ # Figure out if we are creating a IntImmOp or a IntOp
+ # by looking at the instruction name
+ iop = InstObjParams(name, Name, 'IntOp', cblk, opt_flags)
+ strlen = len(name)
+ if name[strlen-1] == 'i' or name[strlen-2:] == 'iu':
+ iop = InstObjParams(name, Name, 'IntImmOp', cblk, opt_flags)
+
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = OperateNopCheckDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
+}};
+
+
+
diff --git a/src/arch/mips/isa/formats/mem.isa b/src/arch/mips/isa/formats/mem.isa
new file mode 100644
index 000000000..e2afc7252
--- /dev/null
+++ b/src/arch/mips/isa/formats/mem.isa
@@ -0,0 +1,473 @@
+// -*- mode:c++ -*-
+
+// Copyright (c) 2003-2005 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+output header {{
+ /**
+ * Base class for general Mips memory-format instructions.
+ */
+ class Memory : public MipsStaticInst
+ {
+ protected:
+
+ /// Memory request flags. See mem_req_base.hh.
+ unsigned memAccessFlags;
+ /// Pointer to EAComp object.
+ const StaticInstPtr eaCompPtr;
+ /// Pointer to MemAcc object.
+ const StaticInstPtr memAccPtr;
+
+ /// Displacement for EA calculation (signed).
+ int32_t disp;
+
+ /// Constructor
+ Memory(const char *mnem, MachInst _machInst, OpClass __opClass,
+ StaticInstPtr _eaCompPtr = nullStaticInstPtr,
+ StaticInstPtr _memAccPtr = nullStaticInstPtr)
+ : MipsStaticInst(mnem, _machInst, __opClass),
+ memAccessFlags(0), eaCompPtr(_eaCompPtr), memAccPtr(_memAccPtr),
+ disp(OFFSET)
+ {
+ //If Bit 15 is 1 then Sign Extend
+ int32_t temp = disp & 0x00008000;
+
+ if (temp > 0) {
+ disp |= 0xFFFF0000;
+ }
+ }
+
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+
+ public:
+
+ const StaticInstPtr &eaCompInst() const { return eaCompPtr; }
+ const StaticInstPtr &memAccInst() const { return memAccPtr; }
+ };
+
+}};
+
+
+output decoder {{
+ std::string
+ Memory::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+ return csprintf("%-10s %c%d,%d(r%d)", mnemonic,
+ flags[IsFloating] ? 'f' : 'r', RT, disp, RS);
+ }
+
+}};
+
+def format LoadAddress(code) {{
+ iop = InstObjParams(name, Name, 'MemoryDisp32', CodeBlock(code))
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
+}};
+
+
+def template LoadStoreDeclare {{
+ /**
+ * Static instruction class for "%(mnemonic)s".
+ */
+ class %(class_name)s : public %(base_class)s
+ {
+ protected:
+
+ /**
+ * "Fake" effective address computation class for "%(mnemonic)s".
+ */
+ class EAComp : public %(base_class)s
+ {
+ public:
+ /// Constructor
+ EAComp(MachInst machInst);
+
+ %(BasicExecDeclare)s
+ };
+
+ /**
+ * "Fake" memory access instruction class for "%(mnemonic)s".
+ */
+ class MemAcc : public %(base_class)s
+ {
+ public:
+ /// Constructor
+ MemAcc(MachInst machInst);
+
+ %(BasicExecDeclare)s
+ };
+
+ public:
+
+ /// Constructor.
+ %(class_name)s(MachInst machInst);
+
+ %(BasicExecDeclare)s
+
+ %(InitiateAccDeclare)s
+
+ %(CompleteAccDeclare)s
+ };
+}};
+
+
+def template InitiateAccDeclare {{
+ Fault initiateAcc(%(CPU_exec_context)s *, Trace::InstRecord *) const;
+}};
+
+
+def template CompleteAccDeclare {{
+ Fault completeAcc(uint8_t *, %(CPU_exec_context)s *, Trace::InstRecord *) const;
+}};
+
+
+def template LoadStoreConstructor {{
+ /** TODO: change op_class to AddrGenOp or something (requires
+ * creating new member of OpClass enum in op_class.hh, updating
+ * config files, etc.). */
+ inline %(class_name)s::EAComp::EAComp(MachInst machInst)
+ : %(base_class)s("%(mnemonic)s (EAComp)", machInst, IntAluOp)
+ {
+ %(ea_constructor)s;
+ }
+
+ inline %(class_name)s::MemAcc::MemAcc(MachInst machInst)
+ : %(base_class)s("%(mnemonic)s (MemAcc)", machInst, %(op_class)s)
+ {
+ %(memacc_constructor)s;
+ }
+
+ inline %(class_name)s::%(class_name)s(MachInst machInst)
+ : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s,
+ new EAComp(machInst), new MemAcc(machInst))
+ {
+ %(constructor)s;
+ }
+}};
+
+
+def template EACompExecute {{
+ Fault
+ %(class_name)s::EAComp::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ Addr EA;
+ Fault fault = NoFault;
+
+ %(fp_enable_check)s;
+ %(op_decl)s;
+ %(op_rd)s;
+ %(code)s;
+
+ if (fault == NoFault) {
+ %(op_wb)s;
+ xc->setEA(EA);
+ }
+
+ return fault;
+ }
+}};
+
+def template LoadMemAccExecute {{
+ Fault
+ %(class_name)s::MemAcc::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ Addr EA;
+ Fault fault = NoFault;
+
+ %(fp_enable_check)s;
+ %(op_decl)s;
+ %(op_rd)s;
+ EA = xc->getEA();
+
+ if (fault == NoFault) {
+ fault = xc->read(EA, (uint%(mem_acc_size)d_t&)Mem, memAccessFlags);
+ %(code)s;
+ }
+
+ if (fault == NoFault) {
+ %(op_wb)s;
+ }
+
+ return fault;
+ }
+}};
+
+
+def template LoadExecute {{
+ Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ Addr EA;
+ Fault fault = NoFault;
+
+ %(fp_enable_check)s;
+ %(op_decl)s;
+ %(op_rd)s;
+ %(ea_code)s;
+
+ if (fault == NoFault) {
+ fault = xc->read(EA, (uint%(mem_acc_size)d_t&)Mem, memAccessFlags);
+ %(memacc_code)s;
+ }
+
+ if (fault == NoFault) {
+ %(op_wb)s;
+ }
+
+ return fault;
+ }
+}};
+
+
+def template LoadInitiateAcc {{
+ Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ Addr EA;
+ Fault fault = NoFault;
+
+ %(fp_enable_check)s;
+ %(op_src_decl)s;
+ %(op_rd)s;
+ %(ea_code)s;
+
+ if (fault == NoFault) {
+ fault = xc->read(EA, (uint%(mem_acc_size)d_t &)Mem, memAccessFlags);
+ }
+
+ return fault;
+ }
+}};
+
+
+def template LoadCompleteAcc {{
+ Fault %(class_name)s::completeAcc(uint8_t *data,
+ %(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ Fault fault = NoFault;
+
+ %(fp_enable_check)s;
+ %(op_decl)s;
+
+ memcpy(&Mem, data, sizeof(Mem));
+
+ if (fault == NoFault) {
+ %(memacc_code)s;
+ }
+
+ if (fault == NoFault) {
+ %(op_wb)s;
+ }
+
+ return fault;
+ }
+}};
+
+
+def template StoreMemAccExecute {{
+ Fault
+ %(class_name)s::MemAcc::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ Addr EA;
+ Fault fault = NoFault;
+ uint64_t write_result = 0;
+
+ %(fp_enable_check)s;
+ %(op_decl)s;
+ %(op_rd)s;
+ EA = xc->getEA();
+
+ if (fault == NoFault) {
+ %(code)s;
+ }
+
+ if (fault == NoFault) {
+ fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA,
+ memAccessFlags, &write_result);
+ if (traceData) { traceData->setData(Mem); }
+ }
+
+ if (fault == NoFault) {
+ %(postacc_code)s;
+ }
+
+ if (fault == NoFault) {
+ %(op_wb)s;
+ }
+
+ return fault;
+ }
+}};
+
+
+def template StoreExecute {{
+ Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ Addr EA;
+ Fault fault = NoFault;
+ uint64_t write_result = 0;
+
+ %(fp_enable_check)s;
+ %(op_decl)s;
+ %(op_rd)s;
+ %(ea_code)s;
+
+ if (fault == NoFault) {
+ %(memacc_code)s;
+ }
+
+ if (fault == NoFault) {
+ fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA,
+ memAccessFlags, &write_result);
+ if (traceData) { traceData->setData(Mem); }
+ }
+
+ if (fault == NoFault) {
+ %(postacc_code)s;
+ }
+
+ if (fault == NoFault) {
+ %(op_wb)s;
+ }
+
+ return fault;
+ }
+}};
+
+def template StoreInitiateAcc {{
+ Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ Addr EA;
+ Fault fault = NoFault;
+ uint64_t write_result = 0;
+
+ %(fp_enable_check)s;
+ %(op_decl)s;
+ %(op_rd)s;
+ %(ea_code)s;
+
+ if (fault == NoFault) {
+ %(memacc_code)s;
+ }
+
+ if (fault == NoFault) {
+ fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA,
+ memAccessFlags, &write_result);
+ if (traceData) { traceData->setData(Mem); }
+ }
+
+ return fault;
+ }
+}};
+
+
+def template StoreCompleteAcc {{
+ Fault %(class_name)s::completeAcc(uint8_t *data,
+ %(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ Fault fault = NoFault;
+ uint64_t write_result = 0;
+
+ %(fp_enable_check)s;
+ %(op_dest_decl)s;
+
+ memcpy(&write_result, data, sizeof(write_result));
+
+ if (fault == NoFault) {
+ %(postacc_code)s;
+ }
+
+ if (fault == NoFault) {
+ %(op_wb)s;
+ }
+
+ return fault;
+ }
+}};
+
+// load instructions use Rt as dest, so check for
+// Rt == 31 to detect nops
+def template LoadNopCheckDecode {{
+ {
+ MipsStaticInst *i = new %(class_name)s(machInst);
+ if (RT == 0) {
+ i = makeNop(i);
+ }
+ return i;
+ }
+}};
+
+def format LoadMemory(memacc_code, ea_code = {{ EA = Rs + disp; }},
+ mem_flags = [], inst_flags = []) {{
+ (header_output, decoder_output, decode_block, exec_output) = \
+ LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
+ decode_template = LoadNopCheckDecode,
+ exec_template_base = 'Load')
+}};
+
+
+def format StoreMemory(memacc_code, ea_code = {{ EA = Rs + disp; }},
+ mem_flags = [], inst_flags = []) {{
+ (header_output, decoder_output, decode_block, exec_output) = \
+ LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
+ exec_template_base = 'Store')
+}};
+
+//FP loads are offloaded to these formats for now ...
+def format LoadFloatMemory(memacc_code, ea_code = {{ EA = Rs + disp; }},
+ mem_flags = [], inst_flags = []) {{
+ (header_output, decoder_output, decode_block, exec_output) = \
+ LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
+ decode_template = BasicDecode,
+ exec_template_base = 'Load')
+}};
+
+
+def format StoreFloatMemory(memacc_code, ea_code = {{ EA = Rs + disp; }},
+ mem_flags = [], inst_flags = []) {{
+ (header_output, decoder_output, decode_block, exec_output) = \
+ LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
+ exec_template_base = 'Store')
+}};
+
+
+def format UnalignedStore(memacc_code, postacc_code,
+ ea_code = {{ EA = Rb + disp; }},
+ mem_flags = [], inst_flags = []) {{
+ (header_output, decoder_output, decode_block, exec_output) = \
+ LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
+ postacc_code, exec_template_base = 'Store')
+}};
diff --git a/src/arch/mips/isa/formats/noop.isa b/src/arch/mips/isa/formats/noop.isa
new file mode 100644
index 000000000..2aa4816e3
--- /dev/null
+++ b/src/arch/mips/isa/formats/noop.isa
@@ -0,0 +1,94 @@
+// -*- mode:c++ -*-
+
+////////////////////////////////////////////////////////////////////
+//
+// Nop
+//
+
+output header {{
+ /**
+ * Static instruction class for no-ops. This is a leaf class.
+ */
+ class Nop : public MipsStaticInst
+ {
+ /// Disassembly of original instruction.
+ const std::string originalDisassembly;
+
+ public:
+ /// Constructor
+ Nop(const std::string _originalDisassembly, MachInst _machInst)
+ : MipsStaticInst("nop", _machInst, No_OpClass),
+ originalDisassembly(_originalDisassembly)
+ {
+ flags[IsNop] = true;
+ }
+
+ ~Nop() { }
+
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+
+ %(BasicExecDeclare)s
+ };
+}};
+
+output decoder {{
+ std::string Nop::generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+ {
+#ifdef SS_COMPATIBLE_DISASSEMBLY
+ return originalDisassembly;
+#else
+ return csprintf("%-10s (%s)", "nop", originalDisassembly);
+#endif
+ }
+
+ /// Helper function for decoding nops. Substitute Nop object
+ /// for original inst passed in as arg (and delete latter).
+ inline
+ MipsStaticInst *
+ makeNop(MipsStaticInst *inst)
+ {
+ MipsStaticInst *nop = new Nop(inst->disassemble(0), inst->machInst);
+ delete inst;
+ return nop;
+ }
+}};
+
+output exec {{
+ Fault
+ Nop::execute(%(CPU_exec_context)s *, Trace::InstRecord *) const
+ {
+ return NoFault;
+ }
+}};
+
+// integer & FP operate instructions use RT as dest, so check for
+// RT == 0 to detect nops
+def template OperateNopCheckDecode {{
+ {
+ MipsStaticInst *i = new %(class_name)s(machInst);
+
+ //if (RD == 0) {
+ // i = makeNop(i);
+ //}
+
+ return i;
+ }
+}};
+
+
+// Like BasicOperate format, but generates NOP if RC/FC == 31
+def format BasicOperateWithNopCheck(code, *opt_args) {{
+ iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code),
+ opt_args)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = OperateNopCheckDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
+}};
+
+def format Nop() {{
+ decode_block = 'return new Nop(\"sll r0,r0,0\",machInst);\n'
+}};
+
diff --git a/src/arch/mips/isa/formats/tlbop.isa b/src/arch/mips/isa/formats/tlbop.isa
new file mode 100644
index 000000000..f5e4076f2
--- /dev/null
+++ b/src/arch/mips/isa/formats/tlbop.isa
@@ -0,0 +1,53 @@
+////////////////////////////////////////////////////////////////////
+//
+// TlbOp instructions
+//
+
+output header {{
+ /**
+ * Base class for integer operations.
+ */
+ class TlbOp : public MipsStaticInst
+ {
+ protected:
+
+ /// Constructor
+ TlbOp(const char *mnem, MachInst _machInst, OpClass __opClass) : MipsStaticInst(mnem, _machInst, __opClass)
+ {
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+}};
+
+output decoder {{
+ std::string TlbOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+ return "Disassembly of integer instruction\n";
+ }
+}};
+
+def template TlbOpExecute {{
+ Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const
+ {
+ //Call into the trap handler with the appropriate fault
+ return No_Fault;
+ }
+
+ //Write the resulting state to the execution context
+ %(op_wb)s;
+
+ return No_Fault;
+ }
+}};
+
+// Primary format for integer operate instructions:
+def format TlbOp(code, *opt_flags) {{
+ orig_code = code
+ cblk = CodeBlock(code)
+ iop = InstObjParams(name, Name, 'MipsStaticInst', cblk, opt_flags)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecodeWithMnemonic.subst(iop)
+ exec_output = TlbOpExecute.subst(iop)
+}};
diff --git a/src/arch/mips/isa/formats/trap.isa b/src/arch/mips/isa/formats/trap.isa
new file mode 100644
index 000000000..6884d4fa8
--- /dev/null
+++ b/src/arch/mips/isa/formats/trap.isa
@@ -0,0 +1,52 @@
+////////////////////////////////////////////////////////////////////
+//
+// Trap instructions
+//
+
+output header {{
+ /**
+ * Base class for integer operations.
+ */
+ class Trap : public MipsStaticInst
+ {
+ protected:
+
+ /// Constructor
+ Trap(const char *mnem, MachInst _machInst, OpClass __opClass) : MipsStaticInst(mnem, _machInst, __opClass)
+ {
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+}};
+
+output decoder {{
+ std::string Trap::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+ return "Disassembly of integer instruction\n";
+ }
+}};
+
+def template TrapExecute {{
+ Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const
+ {
+ //Call into the trap handler with the appropriate fault
+ return No_Fault;
+ }
+
+ //Write the resulting state to the execution context
+ %(op_wb)s;
+
+ return No_Fault;
+ }
+}};
+
+// Primary format for integer operate instructions:
+def format Trap(code, *flags) {{
+ code = 'bool cond;\n' + code;
+ iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
+}};
diff --git a/src/arch/mips/isa/formats/unimp.isa b/src/arch/mips/isa/formats/unimp.isa
new file mode 100644
index 000000000..475a88752
--- /dev/null
+++ b/src/arch/mips/isa/formats/unimp.isa
@@ -0,0 +1,166 @@
+// -*- mode:c++ -*-
+
+// Copyright (c) 2003-2005 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+output header {{
+ /**
+ * Static instruction class for unimplemented instructions that
+ * cause simulator termination. Note that these are recognized
+ * (legal) instructions that the simulator does not support; the
+ * 'Unknown' class is used for unrecognized/illegal instructions.
+ * This is a leaf class.
+ */
+ class FailUnimplemented : public MipsStaticInst
+ {
+ public:
+ /// Constructor
+ FailUnimplemented(const char *_mnemonic, MachInst _machInst)
+ : MipsStaticInst(_mnemonic, _machInst, No_OpClass)
+ {
+ // don't call execute() (which panics) if we're on a
+ // speculative path
+ flags[IsNonSpeculative] = true;
+ }
+
+ %(BasicExecDeclare)s
+
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+
+ /**
+ * Base class for unimplemented instructions that cause a warning
+ * to be printed (but do not terminate simulation). This
+ * implementation is a little screwy in that it will print a
+ * warning for each instance of a particular unimplemented machine
+ * instruction, not just for each unimplemented opcode. Should
+ * probably make the 'warned' flag a static member of the derived
+ * class.
+ */
+ class WarnUnimplemented : public MipsStaticInst
+ {
+ private:
+ /// Have we warned on this instruction yet?
+ mutable bool warned;
+
+ public:
+ /// Constructor
+ WarnUnimplemented(const char *_mnemonic, MachInst _machInst)
+ : MipsStaticInst(_mnemonic, _machInst, No_OpClass), warned(false)
+ {
+ // don't call execute() (which panics) if we're on a
+ // speculative path
+ flags[IsNonSpeculative] = true;
+ }
+
+ %(BasicExecDeclare)s
+
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+}};
+
+output decoder {{
+ std::string
+ FailUnimplemented::generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+ {
+ return csprintf("%-10s (unimplemented)", mnemonic);
+ }
+
+ std::string
+ WarnUnimplemented::generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+ {
+#ifdef SS_COMPATIBLE_DISASSEMBLY
+ return csprintf("%-10s", mnemonic);
+#else
+ return csprintf("%-10s (unimplemented)", mnemonic);
+#endif
+ }
+}};
+
+output exec {{
+ Fault
+ FailUnimplemented::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ panic("attempt to execute unimplemented instruction '%s' "
+ "(inst 0x%08x, opcode 0x%x, binary:%s)", mnemonic, machInst, OPCODE,
+ inst2string(machInst));
+ return new UnimplementedOpcodeFault;
+ }
+
+ Fault
+ WarnUnimplemented::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ if (!warned) {
+ warn("instruction '%s' unimplemented\n", mnemonic);
+ warned = true;
+ }
+
+ return NoFault;
+ }
+}};
+
+
+def format FailUnimpl() {{
+ iop = InstObjParams(name, 'FailUnimplemented')
+ decode_block = BasicDecodeWithMnemonic.subst(iop)
+}};
+
+def format WarnUnimpl() {{
+ iop = InstObjParams(name, 'WarnUnimplemented')
+ decode_block = BasicDecodeWithMnemonic.subst(iop)
+}};
+
+output header {{
+ /**
+ * Static instruction class for unknown (illegal) instructions.
+ * These cause simulator termination if they are executed in a
+ * non-speculative mode. This is a leaf class.
+ */
+ class Unknown : public MipsStaticInst
+ {
+ public:
+ /// Constructor
+ Unknown(MachInst _machInst)
+ : MipsStaticInst("unknown", _machInst, No_OpClass)
+ {
+ // don't call execute() (which panics) if we're on a
+ // speculative path
+ flags[IsNonSpeculative] = true;
+ }
+
+ %(BasicExecDeclare)s
+
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+}};
+
diff --git a/src/arch/mips/isa/formats/unknown.isa b/src/arch/mips/isa/formats/unknown.isa
new file mode 100644
index 000000000..ba83c007e
--- /dev/null
+++ b/src/arch/mips/isa/formats/unknown.isa
@@ -0,0 +1,74 @@
+// -*- mode:c++ -*-
+
+// Copyright (c) 2003-2005 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+output header {{
+ std::string inst2string(MachInst machInst);
+}};
+output decoder {{
+
+std::string inst2string(MachInst machInst)
+{
+ string str = "";
+ uint32_t mask = 0x80000000;
+
+ for(int i=0; i < 32; i++) {
+ if ((machInst & mask) == 0) {
+ str += "0";
+ } else {
+ str += "1";
+ }
+
+ mask = mask >> 1;
+ }
+
+ return str;
+}
+
+ std::string
+ Unknown::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+ return csprintf("%-10s (inst 0x%x, opcode 0x%x, binary:%s)",
+ "unknown", machInst, OPCODE, inst2string(machInst));
+ }
+}};
+
+output exec {{
+ Fault
+ Unknown::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ panic("attempt to execute unknown instruction "
+ "(inst 0x%08x, opcode 0x%x, binary: %s)", machInst, OPCODE, inst2string(machInst));
+ return new UnimplementedOpcodeFault;
+ }
+}};
+
+def format Unknown() {{
+ decode_block = 'return new Unknown(machInst);\n'
+}};
+
diff --git a/src/arch/mips/isa/formats/util.isa b/src/arch/mips/isa/formats/util.isa
new file mode 100644
index 000000000..615160931
--- /dev/null
+++ b/src/arch/mips/isa/formats/util.isa
@@ -0,0 +1,129 @@
+// -*- mode:c++ -*-
+
+let {{
+def LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
+ postacc_code = '', base_class = 'Memory',
+ decode_template = BasicDecode, exec_template_base = ''):
+ # Make sure flags are in lists (convert to lists if not).
+ mem_flags = makeList(mem_flags)
+ inst_flags = makeList(inst_flags)
+
+ # add hook to get effective addresses into execution trace output.
+ ea_code += '\nif (traceData) { traceData->setAddr(EA); }\n'
+
+ # generate code block objects
+ ea_cblk = CodeBlock(ea_code)
+ memacc_cblk = CodeBlock(memacc_code)
+ postacc_cblk = CodeBlock(postacc_code)
+
+ # Some CPU models execute the memory operation as an atomic unit,
+ # while others want to separate them into an effective address
+ # computation and a memory access operation. As a result, we need
+ # to generate three StaticInst objects. Note that the latter two
+ # are nested inside the larger "atomic" one.
+
+ # generate InstObjParams for EAComp object
+ ea_iop = InstObjParams(name, Name, base_class, ea_cblk, inst_flags)
+
+ # generate InstObjParams for MemAcc object
+ memacc_iop = InstObjParams(name, Name, base_class, memacc_cblk, inst_flags)
+ # in the split execution model, the MemAcc portion is responsible
+ # for the post-access code.
+ memacc_iop.postacc_code = postacc_cblk.code
+
+ # generate InstObjParams for InitiateAcc, CompleteAcc object
+ # The code used depends on the template being used
+ if (exec_template_base == 'Load'):
+ initiateacc_cblk = CodeBlock(ea_code + memacc_code)
+ completeacc_cblk = CodeBlock(memacc_code + postacc_code)
+ elif (exec_template_base == 'Store'):
+ initiateacc_cblk = CodeBlock(ea_code + memacc_code)
+ completeacc_cblk = CodeBlock(postacc_code)
+ else:
+ initiateacc_cblk = ''
+ completeacc_cblk = ''
+
+ initiateacc_iop = InstObjParams(name, Name, base_class, initiateacc_cblk,
+ inst_flags)
+
+ completeacc_iop = InstObjParams(name, Name, base_class, completeacc_cblk,
+ inst_flags)
+
+ if (exec_template_base == 'Load'):
+ initiateacc_iop.ea_code = ea_cblk.code
+ initiateacc_iop.memacc_code = memacc_cblk.code
+ completeacc_iop.memacc_code = memacc_cblk.code
+ completeacc_iop.postacc_code = postacc_cblk.code
+ elif (exec_template_base == 'Store'):
+ initiateacc_iop.ea_code = ea_cblk.code
+ initiateacc_iop.memacc_code = memacc_cblk.code
+ completeacc_iop.postacc_code = postacc_cblk.code
+
+ # generate InstObjParams for unified execution
+ cblk = CodeBlock(ea_code + memacc_code + postacc_code)
+ iop = InstObjParams(name, Name, base_class, cblk, inst_flags)
+
+ iop.ea_constructor = ea_cblk.constructor
+ iop.ea_code = ea_cblk.code
+ iop.memacc_constructor = memacc_cblk.constructor
+ iop.memacc_code = memacc_cblk.code
+ iop.postacc_code = postacc_cblk.code
+
+ if mem_flags:
+ s = '\n\tmemAccessFlags = ' + string.join(mem_flags, '|') + ';'
+ iop.constructor += s
+ memacc_iop.constructor += s
+
+ # select templates
+ memAccExecTemplate = eval(exec_template_base + 'MemAccExecute')
+ fullExecTemplate = eval(exec_template_base + 'Execute')
+ initiateAccTemplate = eval(exec_template_base + 'InitiateAcc')
+ completeAccTemplate = eval(exec_template_base + 'CompleteAcc')
+
+ # (header_output, decoder_output, decode_block, exec_output)
+ return (LoadStoreDeclare.subst(iop), LoadStoreConstructor.subst(iop),
+ decode_template.subst(iop),
+ EACompExecute.subst(ea_iop)
+ + memAccExecTemplate.subst(memacc_iop)
+ + fullExecTemplate.subst(iop)
+ + initiateAccTemplate.subst(initiateacc_iop)
+ + completeAccTemplate.subst(completeacc_iop))
+}};
+
+
+output exec {{
+
+ using namespace MipsISA;
+
+ /// CLEAR ALL CPU INST/EXE HAZARDS
+ inline void
+ clear_exe_inst_hazards()
+ {
+ //CODE HERE
+ }
+
+
+ /// Check "FP enabled" machine status bit. Called when executing any FP
+ /// instruction in full-system mode.
+ /// @retval Full-system mode: NoFault if FP is enabled, FenFault
+ /// if not. Non-full-system mode: always returns NoFault.
+#if FULL_SYSTEM
+ inline Fault checkFpEnableFault(%(CPU_exec_context)s *xc)
+ {
+ Fault fault = NoFault; // dummy... this ipr access should not fault
+ if (!Mips34k::ICSR_FPE(xc->readIpr(MipsISA::IPR_ICSR, fault))) {
+ fault = FloatEnableFault;
+ }
+ return fault;
+ }
+#else
+ inline Fault checkFpEnableFault(%(CPU_exec_context)s *xc)
+ {
+ return NoFault;
+ }
+#endif
+
+
+}};
+
+
diff --git a/src/arch/mips/isa/includes.isa b/src/arch/mips/isa/includes.isa
new file mode 100644
index 000000000..9c370fbe3
--- /dev/null
+++ b/src/arch/mips/isa/includes.isa
@@ -0,0 +1,48 @@
+////////////////////////////////////////////////////////////////////
+//
+// Output include file directives.
+//
+
+output header {{
+#include <sstream>
+#include <iostream>
+#include <iomanip>
+
+#include "cpu/static_inst.hh"
+#include "arch/mips/isa_traits.hh"
+}};
+
+output decoder {{
+#include "arch/mips/isa_traits.hh"
+#include "base/cprintf.hh"
+#include "base/loader/symtab.hh"
+#include "cpu/exec_context.hh" // for Jump::branchTarget()
+#include "arch/mips/faults.hh"
+#include "arch/mips/isa_traits.hh"
+
+#include <math.h>
+#if defined(linux)
+#include <fenv.h>
+#endif
+
+using namespace MipsISA;
+}};
+
+output exec {{
+#include "arch/mips/faults.hh"
+#include "arch/mips/isa_traits.hh"
+#include <math.h>
+#if defined(linux)
+#include <fenv.h>
+#endif
+
+#ifdef FULL_SYSTEM
+//#include "arch/alpha/pseudo_inst.hh"
+#endif
+#include "cpu/base.hh"
+#include "cpu/exetrace.hh"
+#include "sim/sim_exit.hh"
+
+using namespace MipsISA;
+}};
+
diff --git a/src/arch/mips/isa/main.isa b/src/arch/mips/isa/main.isa
new file mode 100644
index 000000000..01d81323e
--- /dev/null
+++ b/src/arch/mips/isa/main.isa
@@ -0,0 +1,52 @@
+// -*- mode:c++ -*-
+
+// Copyright (c) 2003-2005 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+##include "includes.isa"
+
+////////////////////////////////////////////////////////////////////
+//
+// Namespace statement. Everything below this line will be in the
+// MipsISAInst namespace.
+//
+
+namespace MipsISA;
+
+//Include the bitfield definitions
+##include "bitfields.isa"
+
+//Include the operand_types and operand definitions
+##include "operands.isa"
+
+//Include the base class for mips instructions, and some support code
+##include "base.isa"
+
+//Include the definitions for the instruction formats
+##include "formats/formats.isa"
+
+//Include the decoder definition
+##include "decoder.isa"
diff --git a/src/arch/mips/isa/operands.isa b/src/arch/mips/isa/operands.isa
new file mode 100644
index 000000000..0f9c74b48
--- /dev/null
+++ b/src/arch/mips/isa/operands.isa
@@ -0,0 +1,61 @@
+def operand_types {{
+ 'sb' : ('signed int', 8),
+ 'ub' : ('unsigned int', 8),
+ 'sh' : ('signed int', 16),
+ 'uh' : ('unsigned int', 16),
+ 'sw' : ('signed int', 32),
+ 'uw' : ('unsigned int', 32),
+ 'sd' : ('signed int', 64),
+ 'ud' : ('unsigned int', 64),
+ 'sf' : ('float', 32),
+ 'df' : ('float', 64),
+ 'qf' : ('float', 128)
+}};
+
+def operands {{
+ #General Purpose Integer Reg Operands
+ 'Rd': ('IntReg', 'uw', 'RD', 'IsInteger', 1),
+ 'Rs': ('IntReg', 'uw', 'RS', 'IsInteger', 2),
+ 'Rt': ('IntReg', 'uw', 'RT', 'IsInteger', 3),
+
+ #Operands used for Link or Syscall Insts
+ 'R31': ('IntReg', 'uw','31','IsInteger', 4),
+ 'R2': ('IntReg', 'uw','2', 'IsInteger', 5),
+
+ #Special Integer Reg operands
+ 'HI': ('IntReg', 'uw','32', 'IsInteger', 6),
+ 'LO': ('IntReg', 'uw','33', 'IsInteger', 7),
+
+ #Immediate Value operand
+ 'IntImm': ('IntReg', 'uw', 'INTIMM', 'IsInteger', 3),
+
+ #Floating Point Reg Operands
+ 'Fd': ('FloatReg', 'sf', 'FD', 'IsFloating', 1),
+ 'Fs': ('FloatReg', 'sf', 'FS', 'IsFloating', 2),
+ 'Ft': ('FloatReg', 'sf', 'FT', 'IsFloating', 3),
+ 'Fr': ('FloatReg', 'sf', 'FR', 'IsFloating', 3),
+
+ #Special Floating Point Control Reg Operands
+ 'FIR': ('FloatReg', 'uw', '32', 'IsFloating', 1),
+ 'FCCR': ('FloatReg', 'uw', '33', 'IsFloating', 2),
+ 'FEXR': ('FloatReg', 'uw', '34', 'IsFloating', 3),
+ 'FENR': ('FloatReg', 'uw', '35', 'IsFloating', 3),
+ 'FCSR': ('FloatReg', 'uw', '36', 'IsFloating', 3),
+
+ #Operands For Paired Singles FP Operations
+ 'Fd1': ('FloatReg', 'sf', 'FD', 'IsFloating', 4),
+ 'Fd2': ('FloatReg', 'sf', 'FD+1', 'IsFloating', 4),
+ 'Fs1': ('FloatReg', 'sf', 'FS', 'IsFloating', 5),
+ 'Fs2': ('FloatReg', 'sf', 'FS+1', 'IsFloating', 5),
+ 'Ft1': ('FloatReg', 'sf', 'FT', 'IsFloating', 6),
+ 'Ft2': ('FloatReg', 'sf', 'FT+1', 'IsFloating', 6),
+ 'Fr1': ('FloatReg', 'sf', 'FR', 'IsFloating', 7),
+ 'Fr2': ('FloatReg', 'sf', 'FR+1', 'IsFloating', 7),
+
+ #Memory Operand
+ 'Mem': ('Mem', 'uw', None, ('IsMemRef', 'IsLoad', 'IsStore'), 4),
+
+ #Program Counter Operands
+ 'NPC': ('NPC', 'uw', None, ( None, None, 'IsControl' ), 4),
+ 'NNPC':('NNPC', 'uw', None, ( None, None, 'IsControl' ), 4)
+}};
diff --git a/src/arch/mips/isa_traits.cc b/src/arch/mips/isa_traits.cc
new file mode 100644
index 000000000..216a6e2ec
--- /dev/null
+++ b/src/arch/mips/isa_traits.cc
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "arch/mips/isa_traits.hh"
+#include "config/full_system.hh"
+#include "cpu/static_inst.hh"
+#include "sim/serialize.hh"
+#include "base/bitfield.hh"
+
+using namespace MipsISA;
+using namespace std;
+
+
+void
+MipsISA::copyRegs(ExecContext *src, ExecContext *dest)
+{
+ /*fpcr = xc->readMiscReg(MipsISA::Fpcr_DepTag);
+ uniq = xc->readMiscReg(MipsISA::Uniq_DepTag);
+ lock_flag = xc->readMiscReg(MipsISA::Lock_Flag_DepTag);
+ lock_addr = xc->readMiscReg(MipsISA::Lock_Addr_DepTag);
+
+#if FULL_SYSTEM
+ copyIprs(xc);
+ #endif*/
+}
+
+void
+MipsISA::MiscRegFile::copyMiscRegs(ExecContext *xc)
+{
+ /*fpcr = xc->readMiscReg(MipsISA::Fpcr_DepTag);
+ uniq = xc->readMiscReg(MipsISA::Uniq_DepTag);
+ lock_flag = xc->readMiscReg(MipsISA::Lock_Flag_DepTag);
+ lock_addr = xc->readMiscReg(MipsISA::Lock_Addr_DepTag);
+
+ #endif*/
+}
+
+uint64_t
+MipsISA::fpConvert(double fp_val, ConvertType cvt_type)
+{
+
+ switch (cvt_type)
+ {
+ case SINGLE_TO_DOUBLE:
+ double sdouble_val = fp_val;
+ void *sdouble_ptr = &sdouble_val;
+ uint64_t sdp_bits = *(uint64_t *) sdouble_ptr;
+ return sdp_bits;
+
+ case SINGLE_TO_WORD:
+ int32_t sword_val = (int32_t) fp_val;
+ void *sword_ptr = &sword_val;
+ uint64_t sword_bits= *(uint32_t *) sword_ptr;
+ return sword_bits;
+
+ case WORD_TO_SINGLE:
+ float wfloat_val = fp_val;
+ void *wfloat_ptr = &wfloat_val;
+ uint64_t wfloat_bits = *(uint32_t *) wfloat_ptr;
+ return wfloat_bits;
+
+ case WORD_TO_DOUBLE:
+ double wdouble_val = fp_val;
+ void *wdouble_ptr = &wdouble_val;
+ uint64_t wdp_bits = *(uint64_t *) wdouble_ptr;
+ return wdp_bits;
+
+ default:
+ panic("Invalid Floating Point Conversion Type (%d). See \"types.hh\" for List of Conversions\n",cvt_type);
+ return 0;
+ }
+}
+
+double
+MipsISA::roundFP(double val, int digits)
+{
+ double digit_offset = pow(10.0,digits);
+ val = val * digit_offset;
+ val = val + 0.5;
+ val = floor(val);
+ val = val / digit_offset;
+ return val;
+}
+
+double
+MipsISA::truncFP(double val)
+{
+ int trunc_val = (int) val;
+ return (double) trunc_val;
+}
+
+bool
+MipsISA::getFPConditionCode(uint32_t fcsr_reg, int cc)
+{
+ //uint32_t cc_bits = xc->readFloatReg(35);
+ return false;//regFile.floatRegfile.getConditionCode(cc);
+}
+
+uint32_t
+MipsISA::makeCCVector(uint32_t fcsr, int num, bool val)
+{
+ int shift = (num == 0) ? 22 : num + 23;
+
+ fcsr = fcsr | (val << shift);
+
+ return fcsr;
+}
+
+#if FULL_SYSTEM
+
+static inline Addr
+TruncPage(Addr addr)
+{ return addr & ~(MipsISA::PageBytes - 1); }
+
+static inline Addr
+RoundPage(Addr addr)
+{ return (addr + MipsISA::PageBytes - 1) & ~(MipsISA::PageBytes - 1); }
+#endif
+
+void
+IntRegFile::serialize(std::ostream &os)
+{
+ SERIALIZE_ARRAY(regs, NumIntRegs);
+}
+
+void
+IntRegFile::unserialize(Checkpoint *cp, const std::string &section)
+{
+ UNSERIALIZE_ARRAY(regs, NumIntRegs);
+}
+
+void
+RegFile::serialize(std::ostream &os)
+{
+ intRegFile.serialize(os);
+ //SERIALIZE_ARRAY(floatRegFile.q, NumFloatRegs);
+ //SERIALIZE_SCALAR(miscRegs.fpcr);
+ //SERIALIZE_SCALAR(miscRegs.uniq);
+ //SERIALIZE_SCALAR(miscRegs.lock_flag);
+ //SERIALIZE_SCALAR(miscRegs.lock_addr);
+ SERIALIZE_SCALAR(pc);
+ SERIALIZE_SCALAR(npc);
+ SERIALIZE_SCALAR(nnpc);
+#if FULL_SYSTEM
+ SERIALIZE_ARRAY(palregs, NumIntRegs);
+ SERIALIZE_ARRAY(ipr, NumInternalProcRegs);
+ SERIALIZE_SCALAR(intrflag);
+ SERIALIZE_SCALAR(pal_shadow);
+#endif
+}
+
+
+void
+RegFile::unserialize(Checkpoint *cp, const std::string &section)
+{
+ intRegFile.unserialize(cp, section);
+ //UNSERIALIZE_ARRAY(floatRegFile.q, NumFloatRegs);
+ //UNSERIALIZE_SCALAR(miscRegs.fpcr);
+ //UNSERIALIZE_SCALAR(miscRegs.uniq);
+ //UNSERIALIZE_SCALAR(miscRegs.lock_flag);
+ //UNSERIALIZE_SCALAR(miscRegs.lock_addr);
+ UNSERIALIZE_SCALAR(pc);
+ UNSERIALIZE_SCALAR(npc);
+ UNSERIALIZE_SCALAR(nnpc);
+#if FULL_SYSTEM
+ UNSERIALIZE_ARRAY(palregs, NumIntRegs);
+ UNSERIALIZE_ARRAY(ipr, NumInternalProcRegs);
+ UNSERIALIZE_SCALAR(intrflag);
+ UNSERIALIZE_SCALAR(pal_shadow);
+#endif
+}
+
+
+#if FULL_SYSTEM
+void
+PTE::serialize(std::ostream &os)
+{
+ SERIALIZE_SCALAR(tag);
+ SERIALIZE_SCALAR(ppn);
+ SERIALIZE_SCALAR(xre);
+ SERIALIZE_SCALAR(xwe);
+ SERIALIZE_SCALAR(asn);
+ SERIALIZE_SCALAR(asma);
+ SERIALIZE_SCALAR(fonr);
+ SERIALIZE_SCALAR(fonw);
+ SERIALIZE_SCALAR(valid);
+}
+
+
+void
+PTE::unserialize(Checkpoint *cp, const std::string &section)
+{
+ UNSERIALIZE_SCALAR(tag);
+ UNSERIALIZE_SCALAR(ppn);
+ UNSERIALIZE_SCALAR(xre);
+ UNSERIALIZE_SCALAR(xwe);
+ UNSERIALIZE_SCALAR(asn);
+ UNSERIALIZE_SCALAR(asma);
+ UNSERIALIZE_SCALAR(fonr);
+ UNSERIALIZE_SCALAR(fonw);
+ UNSERIALIZE_SCALAR(valid);
+}
+
+#endif //FULL_SYSTEM
diff --git a/src/arch/mips/isa_traits.hh b/src/arch/mips/isa_traits.hh
new file mode 100644
index 000000000..148c405df
--- /dev/null
+++ b/src/arch/mips/isa_traits.hh
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ARCH_MIPS_ISA_TRAITS_HH__
+#define __ARCH_MIPS_ISA_TRAITS_HH__
+
+#include "arch/mips/constants.hh"
+#include "arch/mips/types.hh"
+#include "arch/mips/regfile/regfile.hh"
+#include "arch/mips/faults.hh"
+#include "arch/mips/utility.hh"
+#include "base/misc.hh"
+#include "config/full_system.hh"
+#include "sim/byteswap.hh"
+#include "sim/host.hh"
+#include "sim/faults.hh"
+
+#include <vector>
+
+class FastCPU;
+class FullCPU;
+class Checkpoint;
+class ExecContext;
+
+namespace LittleEndianGuest {};
+
+#define TARGET_MIPS
+
+class StaticInst;
+class StaticInstPtr;
+
+namespace MIPS34K {
+int DTB_ASN_ASN(uint64_t reg);
+int ITB_ASN_ASN(uint64_t reg);
+};
+
+#if !FULL_SYSTEM
+class SyscallReturn {
+ public:
+ template <class T>
+ SyscallReturn(T v, bool s)
+ {
+ retval = (uint32_t)v;
+ success = s;
+ }
+
+ template <class T>
+ SyscallReturn(T v)
+ {
+ success = (v >= 0);
+ retval = (uint32_t)v;
+ }
+
+ ~SyscallReturn() {}
+
+ SyscallReturn& operator=(const SyscallReturn& s) {
+ retval = s.retval;
+ success = s.success;
+ return *this;
+ }
+
+ bool successful() { return success; }
+ uint64_t value() { return retval; }
+
+
+ private:
+ uint64_t retval;
+ bool success;
+};
+#endif
+
+namespace MipsISA
+{
+ using namespace LittleEndianGuest;
+
+ static inline void setSyscallReturn(SyscallReturn return_value, RegFile *regs)
+ {
+ if (return_value.successful()) {
+ // no error
+ regs->setIntReg(SyscallSuccessReg, 0);
+ regs->setIntReg(ReturnValueReg1, return_value.value());
+ } else {
+ // got an error, return details
+ regs->setIntReg(SyscallSuccessReg, (IntReg) -1);
+ regs->setIntReg(ReturnValueReg1, -return_value.value());
+ }
+ }
+
+ StaticInstPtr decodeInst(ExtMachInst);
+
+ static inline ExtMachInst
+ makeExtMI(MachInst inst, const uint64_t &pc) {
+#if FULL_SYSTEM
+ ExtMachInst ext_inst = inst;
+ if (pc && 0x1)
+ return ext_inst|=(static_cast<ExtMachInst>(pc & 0x1) << 32);
+ else
+ return ext_inst;
+#else
+ return ExtMachInst(inst);
+#endif
+ }
+
+ /**
+ * Function to insure ISA semantics about 0 registers.
+ * @param xc The execution context.
+ */
+ template <class XC>
+ void zeroRegisters(XC *xc);
+
+ const Addr MaxAddr = (Addr)-1;
+
+ void copyRegs(ExecContext *src, ExecContext *dest);
+
+ uint64_t fpConvert(double fp_val, ConvertType cvt_type);
+ double roundFP(double val, int digits);
+ double truncFP(double val);
+ bool getFPConditionCode(uint32_t fcsr_reg, int cc);
+ uint32_t makeCCVector(uint32_t fcsr, int num, bool val);
+
+ // Machine operations
+
+ void saveMachineReg(AnyReg &savereg, const RegFile &reg_file,
+ int regnum);
+
+ void restoreMachineReg(RegFile &regs, const AnyReg &reg,
+ int regnum);
+
+#if 0
+ static void serializeSpecialRegs(const Serializable::Proxy &proxy,
+ const RegFile &regs);
+
+ static void unserializeSpecialRegs(const IniFile *db,
+ const std::string &category,
+ ConfigNode *node,
+ RegFile &regs);
+#endif
+
+ static inline Addr alignAddress(const Addr &addr,
+ unsigned int nbytes) {
+ return (addr & ~(nbytes - 1));
+ }
+
+ // Instruction address compression hooks
+ static inline Addr realPCToFetchPC(const Addr &addr) {
+ return addr;
+ }
+
+ static inline Addr fetchPCToRealPC(const Addr &addr) {
+ return addr;
+ }
+
+ // the size of "fetched" instructions (not necessarily the size
+ // of real instructions for PISA)
+ static inline size_t fetchInstSize() {
+ return sizeof(MachInst);
+ }
+
+ static inline MachInst makeRegisterCopy(int dest, int src) {
+ panic("makeRegisterCopy not implemented");
+ return 0;
+ }
+
+};
+
+#if FULL_SYSTEM
+
+#include "arch/mips/mips34k.hh"
+
+#endif
+
+using namespace MipsISA;
+
+#endif // __ARCH_MIPS_ISA_TRAITS_HH__
diff --git a/src/arch/mips/linux/linux.cc b/src/arch/mips/linux/linux.cc
new file mode 100644
index 000000000..26e3dd479
--- /dev/null
+++ b/src/arch/mips/linux/linux.cc
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Korey Sewell
+ */
+
+#include "arch/mips/linux/linux.hh"
+
+// open(2) flags translation table
+OpenFlagTransTable MipsLinux::openFlagTable[] = {
+#ifdef _MSC_VER
+ { MipsLinux::TGT_O_RDONLY, _O_RDONLY },
+ { MipsLinux::TGT_O_WRONLY, _O_WRONLY },
+ { MipsLinux::TGT_O_RDWR, _O_RDWR },
+ { MipsLinux::TGT_O_APPEND, _O_APPEND },
+ { MipsLinux::TGT_O_CREAT, _O_CREAT },
+ { MipsLinux::TGT_O_TRUNC, _O_TRUNC },
+ { MipsLinux::TGT_O_EXCL, _O_EXCL },
+#ifdef _O_NONBLOCK
+ { MipsLinux::TGT_O_NONBLOCK, _O_NONBLOCK },
+#endif
+#ifdef _O_NOCTTY
+ { MipsLinux::TGT_O_NOCTTY, _O_NOCTTY },
+#endif
+#ifdef _O_SYNC
+ { MipsLinux::TGT_O_SYNC, _O_SYNC },
+#endif
+#else /* !_MSC_VER */
+ { MipsLinux::TGT_O_RDONLY, O_RDONLY },
+ { MipsLinux::TGT_O_WRONLY, O_WRONLY },
+ { MipsLinux::TGT_O_RDWR, O_RDWR },
+ { MipsLinux::TGT_O_APPEND, O_APPEND },
+ { MipsLinux::TGT_O_CREAT, O_CREAT },
+ { MipsLinux::TGT_O_TRUNC, O_TRUNC },
+ { MipsLinux::TGT_O_EXCL, O_EXCL },
+ { MipsLinux::TGT_O_NONBLOCK, O_NONBLOCK },
+ { MipsLinux::TGT_O_NOCTTY, O_NOCTTY },
+#ifdef O_SYNC
+ { MipsLinux::TGT_O_SYNC, O_SYNC },
+#endif
+#endif /* _MSC_VER */
+};
+
+const int MipsLinux::NUM_OPEN_FLAGS =
+ (sizeof(MipsLinux::openFlagTable)/sizeof(MipsLinux::openFlagTable[0]));
+
+
+
diff --git a/src/arch/mips/linux/linux.hh b/src/arch/mips/linux/linux.hh
new file mode 100644
index 000000000..f85935bb9
--- /dev/null
+++ b/src/arch/mips/linux/linux.hh
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Korey Sewell
+ */
+
+#ifndef __ARCH_MIPS_LINUX_LINUX_HH__
+#define __ARCH_MIPS_LINUX_LINUX_HH__
+
+#include "kern/linux/linux.hh"
+
+class MipsLinux : public Linux
+{
+ public:
+
+ /// This table maps the target open() flags to the corresponding
+ /// host open() flags.
+ static OpenFlagTransTable openFlagTable[];
+
+ /// Number of entries in openFlagTable[].
+ static const int NUM_OPEN_FLAGS;
+
+ //@{
+ /// open(2) flag values.
+ static const int TGT_O_RDONLY = 0x00000000; //!< O_RDONLY
+ static const int TGT_O_WRONLY = 0x00000001; //!< O_WRONLY
+ static const int TGT_O_RDWR = 0x00000002; //!< O_RDWR
+ static const int TGT_O_NONBLOCK = 0x00000080; //!< O_NONBLOCK
+ static const int TGT_O_APPEND = 0x00000008; //!< O_APPEND
+ static const int TGT_O_CREAT = 0x00000100; //!< O_CREAT
+ static const int TGT_O_TRUNC = 0x00000200; //!< O_TRUNC
+ static const int TGT_O_EXCL = 0x00000400; //!< O_EXCL
+ static const int TGT_O_NOCTTY = 0x00000800; //!< O_NOCTTY
+ static const int TGT_O_SYNC = 0x00000010; //!< O_SYNC
+ static const int TGT_O_DRD = 0x00010000; //!< O_DRD
+ static const int TGT_O_DIRECTIO = 0x00020000; //!< O_DIRECTIO
+ static const int TGT_O_CACHE = 0x00002000; //!< O_CACHE
+ static const int TGT_O_DSYNC = 0x00008000; //!< O_DSYNC
+ static const int TGT_O_RSYNC = 0x00040000; //!< O_RSYNC
+ //@}
+
+ /// For mmap().
+ static const unsigned TGT_MAP_ANONYMOUS = 0x800;
+
+ //@{
+ /// For getsysinfo().
+ static const unsigned GSI_PLATFORM_NAME = 103; //!< platform name as string
+ static const unsigned GSI_CPU_INFO = 59; //!< CPU information
+ static const unsigned GSI_PROC_TYPE = 60; //!< get proc_type
+ static const unsigned GSI_MAX_CPU = 30; //!< max # cpu's on this machine
+ static const unsigned GSI_CPUS_IN_BOX = 55; //!< number of CPUs in system
+ static const unsigned GSI_PHYSMEM = 19; //!< Physical memory in KB
+ static const unsigned GSI_CLK_TCK = 42; //!< clock freq in Hz
+ //@}
+
+ //@{
+ /// For getrusage().
+ static const int TGT_RUSAGE_SELF = 0;
+ static const int TGT_RUSAGE_CHILDREN = -1;
+ static const int TGT_RUSAGE_BOTH = -2;
+ //@}
+
+ //@{
+ /// For setsysinfo().
+ static const unsigned SSI_IEEE_FP_CONTROL = 14; //!< ieee_set_fp_control()
+ //@}
+
+ //@{
+ /// ioctl() command codes.
+ static const unsigned TIOCGETP = 0x7408;
+ static const unsigned TIOCSETP = 0x7409;
+ static const unsigned TIOCSETN = 0x740a;
+ static const unsigned TIOCSETC = 0x7411;
+ static const unsigned TIOCGETC = 0x7412;
+ static const unsigned FIONREAD = 0x467f;
+ static const unsigned TIOCISATTY = 0x5480;
+ static const unsigned TIOCGETS = 0x7413;
+ static const unsigned TIOCGETA = 0x7417;
+ //@}
+
+ /// For table().
+ static const int TBL_SYSINFO = 12;
+
+ /// Resource enumeration for getrlimit().
+ enum rlimit_resources {
+ TGT_RLIMIT_CPU = 0,
+ TGT_RLIMIT_FSIZE = 1,
+ TGT_RLIMIT_DATA = 2,
+ TGT_RLIMIT_STACK = 3,
+ TGT_RLIMIT_CORE = 4,
+ TGT_RLIMIT_NOFILE = 5,
+ TGT_RLIMIT_AS = 6,
+ TGT_RLIMIT_RSS = 7,
+ TGT_RLIMIT_VMEM = 7,
+ TGT_RLIMIT_NPROC = 8,
+ TGT_RLIMIT_MEMLOCK = 9,
+ TGT_RLIMIT_LOCKS = 10
+ };
+
+};
+
+#endif
diff --git a/src/arch/mips/linux/process.cc b/src/arch/mips/linux/process.cc
new file mode 100644
index 000000000..ffc5da2e1
--- /dev/null
+++ b/src/arch/mips/linux/process.cc
@@ -0,0 +1,429 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "arch/mips/linux/linux.hh"
+#include "arch/mips/linux/process.hh"
+#include "arch/mips/isa_traits.hh"
+
+#include "base/trace.hh"
+#include "cpu/exec_context.hh"
+#include "kern/linux/linux.hh"
+
+#include "sim/process.hh"
+#include "sim/syscall_emul.hh"
+
+using namespace std;
+using namespace MipsISA;
+
+/// Target uname() handler.
+static SyscallReturn
+unameFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ TypedBufferArg<Linux::utsname> name(xc->getSyscallArg(0));
+
+ strcpy(name->sysname, "Linux");
+ strcpy(name->nodename, "m5.eecs.umich.edu");
+ strcpy(name->release, "2.4.20");
+ strcpy(name->version, "#1 Mon Aug 18 11:32:15 EDT 2003");
+ strcpy(name->machine, "mips");
+
+ name.copyOut(xc->getMemPort());
+ return 0;
+}
+
+/// Target sys_getsysyinfo() handler. Even though this call is
+/// borrowed from Tru64, the subcases that get used appear to be
+/// different in practice from those used by Tru64 processes.
+static SyscallReturn
+sys_getsysinfoFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ unsigned op = xc->getSyscallArg(0);
+ // unsigned nbytes = xc->getSyscallArg(2);
+
+ switch (op) {
+
+ case 45: { // GSI_IEEE_FP_CONTROL
+ TypedBufferArg<uint64_t> fpcr(xc->getSyscallArg(1));
+ // I don't think this exactly matches the HW FPCR
+ *fpcr = 0;
+ fpcr.copyOut(xc->getMemPort());
+ return 0;
+ }
+
+ default:
+ cerr << "sys_getsysinfo: unknown op " << op << endl;
+ abort();
+ break;
+ }
+
+ return 1;
+}
+
+/// Target sys_setsysinfo() handler.
+static SyscallReturn
+sys_setsysinfoFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ unsigned op = xc->getSyscallArg(0);
+ // unsigned nbytes = xc->getSyscallArg(2);
+
+ switch (op) {
+
+ case 14: { // SSI_IEEE_FP_CONTROL
+ TypedBufferArg<uint64_t> fpcr(xc->getSyscallArg(1));
+ // I don't think this exactly matches the HW FPCR
+ fpcr.copyIn(xc->getMemPort());
+ DPRINTFR(SyscallVerbose, "sys_setsysinfo(SSI_IEEE_FP_CONTROL): "
+ " setting FPCR to 0x%x\n", gtoh(*(uint64_t*)fpcr));
+ return 0;
+ }
+
+ default:
+ cerr << "sys_setsysinfo: unknown op " << op << endl;
+ abort();
+ break;
+ }
+
+ return 1;
+}
+
+
+SyscallDesc MipsLinuxProcess::syscallDescs[] = {
+ /* 0 */ SyscallDesc("syscall", unimplementedFunc),
+ /* 1 */ SyscallDesc("exit", exitFunc),
+ /* 2 */ SyscallDesc("fork", unimplementedFunc),
+ /* 3 */ SyscallDesc("read", readFunc),
+ /* 4 */ SyscallDesc("write", writeFunc),
+ /* 5 */ SyscallDesc("open", openFunc<MipsLinux>),
+ /* 6 */ SyscallDesc("close", closeFunc),
+ /* 7 */ SyscallDesc("waitpid", unimplementedFunc),
+ /* 8 */ SyscallDesc("creat", unimplementedFunc),
+ /* 9 */ SyscallDesc("link", unimplementedFunc),
+ /* 10 */ SyscallDesc("unlink", unlinkFunc),
+ /* 11 */ SyscallDesc("execve", unimplementedFunc),
+ /* 12 */ SyscallDesc("chdir", unimplementedFunc),
+ /* 13 */ SyscallDesc("time", unimplementedFunc),
+ /* 14 */ SyscallDesc("mknod", unimplementedFunc),
+ /* 15 */ SyscallDesc("chmod", chmodFunc<MipsLinux>),
+ /* 16 */ SyscallDesc("lchown", chownFunc),
+ /* 17 */ SyscallDesc("break", obreakFunc), /*obreak*/
+ /* 18 */ SyscallDesc("unused#18", unimplementedFunc),
+ /* 19 */ SyscallDesc("lseek", lseekFunc),
+ /* 20 */ SyscallDesc("getpid", getpidFunc),
+ /* 21 */ SyscallDesc("mount", unimplementedFunc),
+ /* 22 */ SyscallDesc("umount", unimplementedFunc),
+ /* 23 */ SyscallDesc("setuid", setuidFunc),
+ /* 24 */ SyscallDesc("getuid", getuidFunc),
+ /* 25 */ SyscallDesc("stime", unimplementedFunc),
+ /* 26 */ SyscallDesc("ptrace", unimplementedFunc),
+ /* 27 */ SyscallDesc("alarm", unimplementedFunc),
+ /* 28 */ SyscallDesc("unused#28", unimplementedFunc),
+ /* 29 */ SyscallDesc("pause", unimplementedFunc),
+ /* 30 */ SyscallDesc("utime", unimplementedFunc),
+ /* 31 */ SyscallDesc("stty", unimplementedFunc),
+ /* 32 */ SyscallDesc("gtty", unimplementedFunc),
+ /* 33 */ SyscallDesc("access", unimplementedFunc),
+ /* 34 */ SyscallDesc("nice", unimplementedFunc),
+ /* 35 */ SyscallDesc("ftime", unimplementedFunc),
+ /* 36 */ SyscallDesc("sync", unimplementedFunc),
+ /* 37 */ SyscallDesc("kill", ignoreFunc),
+ /* 38 */ SyscallDesc("rename", unimplementedFunc),
+ /* 39 */ SyscallDesc("mkdir", unimplementedFunc),
+ /* 40 */ SyscallDesc("rmdir", unimplementedFunc),
+ /* 41 */ SyscallDesc("dup", unimplementedFunc),
+ /* 42 */ SyscallDesc("pipe", unimplementedFunc),
+ /* 43 */ SyscallDesc("times", unimplementedFunc),
+ /* 44 */ SyscallDesc("prof", unimplementedFunc),
+ /* 45 */ SyscallDesc("brk", obreakFunc),/*openFunc<MipsLinux>*/
+ /* 46 */ SyscallDesc("setgid", unimplementedFunc),
+ /* 47 */ SyscallDesc("getgid", getgidFunc),
+ /* 48 */ SyscallDesc("signal", ignoreFunc),
+ /* 49 */ SyscallDesc("geteuid", geteuidFunc),
+ /* 50 */ SyscallDesc("getegid", getegidFunc),
+ /* 51 */ SyscallDesc("acct", unimplementedFunc),
+ /* 52 */ SyscallDesc("umount2", unimplementedFunc),
+ /* 53 */ SyscallDesc("lock", unimplementedFunc),
+ /* 54 */ SyscallDesc("ioctl", ioctlFunc<MipsLinux>),
+ /* 55 */ SyscallDesc("fcntl", unimplementedFunc),
+ /* 56 */ SyscallDesc("mpx", unimplementedFunc),
+ /* 57 */ SyscallDesc("setpgid", unimplementedFunc),
+ /* 58 */ SyscallDesc("ulimit", unimplementedFunc),
+ /* 59 */ SyscallDesc("unused#59", unimplementedFunc),
+ /* 60 */ SyscallDesc("umask", unimplementedFunc),
+ /* 61 */ SyscallDesc("chroot", unimplementedFunc),
+ /* 62 */ SyscallDesc("ustat", unimplementedFunc),
+ /* 63 */ SyscallDesc("dup2", unimplementedFunc),
+ /* 64 */ SyscallDesc("getppid", getpagesizeFunc),
+ /* 65 */ SyscallDesc("getpgrp", unimplementedFunc),
+ /* 66 */ SyscallDesc("setsid", unimplementedFunc),
+ /* 67 */ SyscallDesc("sigaction",unimplementedFunc),
+ /* 68 */ SyscallDesc("sgetmask", unimplementedFunc),
+ /* 69 */ SyscallDesc("ssetmask", unimplementedFunc),
+ /* 70 */ SyscallDesc("setreuid", unimplementedFunc),
+ /* 71 */ SyscallDesc("setregid", unimplementedFunc),
+ /* 72 */ SyscallDesc("sigsuspend", unimplementedFunc),
+ /* 73 */ SyscallDesc("sigpending", unimplementedFunc),
+ /* 74 */ SyscallDesc("sethostname", ignoreFunc),
+ /* 75 */ SyscallDesc("setrlimit", unimplementedFunc),
+ /* 76 */ SyscallDesc("getrlimit", unimplementedFunc),
+ /* 77 */ SyscallDesc("getrusage", unimplementedFunc),
+ /* 78 */ SyscallDesc("gettimeofday", unimplementedFunc),
+ /* 79 */ SyscallDesc("settimeofday", unimplementedFunc),
+ /* 80 */ SyscallDesc("getgroups", unimplementedFunc),
+ /* 81 */ SyscallDesc("setgroups", unimplementedFunc),
+ /* 82 */ SyscallDesc("reserved#82", unimplementedFunc),
+ /* 83 */ SyscallDesc("symlink", unimplementedFunc),
+ /* 84 */ SyscallDesc("unused#84", unimplementedFunc),
+ /* 85 */ SyscallDesc("readlink", unimplementedFunc),
+ /* 86 */ SyscallDesc("uselib", unimplementedFunc),
+ /* 87 */ SyscallDesc("swapon", gethostnameFunc),
+ /* 88 */ SyscallDesc("reboot", unimplementedFunc),
+ /* 89 */ SyscallDesc("readdir", unimplementedFunc),
+ /* 90 */ SyscallDesc("mmap", mmapFunc<MipsLinux>),
+ /* 91 */ SyscallDesc("munmap",munmapFunc),
+ /* 92 */ SyscallDesc("truncate", fcntlFunc),
+ /* 93 */ SyscallDesc("ftruncate", unimplementedFunc),
+ /* 94 */ SyscallDesc("fchmod", unimplementedFunc),
+ /* 95 */ SyscallDesc("fchown", unimplementedFunc),
+ /* 96 */ SyscallDesc("getpriority", unimplementedFunc),
+ /* 97 */ SyscallDesc("setpriority", unimplementedFunc),
+ /* 98 */ SyscallDesc("profil", unimplementedFunc),
+ /* 99 */ SyscallDesc("statfs", unimplementedFunc),
+ /* 100 */ SyscallDesc("fstatfs", unimplementedFunc),
+ /* 101 */ SyscallDesc("ioperm", unimplementedFunc),
+ /* 102 */ SyscallDesc("socketcall", unimplementedFunc),
+ /* 103 */ SyscallDesc("syslog", unimplementedFunc),
+ /* 104 */ SyscallDesc("setitimer", unimplementedFunc),
+ /* 105 */ SyscallDesc("getitimer", unimplementedFunc),
+ /* 106 */ SyscallDesc("stat", statFunc<MipsLinux>),
+ /* 107 */ SyscallDesc("lstat", unimplementedFunc),
+ /* 108 */ SyscallDesc("fstat", fstatFunc<MipsLinux>),
+ /* 109 */ SyscallDesc("unused#109", unimplementedFunc),
+ /* 110 */ SyscallDesc("iopl", unimplementedFunc),
+ /* 111 */ SyscallDesc("vhangup", unimplementedFunc),
+ /* 112 */ SyscallDesc("idle", ignoreFunc),
+ /* 113 */ SyscallDesc("vm86", unimplementedFunc),
+ /* 114 */ SyscallDesc("wait4", unimplementedFunc),
+ /* 115 */ SyscallDesc("swapoff", unimplementedFunc),
+ /* 116 */ SyscallDesc("sysinfo", unimplementedFunc),
+ /* 117 */ SyscallDesc("ipc", unimplementedFunc),
+ /* 118 */ SyscallDesc("fsync", unimplementedFunc),
+ /* 119 */ SyscallDesc("sigreturn", unimplementedFunc),
+ /* 120 */ SyscallDesc("clone", unimplementedFunc),
+ /* 121 */ SyscallDesc("setdomainname", unimplementedFunc),
+ /* 122 */ SyscallDesc("uname", unameFunc),
+ /* 123 */ SyscallDesc("modify_ldt", unimplementedFunc),
+ /* 124 */ SyscallDesc("adjtimex", unimplementedFunc),
+ /* 125 */ SyscallDesc("mprotect", ignoreFunc),
+ /* 126 */ SyscallDesc("sigprocmask", unimplementedFunc),
+ /* 127 */ SyscallDesc("create_module", unimplementedFunc),
+ /* 128 */ SyscallDesc("init_module", unimplementedFunc),
+ /* 129 */ SyscallDesc("delete_module", unimplementedFunc),
+ /* 130 */ SyscallDesc("get_kernel_syms", unimplementedFunc),
+ /* 131 */ SyscallDesc("quotactl", unimplementedFunc),
+ /* 132 */ SyscallDesc("getpgid", unimplementedFunc),
+ /* 133 */ SyscallDesc("fchdir", unimplementedFunc),
+ /* 134 */ SyscallDesc("bdflush", unimplementedFunc),
+ /* 135 */ SyscallDesc("sysfs", unimplementedFunc),
+ /* 136 */ SyscallDesc("personality", unimplementedFunc),
+ /* 137 */ SyscallDesc("afs_syscall", unimplementedFunc),
+ /* 138 */ SyscallDesc("setfsuid", unimplementedFunc),
+ /* 139 */ SyscallDesc("setfsgid", unimplementedFunc),
+ /* 140 */ SyscallDesc("llseek", unimplementedFunc),
+ /* 141 */ SyscallDesc("getdents", unimplementedFunc),
+ /* 142 */ SyscallDesc("newselect", unimplementedFunc),
+ /* 143 */ SyscallDesc("flock", unimplementedFunc),
+ /* 144 */ SyscallDesc("msync", unimplementedFunc),/*getrlimitFunc<MipsLinux>*/
+ /* 145 */ SyscallDesc("readv", unimplementedFunc),
+ /* 146 */ SyscallDesc("writev", writevFunc<MipsLinux>),
+ /* 147 */ SyscallDesc("cacheflush", unimplementedFunc),
+ /* 148 */ SyscallDesc("cachectl", unimplementedFunc),
+ /* 149 */ SyscallDesc("sysmips", unimplementedFunc),
+ /* 150 */ SyscallDesc("unused#150", unimplementedFunc),
+ /* 151 */ SyscallDesc("getsid", unimplementedFunc),
+ /* 152 */ SyscallDesc("fdatasync", unimplementedFunc),
+ /* 153 */ SyscallDesc("sysctl", unimplementedFunc),
+ /* 154 */ SyscallDesc("mlock", unimplementedFunc),
+ /* 155 */ SyscallDesc("munlock", unimplementedFunc),
+ /* 156 */ SyscallDesc("mlockall", unimplementedFunc),
+ /* 157 */ SyscallDesc("munlockall", unimplementedFunc),
+ /* 158 */ SyscallDesc("sched_setparam", unimplementedFunc),
+ /* 159 */ SyscallDesc("sched_getparam", unimplementedFunc),
+ /* 160 */ SyscallDesc("sched_setscheduler", unimplementedFunc),
+ /* 161 */ SyscallDesc("sched_getscheduler", unimplementedFunc),
+ /* 162 */ SyscallDesc("sched_yield", unimplementedFunc),
+ /* 163 */ SyscallDesc("sched_get_prioritymax", unimplementedFunc),
+ /* 164 */ SyscallDesc("sched_get_priority_min", unimplementedFunc),
+ /* 165 */ SyscallDesc("sched_rr_get_interval", unimplementedFunc),
+ /* 166 */ SyscallDesc("nanosleep", unimplementedFunc),
+ /* 167 */ SyscallDesc("mremap", unimplementedFunc),
+ /* 168 */ SyscallDesc("accept", unimplementedFunc),
+ /* 169 */ SyscallDesc("bind", unimplementedFunc),
+ /* 170 */ SyscallDesc("connect", unimplementedFunc),
+ /* 171 */ SyscallDesc("getpeername", unimplementedFunc),
+ /* 172 */ SyscallDesc("getsockname", unimplementedFunc),
+ /* 173 */ SyscallDesc("getsockopt", unimplementedFunc),
+ /* 174 */ SyscallDesc("listen", unimplementedFunc),
+ /* 175 */ SyscallDesc("recv", unimplementedFunc),
+ /* 176 */ SyscallDesc("recvmsg", unimplementedFunc),
+ /* 177 */ SyscallDesc("send", unimplementedFunc),
+ /* 178 */ SyscallDesc("sendmsg", ignoreFunc),
+ /* 179 */ SyscallDesc("sendto", unimplementedFunc),
+ /* 180 */ SyscallDesc("setsockopt", unimplementedFunc),
+ /* 181 */ SyscallDesc("shutdown", unimplementedFunc),
+ /* 182 */ SyscallDesc("unknown #182", unimplementedFunc),
+ /* 183 */ SyscallDesc("socket", ignoreFunc),
+ /* 184 */ SyscallDesc("socketpair", unimplementedFunc),
+ /* 185 */ SyscallDesc("setresuid", unimplementedFunc),
+ /* 186 */ SyscallDesc("getresuid", unimplementedFunc),
+ /* 187 */ SyscallDesc("query_module", unimplementedFunc),
+ /* 188 */ SyscallDesc("poll", unimplementedFunc),
+ /* 189 */ SyscallDesc("nfsservctl", unimplementedFunc),
+ /* 190 */ SyscallDesc("setresgid", unimplementedFunc),
+ /* 191 */ SyscallDesc("getresgid", unimplementedFunc),
+ /* 192 */ SyscallDesc("prctl", unimplementedFunc),
+ /* 193 */ SyscallDesc("rt_sigreturn", unimplementedFunc),
+ /* 194 */ SyscallDesc("rt_sigaction", ignoreFunc),
+ /* 195 */ SyscallDesc("rt_sigprocmask", ignoreFunc),
+ /* 196 */ SyscallDesc("rt_sigpending", unimplementedFunc),
+ /* 197 */ SyscallDesc("rt_sigtimedwait", unimplementedFunc),
+ /* 198 */ SyscallDesc("rt_sigqueueinfo", ignoreFunc),
+ /* 199 */ SyscallDesc("rt_sigsuspend", unimplementedFunc),
+ /* 200 */ SyscallDesc("pread64", unimplementedFunc),
+ /* 201 */ SyscallDesc("pwrite64", unimplementedFunc),
+ /* 202 */ SyscallDesc("chown", unimplementedFunc),
+ /* 203 */ SyscallDesc("getcwd", unimplementedFunc),
+ /* 204 */ SyscallDesc("capget", unimplementedFunc),
+ /* 205 */ SyscallDesc("capset", unimplementedFunc),
+ /* 206 */ SyscallDesc("sigalstack", unimplementedFunc),
+ /* 207 */ SyscallDesc("sendfile", unimplementedFunc),
+ /* 208 */ SyscallDesc("getpmsg", unimplementedFunc),
+ /* 209 */ SyscallDesc("putpmsg", unimplementedFunc),
+ /* 210 */ SyscallDesc("mmap2", unimplementedFunc),
+ /* 211 */ SyscallDesc("truncate64", unimplementedFunc),
+ /* 212 */ SyscallDesc("ftruncate64", unimplementedFunc),
+ /* 213 */ SyscallDesc("stat64", unimplementedFunc),
+ /* 214 */ SyscallDesc("lstat64", lstat64Func<MipsLinux>),
+ /* 215 */ SyscallDesc("fstat64", fstat64Func<MipsLinux>),
+ /* 216 */ SyscallDesc("pivot_root", unimplementedFunc),
+ /* 217 */ SyscallDesc("mincore", unimplementedFunc),
+ /* 218 */ SyscallDesc("madvise", unimplementedFunc),
+ /* 219 */ SyscallDesc("getdents64", unimplementedFunc),
+ /* 220 */ SyscallDesc("fcntl64", fcntlFunc),
+ /* 221 */ SyscallDesc("reserved#221", unimplementedFunc),
+ /* 222 */ SyscallDesc("gettid", unimplementedFunc),
+ /* 223 */ SyscallDesc("readahead", unimplementedFunc),
+ /* 224 */ SyscallDesc("setxattr", unimplementedFunc),
+ /* 225 */ SyscallDesc("lsetxattr", unimplementedFunc),
+ /* 226 */ SyscallDesc("fsetxattr", unimplementedFunc),
+ /* 227 */ SyscallDesc("getxattr", unimplementedFunc),
+ /* 228 */ SyscallDesc("lgetxattr", unimplementedFunc),
+ /* 229 */ SyscallDesc("fgetxattr", unimplementedFunc),
+ /* 230 */ SyscallDesc("listxattr", unimplementedFunc),
+ /* 231 */ SyscallDesc("llistxattr", unimplementedFunc),
+ /* 232 */ SyscallDesc("flistxattr", unimplementedFunc),
+ /* 233 */ SyscallDesc("removexattr", unimplementedFunc),
+ /* 234 */ SyscallDesc("lremovexattr", unimplementedFunc),
+ /* 235 */ SyscallDesc("fremovexattr", ignoreFunc),
+ /* 236 */ SyscallDesc("tkill", unimplementedFunc),
+ /* 237 */ SyscallDesc("sendfile64", unimplementedFunc),
+ /* 238 */ SyscallDesc("futex", unimplementedFunc),
+ /* 239 */ SyscallDesc("sched_setaffinity", unimplementedFunc),
+ /* 240 */ SyscallDesc("sched_getaffinity", unimplementedFunc),
+ /* 241 */ SyscallDesc("io_setup", unimplementedFunc),
+ /* 242 */ SyscallDesc("io_destroy", unimplementedFunc),
+ /* 243 */ SyscallDesc("io_getevents", unimplementedFunc),
+ /* 244 */ SyscallDesc("io_submit", unimplementedFunc),
+ /* 245 */ SyscallDesc("io_cancel", unimplementedFunc),
+ /* 246 */ SyscallDesc("exit_group", exitFunc),
+ /* 247 */ SyscallDesc("lookup_dcookie", unimplementedFunc),
+ /* 248 */ SyscallDesc("epoll_create", unimplementedFunc),
+ /* 249 */ SyscallDesc("epoll_ctl", unimplementedFunc),
+ /* 250 */ SyscallDesc("epoll_wait", unimplementedFunc),
+ /* 251 */ SyscallDesc("remap_file_pages", unimplementedFunc),
+ /* 252 */ SyscallDesc("set_tid_address", unimplementedFunc),
+ /* 253 */ SyscallDesc("restart_syscall", unimplementedFunc),
+ /* 254 */ SyscallDesc("fadvise64", unimplementedFunc),
+ /* 255 */ SyscallDesc("statfs64", unimplementedFunc),
+ /* 256 */ SyscallDesc("fstafs64", unimplementedFunc),
+ /* 257 */ SyscallDesc("timer_create", sys_getsysinfoFunc),
+ /* 258 */ SyscallDesc("timer_settime", sys_setsysinfoFunc),
+ /* 259 */ SyscallDesc("timer_gettime", unimplementedFunc),
+ /* 260 */ SyscallDesc("timer_getoverrun", unimplementedFunc),
+ /* 261 */ SyscallDesc("timer_delete", unimplementedFunc),
+ /* 262 */ SyscallDesc("clock_settime", unimplementedFunc),
+ /* 263 */ SyscallDesc("clock_gettime", unimplementedFunc),
+ /* 264 */ SyscallDesc("clock_getres", unimplementedFunc),
+ /* 265 */ SyscallDesc("clock_nanosleep", unimplementedFunc),
+ /* 266 */ SyscallDesc("tgkill", unimplementedFunc),
+ /* 267 */ SyscallDesc("utimes", unimplementedFunc),
+ /* 268 */ SyscallDesc("mbind", unimplementedFunc),
+ /* 269 */ SyscallDesc("get_mempolicy", unimplementedFunc),
+ /* 270 */ SyscallDesc("set_mempolicy", unimplementedFunc),
+ /* 271 */ SyscallDesc("mq_open", unimplementedFunc),
+ /* 272 */ SyscallDesc("mq_unlink", unimplementedFunc),
+ /* 273 */ SyscallDesc("mq_timedsend", unimplementedFunc),
+ /* 274 */ SyscallDesc("mq_timedreceive", unimplementedFunc),
+ /* 275 */ SyscallDesc("mq_notify", unimplementedFunc),
+ /* 276 */ SyscallDesc("mq_getsetattr", unimplementedFunc),
+ /* 277 */ SyscallDesc("vserver", unimplementedFunc),
+ /* 278 */ SyscallDesc("waitid", unimplementedFunc),
+ /* 279 */ SyscallDesc("unknown #279", unimplementedFunc),
+ /* 280 */ SyscallDesc("add_key", unimplementedFunc),
+ /* 281 */ SyscallDesc("request_key", unimplementedFunc),
+ /* 282 */ SyscallDesc("keyctl", unimplementedFunc),
+};
+
+MipsLinuxProcess::MipsLinuxProcess(const std::string &name,
+ ObjectFile *objFile,
+ System *system,
+ int stdin_fd,
+ int stdout_fd,
+ int stderr_fd,
+ std::vector<std::string> &argv,
+ std::vector<std::string> &envp)
+ : MipsLiveProcess(name, objFile, system, stdin_fd, stdout_fd, stderr_fd,
+ argv, envp),
+ Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc))
+{
+ //init_regs->intRegFile[0] = 0;
+}
+
+SyscallDesc*
+MipsLinuxProcess::getDesc(int callnum)
+{
+ //MIPS32 syscalls are in the range of 4000 - 4999
+ int m5_sys_idx = callnum - 4000;
+
+ if (m5_sys_idx < 0 || m5_sys_idx > Num_Syscall_Descs)
+ return NULL;
+
+ return &syscallDescs[m5_sys_idx];
+}
diff --git a/src/arch/mips/linux/process.hh b/src/arch/mips/linux/process.hh
new file mode 100644
index 000000000..68da3227b
--- /dev/null
+++ b/src/arch/mips/linux/process.hh
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2003-2004 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MIPS_LINUX_PROCESS_HH__
+#define __MIPS_LINUX_PROCESS_HH__
+
+#include "arch/mips/process.hh"
+
+
+/// A process with emulated Mips/Linux syscalls.
+class MipsLinuxProcess : public MipsLiveProcess
+{
+ public:
+ /// Constructor.
+ MipsLinuxProcess(const std::string &name,
+ ObjectFile *objFile,
+ System *system,
+ int stdin_fd, int stdout_fd, int stderr_fd,
+ std::vector<std::string> &argv,
+ std::vector<std::string> &envp);
+
+ virtual SyscallDesc* getDesc(int callnum);
+
+ /// The target system's hostname.
+ static const char *hostname;
+
+ /// Array of syscall descriptors, indexed by call number.
+ static SyscallDesc syscallDescs[];
+
+ const int Num_Syscall_Descs;
+};
+
+
+#endif // __MIPS_LINUX_PROCESS_HH__
diff --git a/src/arch/mips/process.cc b/src/arch/mips/process.cc
new file mode 100644
index 000000000..7831551be
--- /dev/null
+++ b/src/arch/mips/process.cc
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2003-2004 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "arch/mips/isa_traits.hh"
+#include "arch/mips/process.hh"
+#include "arch/mips/linux/process.hh"
+#include "base/loader/object_file.hh"
+#include "base/misc.hh"
+#include "cpu/exec_context.hh"
+#include "sim/builder.hh"
+#include "sim/system.hh"
+
+using namespace std;
+using namespace MipsISA;
+
+
+MipsLiveProcess *
+MipsLiveProcess::create(const std::string &nm, System *system, int stdin_fd,
+ int stdout_fd, int stderr_fd, std::string executable,
+ std::vector<std::string> &argv, std::vector<std::string> &envp)
+{
+ MipsLiveProcess *process = NULL;
+
+ ObjectFile *objFile = createObjectFile(executable);
+ if (objFile == NULL) {
+ fatal("Can't load object file %s", executable);
+ }
+
+
+ if (objFile->getArch() != ObjectFile::Mips)
+ fatal("Object file does not match architecture.");
+ switch (objFile->getOpSys()) {
+ case ObjectFile::Linux:
+ process = new MipsLinuxProcess(nm, objFile, system,
+ stdin_fd, stdout_fd, stderr_fd,
+ argv, envp);
+ break;
+
+ default:
+ fatal("Unknown/unsupported operating system.");
+ }
+
+ if (process == NULL)
+ fatal("Unknown error creating process object.");
+ return process;
+}
+
+MipsLiveProcess::MipsLiveProcess(const std::string &nm, ObjectFile *objFile,
+ System *_system, int stdin_fd, int stdout_fd, int stderr_fd,
+ std::vector<std::string> &argv, std::vector<std::string> &envp)
+ : LiveProcess(nm, objFile, _system, stdin_fd, stdout_fd, stderr_fd,
+ argv, envp)
+{
+
+ // XXX all the below need to be updated for SPARC - Ali
+ brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize();
+ brk_point = roundUp(brk_point, VMPageSize);
+
+ // Set up stack. On Alpha, stack goes below text section. This
+ // code should get moved to some architecture-specific spot.
+ stack_base = objFile->textBase() - (409600+4096);
+
+ // Set up region for mmaps. Tru64 seems to start just above 0 and
+ // grow up from there.
+ mmap_start = mmap_end = 0x10000;
+
+ // Set pointer for next thread stack. Reserve 8M for main stack.
+ next_thread_stack_base = stack_base - (8 * 1024 * 1024);
+
+}
+
+void
+MipsLiveProcess::startup()
+{
+ argsInit(MachineBytes, VMPageSize);
+}
+
+
+
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(MipsLiveProcess)
+
+ VectorParam<string> cmd;
+ Param<string> executable;
+ Param<string> input;
+ Param<string> output;
+ VectorParam<string> env;
+ SimObjectParam<System *> system;
+
+END_DECLARE_SIM_OBJECT_PARAMS(MipsLiveProcess)
+
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(MipsLiveProcess)
+
+ INIT_PARAM(cmd, "command line (executable plus arguments)"),
+ INIT_PARAM(executable, "executable (overrides cmd[0] if set)"),
+ INIT_PARAM(input, "filename for stdin (dflt: use sim stdin)"),
+ INIT_PARAM(output, "filename for stdout/stderr (dflt: use sim stdout)"),
+ INIT_PARAM(env, "environment settings"),
+ INIT_PARAM(system, "system")
+
+END_INIT_SIM_OBJECT_PARAMS(MipsLiveProcess)
+
+
+CREATE_SIM_OBJECT(MipsLiveProcess)
+{
+ string in = input;
+ string out = output;
+
+ // initialize file descriptors to default: same as simulator
+ int stdin_fd, stdout_fd, stderr_fd;
+
+ if (in == "stdin" || in == "cin")
+ stdin_fd = STDIN_FILENO;
+ else
+ stdin_fd = Process::openInputFile(input);
+
+ if (out == "stdout" || out == "cout")
+ stdout_fd = STDOUT_FILENO;
+ else if (out == "stderr" || out == "cerr")
+ stdout_fd = STDERR_FILENO;
+ else
+ stdout_fd = Process::openOutputFile(out);
+
+ stderr_fd = (stdout_fd != STDOUT_FILENO) ? stdout_fd : STDERR_FILENO;
+
+ return MipsLiveProcess::create(getInstanceName(), system,
+ stdin_fd, stdout_fd, stderr_fd,
+ (string)executable == "" ? cmd[0] : executable,
+ cmd, env);
+}
+
+
+REGISTER_SIM_OBJECT("MipsLiveProcess", MipsLiveProcess)
+
+
diff --git a/src/arch/mips/process.hh b/src/arch/mips/process.hh
new file mode 100644
index 000000000..2a13dc955
--- /dev/null
+++ b/src/arch/mips/process.hh
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2003-2004 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MIPS_PROCESS_HH__
+#define __MIPS_PROCESS_HH__
+
+#include <string>
+#include <vector>
+#include "sim/process.hh"
+
+class LiveProcess;
+class ObjectFile;
+class System;
+
+class MipsLiveProcess : public LiveProcess
+{
+ protected:
+ MipsLiveProcess(const std::string &nm, ObjectFile *objFile,
+ System *_system, int stdin_fd, int stdout_fd, int stderr_fd,
+ std::vector<std::string> &argv,
+ std::vector<std::string> &envp);
+
+ void startup();
+
+ public:
+ // this function is used to create the LiveProcess object, since
+ // we can't tell which subclass of LiveProcess to use until we
+ // open and look at the object file.
+ static MipsLiveProcess *create(const std::string &nm,
+ System *_system,
+ int stdin_fd, int stdout_fd, int stderr_fd,
+ std::string executable,
+ std::vector<std::string> &argv,
+ std::vector<std::string> &envp);
+
+};
+
+
+#endif // __MIPS_PROCESS_HH__
diff --git a/src/arch/mips/regfile/float_regfile.hh b/src/arch/mips/regfile/float_regfile.hh
new file mode 100644
index 000000000..15c6f97f4
--- /dev/null
+++ b/src/arch/mips/regfile/float_regfile.hh
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ARCH_MIPS_FLOAT_REGFILE_HH__
+#define __ARCH_MIPS_FLOAT_REGFILE_HH__
+
+#include "arch/mips/types.hh"
+#include "arch/mips/constants.hh"
+#include "base/misc.hh"
+#include "config/full_system.hh"
+#include "sim/byteswap.hh"
+#include "sim/faults.hh"
+#include "sim/host.hh"
+
+class Checkpoint;
+class ExecContext;
+class Regfile;
+
+namespace MipsISA
+{
+ class FloatRegFile
+ {
+ protected:
+ FloatReg32 regs[NumFloatRegs];
+
+ public:
+
+ void clear()
+ {
+ bzero(regs, sizeof(regs));
+ }
+
+ double readReg(int floatReg, int width)
+ {
+ switch(width)
+ {
+ case SingleWidth:
+ void *float_ptr = &regs[floatReg];
+ return *(float *) float_ptr;
+
+ case DoubleWidth:
+ uint64_t double_val = (FloatReg64)regs[floatReg + 1] << 32 | regs[floatReg];
+ void *double_ptr = &double_val;
+ return *(double *) double_ptr;
+
+ default:
+ panic("Attempted to read a %d bit floating point register!", width);
+ }
+ }
+
+ FloatRegBits readRegBits(int floatReg, int width)
+ {
+ if (floatReg < NumFloatArchRegs - 1) {
+ switch(width)
+ {
+ case SingleWidth:
+ return regs[floatReg];
+
+ case DoubleWidth:
+ return (FloatReg64)regs[floatReg + 1] << 32 | regs[floatReg];
+
+ default:
+ panic("Attempted to read a %d bit floating point register!", width);
+ }
+ } else {
+ if (width > SingleWidth)
+ assert("Control Regs are only 32 bits wide");
+
+ return regs[floatReg];
+ }
+ }
+
+ Fault setReg(int floatReg, const FloatReg &val, int width)
+ {
+
+ switch(width)
+ {
+ case SingleWidth:
+ float temp = val;
+ void *float_ptr = &temp;
+ regs[floatReg] = *(FloatReg32 *) float_ptr;
+ break;
+
+ case DoubleWidth:
+ const void *double_ptr = &val;
+ FloatReg64 temp_double = *(FloatReg64 *) double_ptr;
+ regs[floatReg + 1] = temp_double >> 32;
+ regs[floatReg] = temp_double;
+ break;
+
+ default:
+ panic("Attempted to read a %d bit floating point register!", width);
+ }
+
+ return NoFault;
+ }
+
+ Fault setRegBits(int floatReg, const FloatRegBits &val, int width)
+ {
+ using namespace std;
+
+ switch(width)
+ {
+ case SingleWidth:
+ regs[floatReg] = val;
+ break;
+
+ case DoubleWidth:
+ regs[floatReg + 1] = val >> 32;
+ regs[floatReg] = val;
+ break;
+
+ default:
+ panic("Attempted to read a %d bit floating point register!", width);
+ }
+ return NoFault;
+ }
+
+ void serialize(std::ostream &os);
+
+ void unserialize(Checkpoint *cp, const std::string &section);
+ };
+
+ enum MiscFloatRegNums {
+ FIR = NumFloatArchRegs,
+ FCCR,
+ FEXR,
+ FENR,
+ FCSR
+ };
+
+} // namespace MipsISA
+
+#endif
diff --git a/src/arch/mips/regfile/int_regfile.hh b/src/arch/mips/regfile/int_regfile.hh
new file mode 100644
index 000000000..3cd87734d
--- /dev/null
+++ b/src/arch/mips/regfile/int_regfile.hh
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ARCH_MIPS_INT_REGFILE_HH__
+#define __ARCH_MIPS_INT_REGFILE_HH__
+
+#include "arch/mips/types.hh"
+#include "arch/mips/constants.hh"
+#include "base/misc.hh"
+#include "sim/faults.hh"
+
+class Checkpoint;
+class ExecContext;
+class Regfile;
+
+namespace MipsISA
+{
+ class IntRegFile
+ {
+ protected:
+ IntReg regs[NumIntRegs];
+
+ public:
+ IntReg readReg(int intReg)
+ {
+ return regs[intReg];
+ }
+
+ Fault setReg(int intReg, const IntReg &val)
+ {
+ regs[intReg] = val;
+ return NoFault;
+ }
+
+ void serialize(std::ostream &os);
+
+ void unserialize(Checkpoint *cp, const std::string &section);
+
+ };
+
+ enum MiscIntRegNums {
+ HI = NumIntArchRegs,
+ LO
+ };
+
+} // namespace MipsISA
+
+#endif
diff --git a/src/arch/mips/regfile/misc_regfile.hh b/src/arch/mips/regfile/misc_regfile.hh
new file mode 100644
index 000000000..9f054e5f7
--- /dev/null
+++ b/src/arch/mips/regfile/misc_regfile.hh
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ARCH_MIPS_MISC_REGFILE_HH__
+#define __ARCH_MIPS_MISC_REGFILE_HH__
+
+#include "arch/mips/types.hh"
+#include "arch/mips/constants.hh"
+#include "sim/faults.hh"
+
+class Checkpoint;
+class ExecContext;
+class Regfile;
+
+namespace MipsISA
+{
+ class MiscRegFile {
+
+ protected:
+ uint64_t fpcr; // floating point condition codes
+ uint64_t uniq; // process-unique register
+ bool lock_flag; // lock flag for LL/SC
+ Addr lock_addr; // lock address for LL/SC
+
+ MiscReg miscRegFile[NumMiscRegs];
+
+ public:
+ //These functions should be removed once the simplescalar cpu model
+ //has been replaced.
+ int getInstAsid();
+ int getDataAsid();
+
+ void copyMiscRegs(ExecContext *xc);
+
+ MiscReg readReg(int misc_reg)
+ {
+ return miscRegFile[misc_reg];
+ }
+
+ MiscReg readRegWithEffect(int misc_reg, Fault &fault, ExecContext *xc)
+ {
+ return miscRegFile[misc_reg];
+ }
+
+ Fault setReg(int misc_reg, const MiscReg &val)
+ {
+ miscRegFile[misc_reg] = val; return NoFault;
+ }
+
+ Fault setRegWithEffect(int misc_reg, const MiscReg &val,
+ ExecContext *xc)
+ {
+ miscRegFile[misc_reg] = val; return NoFault;
+ }
+
+#if FULL_SYSTEM
+ void clearIprs() { }
+
+ protected:
+ InternalProcReg ipr[NumInternalProcRegs]; // Internal processor regs
+
+ private:
+ MiscReg readIpr(int idx, Fault &fault, ExecContext *xc) { }
+
+ Fault setIpr(int idx, uint64_t val, ExecContext *xc) { }
+#endif
+ friend class RegFile;
+ };
+} // namespace MipsISA
+
+#endif
diff --git a/src/arch/mips/regfile/regfile.hh b/src/arch/mips/regfile/regfile.hh
new file mode 100644
index 000000000..e77571b33
--- /dev/null
+++ b/src/arch/mips/regfile/regfile.hh
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ARCH_MIPS_REGFILE_HH__
+#define __ARCH_MIPS_REGFILE_HH__
+
+#include "arch/mips/types.hh"
+#include "arch/mips/constants.hh"
+#include "arch/mips/regfile/int_regfile.hh"
+#include "arch/mips/regfile/float_regfile.hh"
+#include "arch/mips/regfile/misc_regfile.hh"
+#include "sim/faults.hh"
+
+class Checkpoint;
+class ExecContext;
+
+namespace MipsISA
+{
+ class RegFile {
+ protected:
+ IntRegFile intRegFile; // (signed) integer register file
+ FloatRegFile floatRegFile; // floating point register file
+ MiscRegFile miscRegFile; // control register file
+
+ public:
+
+ void clear()
+ {
+ bzero(&intRegFile, sizeof(intRegFile));
+ bzero(&floatRegFile, sizeof(floatRegFile));
+ bzero(&miscRegFile, sizeof(miscRegFile));
+ }
+
+ MiscReg readMiscReg(int miscReg)
+ {
+ return miscRegFile.readReg(miscReg);
+ }
+
+ MiscReg readMiscRegWithEffect(int miscReg,
+ Fault &fault, ExecContext *xc)
+ {
+ fault = NoFault;
+ return miscRegFile.readRegWithEffect(miscReg, fault, xc);
+ }
+
+ Fault setMiscReg(int miscReg, const MiscReg &val)
+ {
+ return miscRegFile.setReg(miscReg, val);
+ }
+
+ Fault setMiscRegWithEffect(int miscReg, const MiscReg &val,
+ ExecContext * xc)
+ {
+ return miscRegFile.setRegWithEffect(miscReg, val, xc);
+ }
+
+ FloatReg readFloatReg(int floatReg)
+ {
+ return floatRegFile.readReg(floatReg,SingleWidth);
+ }
+
+ FloatReg readFloatReg(int floatReg, int width)
+ {
+ return floatRegFile.readReg(floatReg,width);
+ }
+
+ FloatRegBits readFloatRegBits(int floatReg)
+ {
+ return floatRegFile.readRegBits(floatReg,SingleWidth);
+ }
+
+ FloatRegBits readFloatRegBits(int floatReg, int width)
+ {
+ return floatRegFile.readRegBits(floatReg,width);
+ }
+
+ Fault setFloatReg(int floatReg, const FloatReg &val)
+ {
+ return floatRegFile.setReg(floatReg, val, SingleWidth);
+ }
+
+ Fault setFloatReg(int floatReg, const FloatReg &val, int width)
+ {
+ return floatRegFile.setReg(floatReg, val, width);
+ }
+
+ Fault setFloatRegBits(int floatReg, const FloatRegBits &val)
+ {
+ return floatRegFile.setRegBits(floatReg, val, SingleWidth);
+ }
+
+ Fault setFloatRegBits(int floatReg, const FloatRegBits &val, int width)
+ {
+ return floatRegFile.setRegBits(floatReg, val, width);
+ }
+
+ IntReg readIntReg(int intReg)
+ {
+ return intRegFile.readReg(intReg);
+ }
+
+ Fault setIntReg(int intReg, const IntReg &val)
+ {
+ return intRegFile.setReg(intReg, val);
+ }
+ protected:
+
+ Addr pc; // program counter
+ Addr npc; // next-cycle program counter
+ Addr nnpc; // next-next-cycle program counter
+ // used to implement branch delay slot
+ // not real register
+ public:
+ Addr readPC()
+ {
+ return pc;
+ }
+
+ void setPC(Addr val)
+ {
+ pc = val;
+ }
+
+ Addr readNextPC()
+ {
+ return npc;
+ }
+
+ void setNextPC(Addr val)
+ {
+ npc = val;
+ }
+
+ Addr readNextNPC()
+ {
+ return nnpc;
+ }
+
+ void setNextNPC(Addr val)
+ {
+ nnpc = val;
+ }
+
+
+#if FULL_SYSTEM
+ IntReg palregs[NumIntRegs]; // PAL shadow registers
+ InternalProcReg ipr[NumInternalProcRegs]; // internal processor regs
+ int intrflag; // interrupt flag
+ bool pal_shadow; // using pal_shadow registers
+ inline int instAsid() { return MIPS34K::ITB_ASN_ASN(ipr[IPR_ITB_ASN]); }
+ inline int dataAsid() { return MIPS34K::DTB_ASN_ASN(ipr[IPR_DTB_ASN]); }
+#endif // FULL_SYSTEM
+
+ void serialize(std::ostream &os);
+ void unserialize(Checkpoint *cp, const std::string &section);
+
+ typedef int ContextParam;
+ typedef int ContextVal;
+
+ void changeContext(ContextParam param, ContextVal val)
+ {
+ }
+ };
+
+ void copyRegs(ExecContext *src, ExecContext *dest);
+
+ void copyMiscRegs(ExecContext *src, ExecContext *dest);
+
+#if FULL_SYSTEM
+ void copyIprs(ExecContext *src, ExecContext *dest);
+#endif
+} // namespace MipsISA
+
+#endif
diff --git a/src/arch/mips/stacktrace.hh b/src/arch/mips/stacktrace.hh
new file mode 100644
index 000000000..1d8d97a79
--- /dev/null
+++ b/src/arch/mips/stacktrace.hh
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ARCH_ALPHA_STACKTRACE_HH__
+#define __ARCH_ALPHA_STACKTRACE_HH__
+
+#include "base/trace.hh"
+#include "cpu/static_inst.hh"
+
+class ExecContext;
+class StackTrace;
+
+class ProcessInfo
+{
+ private:
+ ExecContext *xc;
+
+ int thread_info_size;
+ int task_struct_size;
+ int task_off;
+ int pid_off;
+ int name_off;
+
+ public:
+ ProcessInfo(ExecContext *_xc);
+
+ Addr task(Addr ksp) const;
+ int pid(Addr ksp) const;
+ std::string name(Addr ksp) const;
+};
+
+class StackTrace
+{
+ protected:
+ typedef TheISA::MachInst MachInst;
+ private:
+ ExecContext *xc;
+ std::vector<Addr> stack;
+
+ private:
+ bool isEntry(Addr addr);
+ bool decodePrologue(Addr sp, Addr callpc, Addr func, int &size, Addr &ra);
+ bool decodeSave(MachInst inst, int &reg, int &disp);
+ bool decodeStack(MachInst inst, int &disp);
+
+ void trace(ExecContext *xc, bool is_call);
+
+ public:
+ StackTrace();
+ StackTrace(ExecContext *xc, StaticInstPtr inst);
+ ~StackTrace();
+
+ void clear()
+ {
+ xc = 0;
+ stack.clear();
+ }
+
+ bool valid() const { return xc != NULL; }
+ bool trace(ExecContext *xc, StaticInstPtr inst);
+
+ public:
+ const std::vector<Addr> &getstack() const { return stack; }
+
+ static const int user = 1;
+ static const int console = 2;
+ static const int unknown = 3;
+
+#if TRACING_ON
+ private:
+ void dump();
+
+ public:
+ void dprintf() { if (DTRACE(Stack)) dump(); }
+#else
+ public:
+ void dprintf() {}
+#endif
+};
+
+inline bool
+StackTrace::trace(ExecContext *xc, StaticInstPtr inst)
+{
+ if (!inst->isCall() && !inst->isReturn())
+ return false;
+
+ if (valid())
+ clear();
+
+ trace(xc, !inst->isReturn());
+ return true;
+}
+
+#endif // __ARCH_ALPHA_STACKTRACE_HH__
diff --git a/src/arch/mips/types.hh b/src/arch/mips/types.hh
new file mode 100644
index 000000000..4d5fb3456
--- /dev/null
+++ b/src/arch/mips/types.hh
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ARCH_MIPS_TYPES_HH__
+#define __ARCH_MIPS_TYPES_HH__
+
+#include "sim/host.hh"
+
+namespace MipsISA
+{
+ typedef uint32_t MachInst;
+ typedef uint64_t ExtMachInst;
+ typedef uint8_t RegIndex;
+
+ typedef uint32_t IntReg;
+
+ // floating point register file entry type
+ typedef double FloatReg;
+ typedef uint32_t FloatReg32;
+ typedef uint64_t FloatReg64;
+ typedef uint64_t FloatRegBits;
+
+ // cop-0/cop-1 system control register
+ typedef uint64_t MiscReg;
+ typedef uint64_t InternalProcReg;
+
+ typedef union {
+ IntReg intreg;
+ FloatReg fpreg;
+ MiscReg ctrlreg;
+ } AnyReg;
+
+ //used in FP convert & round function
+ enum ConvertType{
+ SINGLE_TO_DOUBLE,
+ SINGLE_TO_WORD,
+ SINGLE_TO_LONG,
+
+ DOUBLE_TO_SINGLE,
+ DOUBLE_TO_WORD,
+ DOUBLE_TO_LONG,
+
+ LONG_TO_SINGLE,
+ LONG_TO_DOUBLE,
+ LONG_TO_WORD,
+ LONG_TO_PS,
+
+ WORD_TO_SINGLE,
+ WORD_TO_DOUBLE,
+ WORD_TO_LONG,
+ WORD_TO_PS,
+
+ PL_TO_SINGLE,
+ PU_TO_SINGLE
+ };
+
+ //used in FP convert & round function
+ enum RoundMode{
+ RND_ZERO,
+ RND_DOWN,
+ RND_UP,
+ RND_NEAREST
+ };
+
+} // namespace MipsISA
+
+#endif
diff --git a/src/arch/mips/utility.hh b/src/arch/mips/utility.hh
new file mode 100644
index 000000000..5c7dc3ea4
--- /dev/null
+++ b/src/arch/mips/utility.hh
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ * Steve Reinhardt
+ */
+
+#ifndef __ARCH_MIPS_UTILITY_HH__
+#define __ARCH_MIPS_UTILITY_HH__
+
+#include "arch/mips/types.hh"
+#include "arch/mips/constants.hh"
+#include "base/misc.hh"
+#include "sim/host.hh"
+
+namespace MipsISA {
+
+};
+
+#endif
diff --git a/src/arch/sparc/SConscript b/src/arch/sparc/SConscript
new file mode 100644
index 000000000..7362c9275
--- /dev/null
+++ b/src/arch/sparc/SConscript
@@ -0,0 +1,84 @@
+# -*- mode:python -*-
+
+# Copyright (c) 2004-2005 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import os
+import sys
+from os.path import isdir
+
+# Import build environment variable from SConstruct.
+Import('env')
+
+###################################################
+#
+# Define needed sources.
+#
+###################################################
+
+# Base sources used by all configurations.
+base_sources = Split('''
+ faults.cc
+ isa_traits.cc
+ ''')
+
+# Full-system sources
+full_system_sources = Split('''
+ tlb.cc
+ arguments.cc
+ ev5.cc
+ osfpal.cc
+ stacktrace.cc
+ vtophys.cc
+ ''')
+
+# Syscall emulation (non-full-system) sources
+syscall_emulation_sources = Split('''
+ linux/linux.cc
+ linux/process.cc
+ solaris/solaris.cc
+ solaris/process.cc
+ process.cc
+ ''')
+
+sources = base_sources
+
+if env['FULL_SYSTEM']:
+ sources += full_system_sources
+else:
+ sources += syscall_emulation_sources
+
+# Convert file names to SCons File objects. This takes care of the
+# path relative to the top of the directory tree.
+sources = [File(s) for s in sources]
+
+# Add in files generated by the ISA description.
+isa_desc_files = env.ISADesc('isa/main.isa')
+# Only non-header files need to be compiled.
+isa_desc_sources = [f for f in isa_desc_files if not f.path.endswith('.hh')]
+sources += isa_desc_sources
+
+Return('sources')
diff --git a/src/arch/sparc/faults.cc b/src/arch/sparc/faults.cc
new file mode 100644
index 000000000..67a89ab0e
--- /dev/null
+++ b/src/arch/sparc/faults.cc
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "arch/sparc/faults.hh"
+#include "cpu/exec_context.hh"
+#include "cpu/base.hh"
+#include "base/trace.hh"
+
+namespace SparcISA
+{
+
+FaultName InternalProcessorError::_name = "intprocerr";
+TrapType InternalProcessorError::_trapType = 0x029;
+FaultPriority InternalProcessorError::_priority = 4;
+FaultStat InternalProcessorError::_count;
+
+FaultName MemAddressNotAligned::_name = "unalign";
+TrapType MemAddressNotAligned::_trapType = 0x034;
+FaultPriority MemAddressNotAligned::_priority = 10;
+FaultStat MemAddressNotAligned::_count;
+
+FaultName PowerOnReset::_name = "pow_reset";
+TrapType PowerOnReset::_trapType = 0x001;
+FaultPriority PowerOnReset::_priority = 0;
+FaultStat PowerOnReset::_count;
+
+FaultName WatchDogReset::_name = "watch_dog_reset";
+TrapType WatchDogReset::_trapType = 0x002;
+FaultPriority WatchDogReset::_priority = 1;
+FaultStat WatchDogReset::_count;
+
+FaultName ExternallyInitiatedReset::_name = "extern_reset";
+TrapType ExternallyInitiatedReset::_trapType = 0x003;
+FaultPriority ExternallyInitiatedReset::_priority = 1;
+FaultStat ExternallyInitiatedReset::_count;
+
+FaultName SoftwareInitiatedReset::_name = "software_reset";
+TrapType SoftwareInitiatedReset::_trapType = 0x004;
+FaultPriority SoftwareInitiatedReset::_priority = 1;
+FaultStat SoftwareInitiatedReset::_count;
+
+FaultName REDStateException::_name = "red_counte";
+TrapType REDStateException::_trapType = 0x005;
+FaultPriority REDStateException::_priority = 1;
+FaultStat REDStateException::_count;
+
+FaultName InstructionAccessException::_name = "inst_access";
+TrapType InstructionAccessException::_trapType = 0x008;
+FaultPriority InstructionAccessException::_priority = 5;
+FaultStat InstructionAccessException::_count;
+
+FaultName InstructionAccessMMUMiss::_name = "inst_mmu";
+TrapType InstructionAccessMMUMiss::_trapType = 0x009;
+FaultPriority InstructionAccessMMUMiss::_priority = 2;
+FaultStat InstructionAccessMMUMiss::_count;
+
+FaultName InstructionAccessError::_name = "inst_error";
+TrapType InstructionAccessError::_trapType = 0x00A;
+FaultPriority InstructionAccessError::_priority = 3;
+FaultStat InstructionAccessError::_count;
+
+FaultName IllegalInstruction::_name = "illegal_inst";
+TrapType IllegalInstruction::_trapType = 0x010;
+FaultPriority IllegalInstruction::_priority = 7;
+FaultStat IllegalInstruction::_count;
+
+FaultName PrivilegedOpcode::_name = "priv_opcode";
+TrapType PrivilegedOpcode::_trapType = 0x011;
+FaultPriority PrivilegedOpcode::_priority = 6;
+FaultStat PrivilegedOpcode::_count;
+
+FaultName UnimplementedLDD::_name = "unimp_ldd";
+TrapType UnimplementedLDD::_trapType = 0x012;
+FaultPriority UnimplementedLDD::_priority = 6;
+FaultStat UnimplementedLDD::_count;
+
+FaultName UnimplementedSTD::_name = "unimp_std";
+TrapType UnimplementedSTD::_trapType = 0x013;
+FaultPriority UnimplementedSTD::_priority = 6;
+FaultStat UnimplementedSTD::_count;
+
+FaultName FpDisabled::_name = "fp_disabled";
+TrapType FpDisabled::_trapType = 0x020;
+FaultPriority FpDisabled::_priority = 8;
+FaultStat FpDisabled::_count;
+
+FaultName FpExceptionIEEE754::_name = "fp_754";
+TrapType FpExceptionIEEE754::_trapType = 0x021;
+FaultPriority FpExceptionIEEE754::_priority = 11;
+FaultStat FpExceptionIEEE754::_count;
+
+FaultName FpExceptionOther::_name = "fp_other";
+TrapType FpExceptionOther::_trapType = 0x022;
+FaultPriority FpExceptionOther::_priority = 11;
+FaultStat FpExceptionOther::_count;
+
+FaultName TagOverflow::_name = "tag_overflow";
+TrapType TagOverflow::_trapType = 0x023;
+FaultPriority TagOverflow::_priority = 14;
+FaultStat TagOverflow::_count;
+
+FaultName DivisionByZero::_name = "div_by_zero";
+TrapType DivisionByZero::_trapType = 0x028;
+FaultPriority DivisionByZero::_priority = 15;
+FaultStat DivisionByZero::_count;
+
+FaultName DataAccessException::_name = "data_access";
+TrapType DataAccessException::_trapType = 0x030;
+FaultPriority DataAccessException::_priority = 12;
+FaultStat DataAccessException::_count;
+
+FaultName DataAccessMMUMiss::_name = "data_mmu";
+TrapType DataAccessMMUMiss::_trapType = 0x031;
+FaultPriority DataAccessMMUMiss::_priority = 12;
+FaultStat DataAccessMMUMiss::_count;
+
+FaultName DataAccessError::_name = "data_error";
+TrapType DataAccessError::_trapType = 0x032;
+FaultPriority DataAccessError::_priority = 12;
+FaultStat DataAccessError::_count;
+
+FaultName DataAccessProtection::_name = "data_protection";
+TrapType DataAccessProtection::_trapType = 0x033;
+FaultPriority DataAccessProtection::_priority = 12;
+FaultStat DataAccessProtection::_count;
+
+FaultName LDDFMemAddressNotAligned::_name = "unalign_lddf";
+TrapType LDDFMemAddressNotAligned::_trapType = 0x035;
+FaultPriority LDDFMemAddressNotAligned::_priority = 10;
+FaultStat LDDFMemAddressNotAligned::_count;
+
+FaultName STDFMemAddressNotAligned::_name = "unalign_stdf";
+TrapType STDFMemAddressNotAligned::_trapType = 0x036;
+FaultPriority STDFMemAddressNotAligned::_priority = 10;
+FaultStat STDFMemAddressNotAligned::_count;
+
+FaultName PrivilegedAction::_name = "priv_action";
+TrapType PrivilegedAction::_trapType = 0x037;
+FaultPriority PrivilegedAction::_priority = 11;
+FaultStat PrivilegedAction::_count;
+
+FaultName LDQFMemAddressNotAligned::_name = "unalign_ldqf";
+TrapType LDQFMemAddressNotAligned::_trapType = 0x038;
+FaultPriority LDQFMemAddressNotAligned::_priority = 10;
+FaultStat LDQFMemAddressNotAligned::_count;
+
+FaultName STQFMemAddressNotAligned::_name = "unalign_stqf";
+TrapType STQFMemAddressNotAligned::_trapType = 0x039;
+FaultPriority STQFMemAddressNotAligned::_priority = 10;
+FaultStat STQFMemAddressNotAligned::_count;
+
+FaultName AsyncDataError::_name = "async_data";
+TrapType AsyncDataError::_trapType = 0x040;
+FaultPriority AsyncDataError::_priority = 2;
+FaultStat AsyncDataError::_count;
+
+FaultName CleanWindow::_name = "clean_win";
+TrapType CleanWindow::_trapType = 0x024;
+FaultPriority CleanWindow::_priority = 10;
+FaultStat CleanWindow::_count;
+
+//The enumerated faults
+
+FaultName InterruptLevelN::_name = "interrupt_n";
+TrapType InterruptLevelN::_baseTrapType = 0x041;
+FaultStat InterruptLevelN::_count;
+
+FaultName SpillNNormal::_name = "spill_n_normal";
+TrapType SpillNNormal::_baseTrapType = 0x080;
+FaultPriority SpillNNormal::_priority = 9;
+FaultStat SpillNNormal::_count;
+
+FaultName SpillNOther::_name = "spill_n_other";
+TrapType SpillNOther::_baseTrapType = 0x0A0;
+FaultPriority SpillNOther::_priority = 9;
+FaultStat SpillNOther::_count;
+
+FaultName FillNNormal::_name = "fill_n_normal";
+TrapType FillNNormal::_baseTrapType = 0x0C0;
+FaultPriority FillNNormal::_priority = 9;
+FaultStat FillNNormal::_count;
+
+FaultName FillNOther::_name = "fill_n_other";
+TrapType FillNOther::_baseTrapType = 0x0E0;
+FaultPriority FillNOther::_priority = 9;
+FaultStat FillNOther::_count;
+
+FaultName TrapInstruction::_name = "trap_inst_n";
+TrapType TrapInstruction::_baseTrapType = 0x100;
+FaultPriority TrapInstruction::_priority = 16;
+FaultStat TrapInstruction::_count;
+
+#if FULL_SYSTEM
+
+void SparcFault::invoke(ExecContext * xc)
+{
+ FaultBase::invoke(xc);
+ countStat()++;
+
+ //Use the SPARC trap state machine
+ /*// exception restart address
+ if (setRestartAddress() || !xc->inPalMode())
+ xc->setMiscReg(AlphaISA::IPR_EXC_ADDR, xc->regs.pc);
+
+ if (skipFaultingInstruction()) {
+ // traps... skip faulting instruction.
+ xc->setMiscReg(AlphaISA::IPR_EXC_ADDR,
+ xc->readMiscReg(AlphaISA::IPR_EXC_ADDR) + 4);
+ }
+
+ if (!xc->inPalMode())
+ AlphaISA::swap_palshadow(&(xc->regs), true);
+
+ xc->regs.pc = xc->readMiscReg(AlphaISA::IPR_PAL_BASE) + vect();
+ xc->regs.npc = xc->regs.pc + sizeof(MachInst);*/
+}
+
+#endif
+
+#if !FULL_SYSTEM
+
+void TrapInstruction::invoke(ExecContext * xc)
+{
+ xc->syscall(syscall_num);
+}
+
+#endif
+
+} // namespace SparcISA
+
diff --git a/src/arch/sparc/faults.hh b/src/arch/sparc/faults.hh
new file mode 100644
index 000000000..e8fb8dfc5
--- /dev/null
+++ b/src/arch/sparc/faults.hh
@@ -0,0 +1,591 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ALPHA_FAULTS_HH__
+#define __ALPHA_FAULTS_HH__
+
+#include "sim/faults.hh"
+
+// The design of the "name" and "vect" functions is in sim/faults.hh
+
+namespace SparcISA
+{
+
+typedef const uint32_t TrapType;
+typedef const uint32_t FaultPriority;
+
+class SparcFault : public FaultBase
+{
+ public:
+#if FULL_SYSTEM
+ void invoke(ExecContext * xc);
+#endif
+ virtual TrapType trapType() = 0;
+ virtual FaultPriority priority() = 0;
+ virtual FaultStat & countStat() = 0;
+};
+
+class InternalProcessorError : public SparcFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _trapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ TrapType trapType() {return _trapType;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+ bool isMachineCheckFault() {return true;}
+};
+
+class MemAddressNotAligned : public SparcFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _trapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ TrapType trapType() {return _trapType;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+ bool isAlignmentFault() {return true;}
+};
+
+static inline Fault genMachineCheckFault()
+{
+ return new InternalProcessorError;
+}
+
+static inline Fault genAlignmentFault()
+{
+ return new MemAddressNotAligned;
+}
+
+class PowerOnReset : public SparcFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _trapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ TrapType trapType() {return _trapType;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+};
+
+class WatchDogReset : public SparcFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _trapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ TrapType trapType() {return _trapType;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+};
+
+class ExternallyInitiatedReset : public SparcFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _trapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ TrapType trapType() {return _trapType;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+};
+
+class SoftwareInitiatedReset : public SparcFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _trapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ TrapType trapType() {return _trapType;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+};
+
+class REDStateException : public SparcFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _trapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ TrapType trapType() {return _trapType;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+};
+
+class InstructionAccessException : public SparcFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _trapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ TrapType trapType() {return _trapType;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+};
+
+class InstructionAccessMMUMiss : public SparcFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _trapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ TrapType trapType() {return _trapType;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+};
+
+class InstructionAccessError : public SparcFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _trapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ TrapType trapType() {return _trapType;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+};
+
+class IllegalInstruction : public SparcFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _trapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ TrapType trapType() {return _trapType;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+};
+
+class PrivilegedOpcode : public SparcFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _trapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ TrapType trapType() {return _trapType;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+};
+
+class UnimplementedLDD : public SparcFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _trapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ TrapType trapType() {return _trapType;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+};
+
+class UnimplementedSTD : public SparcFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _trapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ TrapType trapType() {return _trapType;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+};
+
+class FpDisabled : public SparcFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _trapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ TrapType trapType() {return _trapType;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+};
+
+class FpExceptionIEEE754 : public SparcFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _trapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ TrapType trapType() {return _trapType;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+};
+
+class FpExceptionOther : public SparcFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _trapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ TrapType trapType() {return _trapType;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+};
+
+class TagOverflow : public SparcFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _trapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ TrapType trapType() {return _trapType;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+};
+
+class DivisionByZero : public SparcFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _trapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ TrapType trapType() {return _trapType;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+};
+
+class DataAccessException : public SparcFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _trapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ TrapType trapType() {return _trapType;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+};
+
+class DataAccessMMUMiss : public SparcFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _trapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ TrapType trapType() {return _trapType;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+};
+
+class DataAccessError : public SparcFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _trapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ TrapType trapType() {return _trapType;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+};
+
+class DataAccessProtection : public SparcFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _trapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ TrapType trapType() {return _trapType;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+};
+
+class LDDFMemAddressNotAligned : public SparcFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _trapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ TrapType trapType() {return _trapType;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+};
+
+class STDFMemAddressNotAligned : public SparcFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _trapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ TrapType trapType() {return _trapType;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+};
+
+class PrivilegedAction : public SparcFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _trapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ TrapType trapType() {return _trapType;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+};
+
+class LDQFMemAddressNotAligned : public SparcFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _trapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ TrapType trapType() {return _trapType;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+};
+
+class STQFMemAddressNotAligned : public SparcFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _trapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ TrapType trapType() {return _trapType;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+};
+
+class AsyncDataError : public SparcFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _trapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ TrapType trapType() {return _trapType;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+};
+
+class CleanWindow : public SparcFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _trapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ public:
+ FaultName name() {return _name;}
+ TrapType trapType() {return _trapType;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+};
+
+class EnumeratedFault : public SparcFault
+{
+ protected:
+ uint32_t _n;
+ virtual TrapType baseTrapType() = 0;
+ public:
+ EnumeratedFault(uint32_t n) : SparcFault() {_n = n;}
+ TrapType trapType() {return baseTrapType() + _n;}
+};
+
+class InterruptLevelN : public EnumeratedFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _baseTrapType;
+ static FaultStat _count;
+ TrapType baseTrapType() {return _baseTrapType;}
+ public:
+ InterruptLevelN(uint32_t n) : EnumeratedFault(n) {;}
+ FaultName name() {return _name;}
+ FaultPriority priority() {return 32 - _n;}
+ FaultStat & countStat() {return _count;}
+};
+
+class SpillNNormal : public EnumeratedFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _baseTrapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ TrapType baseTrapType() {return _baseTrapType;}
+ public:
+ SpillNNormal(uint32_t n) : EnumeratedFault(n) {;}
+ FaultName name() {return _name;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+};
+
+class SpillNOther : public EnumeratedFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _baseTrapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ TrapType baseTrapType() {return _baseTrapType;}
+ public:
+ SpillNOther(uint32_t n) : EnumeratedFault(n) {;}
+ FaultName name() {return _name;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+};
+
+class FillNNormal : public EnumeratedFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _baseTrapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ TrapType baseTrapType() {return _baseTrapType;}
+ public:
+ FillNNormal(uint32_t n) : EnumeratedFault(n) {;}
+ FaultName name() {return _name;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+};
+
+class FillNOther : public EnumeratedFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _baseTrapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ TrapType baseTrapType() {return _baseTrapType;}
+ public:
+ FillNOther(uint32_t n) : EnumeratedFault(n) {;}
+ FaultName name() {return _name;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+};
+
+class TrapInstruction : public EnumeratedFault
+{
+ private:
+ static FaultName _name;
+ static TrapType _baseTrapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ uint64_t syscall_num;
+ TrapType baseTrapType() {return _baseTrapType;}
+ public:
+ TrapInstruction(uint32_t n, uint64_t syscall) :
+ EnumeratedFault(n), syscall_num(syscall) {;}
+ FaultName name() {return _name;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+#if !FULL_SYSTEM
+ void invoke(ExecContext * xc);
+#endif
+};
+
+} // SparcISA namespace
+
+#endif // __FAULTS_HH__
diff --git a/src/arch/sparc/isa/base.isa b/src/arch/sparc/isa/base.isa
new file mode 100644
index 000000000..02f7cf61a
--- /dev/null
+++ b/src/arch/sparc/isa/base.isa
@@ -0,0 +1,252 @@
+// Copyright (c) 2006 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Ali Saidi
+// Gabe Black
+// Steve Reinhardt
+
+////////////////////////////////////////////////////////////////////
+//
+// Base class for sparc instructions, and some support functions
+//
+
+output header {{
+
+ union CondCodes
+ {
+ struct
+ {
+ uint8_t c:1;
+ uint8_t v:1;
+ uint8_t z:1;
+ uint8_t n:1;
+ };
+ uint32_t bits;
+ };
+
+ enum CondTest
+ {
+ Always=0x8,
+ Never=0x0,
+ NotEqual=0x9,
+ Equal=0x1,
+ Greater=0xA,
+ LessOrEqual=0x2,
+ GreaterOrEqual=0xB,
+ Less=0x3,
+ GreaterUnsigned=0xC,
+ LessOrEqualUnsigned=0x4,
+ CarryClear=0xD,
+ CarrySet=0x5,
+ Positive=0xE,
+ Negative=0x6,
+ OverflowClear=0xF,
+ OverflowSet=0x7
+ };
+
+ extern char * CondTestAbbrev[];
+
+ /**
+ * Base class for all SPARC static instructions.
+ */
+ class SparcStaticInst : public StaticInst
+ {
+ protected:
+ // Constructor.
+ SparcStaticInst(const char *mnem,
+ MachInst _machInst, OpClass __opClass)
+ : StaticInst(mnem, _machInst, __opClass)
+ {
+ }
+
+ std::string generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const;
+
+ void printReg(std::ostream &os, int reg) const;
+ };
+
+ bool passesCondition(uint32_t codes, uint32_t condition);
+
+ inline int64_t sign_ext(uint64_t data, int origWidth)
+ {
+ int shiftAmount = 64 - origWidth;
+ return (((int64_t)data) << shiftAmount) >> shiftAmount;
+ }
+}};
+
+output decoder {{
+
+ char * CondTestAbbrev[] =
+ {
+ "nev", //Never
+ "e", //Equal
+ "le", //Less or Equal
+ "l", //Less
+ "leu", //Less or Equal Unsigned
+ "c", //Carry set
+ "n", //Negative
+ "o", //Overflow set
+ "a", //Always
+ "ne", //Not Equal
+ "g", //Greater
+ "ge", //Greater or Equal
+ "gu", //Greater Unsigned
+ "cc", //Carry clear
+ "p", //Positive
+ "oc" //Overflow Clear
+ };
+}};
+
+def template ROrImmDecode {{
+ {
+ return (I ? (SparcStaticInst *)(new %(class_name)sImm(machInst))
+ : (SparcStaticInst *)(new %(class_name)s(machInst)));
+ }
+}};
+
+let {{
+ def splitOutImm(code):
+ matcher = re.compile(r'Rs(?P<rNum>\d)_or_imm(?P<iNum>\d+)(?P<typeQual>\.\w+)?')
+ rOrImmMatch = matcher.search(code)
+ if (rOrImmMatch == None):
+ return (False, code, '', '', '')
+ rString = rOrImmMatch.group("rNum")
+ if (rOrImmMatch.group("typeQual") != None):
+ rString += rOrImmMatch.group("typeQual")
+ iString = rOrImmMatch.group("iNum")
+ orig_code = code
+ code = matcher.sub('Rs' + rString, orig_code)
+ imm_code = matcher.sub('imm', orig_code)
+ return (True, code, imm_code, rString, iString)
+}};
+
+output decoder {{
+
+ inline void printMnemonic(std::ostream &os, const char * mnemonic)
+ {
+ ccprintf(os, "\t%s ", mnemonic);
+ }
+
+ void
+ SparcStaticInst::printReg(std::ostream &os, int reg) const
+ {
+ const int MaxGlobal = 8;
+ const int MaxOutput = 16;
+ const int MaxLocal = 24;
+ const int MaxInput = 32;
+ if (reg == FramePointerReg)
+ ccprintf(os, "%%fp");
+ else if (reg == StackPointerReg)
+ ccprintf(os, "%%sp");
+ else if(reg < MaxGlobal)
+ ccprintf(os, "%%g%d", reg);
+ else if(reg < MaxOutput)
+ ccprintf(os, "%%o%d", reg - MaxGlobal);
+ else if(reg < MaxLocal)
+ ccprintf(os, "%%l%d", reg - MaxOutput);
+ else if(reg < MaxInput)
+ ccprintf(os, "%%i%d", reg - MaxLocal);
+ else {
+ ccprintf(os, "%%f%d", reg - FP_Base_DepTag);
+ }
+ }
+
+ std::string SparcStaticInst::generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+ {
+ std::stringstream ss;
+
+ printMnemonic(ss, mnemonic);
+
+ // just print the first two source regs... if there's
+ // a third one, it's a read-modify-write dest (Rc),
+ // e.g. for CMOVxx
+ if(_numSrcRegs > 0)
+ {
+ printReg(ss, _srcRegIdx[0]);
+ }
+ if(_numSrcRegs > 1)
+ {
+ ss << ",";
+ printReg(ss, _srcRegIdx[1]);
+ }
+
+ // just print the first dest... if there's a second one,
+ // it's generally implicit
+ if(_numDestRegs > 0)
+ {
+ if(_numSrcRegs > 0)
+ ss << ",";
+ printReg(ss, _destRegIdx[0]);
+ }
+
+ return ss.str();
+ }
+
+ bool passesCondition(uint32_t codes, uint32_t condition)
+ {
+ CondCodes condCodes;
+ condCodes.bits = codes;
+ switch(condition)
+ {
+ case Always:
+ return true;
+ case Never:
+ return false;
+ case NotEqual:
+ return !condCodes.z;
+ case Equal:
+ return condCodes.z;
+ case Greater:
+ return !(condCodes.z | (condCodes.n ^ condCodes.v));
+ case LessOrEqual:
+ return condCodes.z | (condCodes.n ^ condCodes.v);
+ case GreaterOrEqual:
+ return !(condCodes.n ^ condCodes.v);
+ case Less:
+ return (condCodes.n ^ condCodes.v);
+ case GreaterUnsigned:
+ return !(condCodes.c | condCodes.z);
+ case LessOrEqualUnsigned:
+ return (condCodes.c | condCodes.z);
+ case CarryClear:
+ return !condCodes.c;
+ case CarrySet:
+ return condCodes.c;
+ case Positive:
+ return !condCodes.n;
+ case Negative:
+ return condCodes.n;
+ case OverflowClear:
+ return !condCodes.v;
+ case OverflowSet:
+ return condCodes.v;
+ }
+ panic("Tried testing condition nonexistant "
+ "condition code %d", condition);
+ }
+}};
+
diff --git a/src/arch/sparc/isa/bitfields.isa b/src/arch/sparc/isa/bitfields.isa
new file mode 100644
index 000000000..27f52fa29
--- /dev/null
+++ b/src/arch/sparc/isa/bitfields.isa
@@ -0,0 +1,78 @@
+// Copyright (c) 2006 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Ali Saidi
+// Gabe Black
+// Steve Reinhardt
+
+////////////////////////////////////////////////////////////////////
+//
+// Bitfield definitions.
+//
+
+// Bitfields are shared liberally between instruction formats, so they are
+// simply defined alphabetically
+
+def bitfield A <29>;
+def bitfield BPCC <21:20>; // for BPcc & FBPcc
+def bitfield FCMPCC <26:56>; // for FCMP & FCMPEa
+def bitfield FMOVCC <13:11>; // for FMOVcc
+def bitfield CC <12:11>; // for MOVcc & Tcc
+def bitfield MOVCC3 <18>; // also for MOVcc
+def bitfield CMASK <6:4>;
+def bitfield COND2 <28:25>;
+def bitfield COND4 <17:14>;
+def bitfield D16HI <21:20>;
+def bitfield D16LO <13:0>;
+def bitfield DISP19 <18:0>;
+def bitfield DISP22 <21:0>;
+def bitfield DISP30 <29:0>;
+def bitfield FCN <29:26>;
+def bitfield I <13>;
+def bitfield IMM_ASI <12:5>;
+def bitfield IMM22 <21:0>;
+def bitfield MMASK <3:0>;
+def bitfield OP <31:30>;
+def bitfield OP2 <24:22>;
+def bitfield OP3 <24:19>;
+def bitfield OPF <13:5>;
+def bitfield OPF_CC <13:11>;
+def bitfield OPF_LOW5 <9:5>;
+def bitfield OPF_LOW6 <10:5>;
+def bitfield P <19>;
+def bitfield RCOND2 <27:25>;
+def bitfield RCOND3 <12:10>;
+def bitfield RCOND4 <12:10>;
+def bitfield RD <29:25>;
+def bitfield RS1 <18:14>;
+def bitfield RS2 <4:0>;
+def bitfield SHCNT32 <4:0>;
+def bitfield SHCNT64 <5:0>;
+def bitfield SIMM10 <9:0>;
+def bitfield SIMM11 <10:0>;
+def bitfield SIMM13 <12:0>;
+def bitfield SW_TRAP <7:0>;
+def bitfield X <12>;
diff --git a/src/arch/sparc/isa/decoder.isa b/src/arch/sparc/isa/decoder.isa
new file mode 100644
index 000000000..c6e05bf6f
--- /dev/null
+++ b/src/arch/sparc/isa/decoder.isa
@@ -0,0 +1,721 @@
+// Copyright (c) 2006 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Ali Saidi
+// Gabe Black
+// Steve Reinhardt
+
+////////////////////////////////////////////////////////////////////
+//
+// The actual decoder specification
+//
+
+decode OP default Unknown::unknown()
+{
+ 0x0: decode OP2
+ {
+ //Throw an illegal instruction acception
+ 0x0: Trap::illtrap({{fault = new IllegalInstruction;}});
+ 0x1: decode BPCC
+ {
+ format Branch19
+ {
+ 0x0: bpcci({{
+ if(passesCondition(CcrIcc, COND2))
+ NNPC = xc->readPC() + disp;
+ else
+ handle_annul
+ }});
+ 0x2: bpccx({{
+ if(passesCondition(CcrXcc, COND2))
+ NNPC = xc->readPC() + disp;
+ else
+ handle_annul
+ }});
+ }
+ }
+ 0x2: Branch22::bicc({{
+ if(passesCondition(CcrIcc, COND2))
+ NNPC = xc->readPC() + disp;
+ else
+ handle_annul
+ }});
+ 0x3: decode RCOND2
+ {
+ format BranchSplit
+ {
+ 0x1: bpreq({{
+ if(Rs1.sdw == 0)
+ NNPC = xc->readPC() + disp;
+ else
+ handle_annul
+ }});
+ 0x2: bprle({{
+ if(Rs1.sdw <= 0)
+ NNPC = xc->readPC() + disp;
+ else
+ handle_annul
+ }});
+ 0x3: bprl({{
+ if(Rs1.sdw < 0)
+ NNPC = xc->readPC() + disp;
+ else
+ handle_annul
+ }});
+ 0x5: bprne({{
+ if(Rs1.sdw != 0)
+ NNPC = xc->readPC() + disp;
+ else
+ handle_annul
+ }});
+ 0x6: bprg({{
+ if(Rs1.sdw > 0)
+ NNPC = xc->readPC() + disp;
+ else
+ handle_annul
+ }});
+ 0x7: bprge({{
+ if(Rs1.sdw >= 0)
+ NNPC = xc->readPC() + disp;
+ else
+ handle_annul
+ }});
+ }
+ }
+ //SETHI (or NOP if rd == 0 and imm == 0)
+ 0x4: SetHi::sethi({{Rd = imm;}});
+ 0x5: Trap::fbpfcc({{fault = new FpDisabled;}});
+ 0x6: Trap::fbfcc({{fault = new FpDisabled;}});
+ }
+ 0x1: Branch30::call({{
+ R15 = xc->readPC();
+ NNPC = R15 + disp;
+ }});
+ 0x2: decode OP3 {
+ format IntOp {
+ 0x00: add({{Rd = Rs1.sdw + Rs2_or_imm13;}});
+ 0x01: and({{Rd = Rs1.udw & Rs2_or_imm13;}});
+ 0x02: or({{Rd = Rs1.udw | Rs2_or_imm13;}});
+ 0x03: xor({{Rd = Rs1.udw ^ Rs2_or_imm13;}});
+ 0x04: sub({{Rd = Rs1.sdw - Rs2_or_imm13;}});
+ 0x05: andn({{Rd = Rs1.udw & ~Rs2_or_imm13;}});
+ 0x06: orn({{Rd = Rs1.udw | ~Rs2_or_imm13;}});
+ 0x07: xnor({{Rd = ~(Rs1.udw ^ Rs2_or_imm13);}});
+ 0x08: addc({{Rd = Rs1.sdw + Rs2_or_imm13 + CcrIccC;}});
+ 0x09: mulx({{Rd = Rs1 * Rs2_or_imm13;}});
+ 0x0A: umul({{
+ Rd = Rs1.udw<31:0> * Rs2_or_imm13<31:0>;
+ YValue = Rd<63:32>;
+ }});
+ 0x0B: smul({{
+ Rd.sdw = Rs1.sdw<31:0> * Rs2_or_imm13<31:0>;
+ YValue = Rd.sdw;
+ }});
+ 0x0C: subc({{Rd.sdw = Rs1.sdw + (~Rs2_or_imm13) + 1 + CcrIccC;}});
+ 0x0D: udivx({{
+ if(Rs2_or_imm13 == 0) fault = new DivisionByZero;
+ else Rd.udw = Rs1.udw / Rs2_or_imm13;
+ }});
+ 0x0E: udiv({{
+ if(Rs2_or_imm13 == 0) fault = new DivisionByZero;
+ else
+ {
+ Rd.udw = ((YValue << 32) | Rs1.udw<31:0>) / Rs2_or_imm13;
+ if(Rd.udw >> 32 != 0)
+ Rd.udw = 0xFFFFFFFF;
+ }
+ }});
+ 0x0F: sdiv({{
+ if(Rs2_or_imm13.sdw == 0)
+ fault = new DivisionByZero;
+ else
+ {
+ Rd.udw = ((int64_t)((YValue << 32) | Rs1.sdw<31:0>)) / Rs2_or_imm13.sdw;
+ if(Rd.udw<63:31> != 0)
+ Rd.udw = 0x7FFFFFFF;
+ else if(Rd.udw<63:> && Rd.udw<62:31> != 0xFFFFFFFF)
+ Rd.udw = 0xFFFFFFFF80000000ULL;
+ }
+ }});
+ }
+ format IntOpCc {
+ 0x10: addcc({{
+ int64_t resTemp, val2 = Rs2_or_imm13;
+ Rd = resTemp = Rs1 + val2;}},
+ {{(Rs1<31:0> + val2<31:0>)<32:>}},
+ {{Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>}},
+ {{(Rs1<63:1> + val2<63:1> + (Rs1 & val2)<0:>)<63:>}},
+ {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}}
+ );
+ 0x11: IntOpCcRes::andcc({{Rd = Rs1 & Rs2_or_imm13;}});
+ 0x12: IntOpCcRes::orcc({{Rd = Rs1 | Rs2_or_imm13;}});
+ 0x13: IntOpCcRes::xorcc({{Rd = Rs1 ^ Rs2_or_imm13;}});
+ 0x14: subcc({{
+ int64_t val2 = Rs2_or_imm13;
+ Rd = Rs1 - val2;}},
+ {{(~(Rs1<31:0> + (~val2)<31:0> + 1))<32:>}},
+ {{(Rs1<31:> != val2<31:>) && (Rs1<31:> != Rd<31:>)}},
+ {{(~(Rs1<63:1> + (~val2)<63:1> +
+ (Rs1 | ~val2)<0:>))<63:>}},
+ {{Rs1<63:> != val2<63:> && Rs1<63:> != Rd<63:>}}
+ );
+ 0x15: IntOpCcRes::andncc({{Rd = Rs1 & ~Rs2_or_imm13;}});
+ 0x16: IntOpCcRes::orncc({{Rd = Rs1 | ~Rs2_or_imm13;}});
+ 0x17: IntOpCcRes::xnorcc({{Rd = ~(Rs1 ^ Rs2_or_imm13);}});
+ 0x18: addccc({{
+ int64_t resTemp, val2 = Rs2_or_imm13;
+ int64_t carryin = CcrIccC;
+ Rd = resTemp = Rs1 + val2 + carryin;}},
+ {{(Rs1<31:0> + val2<31:0> + carryin)<32:>}},
+ {{Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>}},
+ {{(Rs1<63:1> + val2<63:1> +
+ ((Rs1 & val2) | (carryin & (Rs1 | val2)))<0:>)<63:>}},
+ {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}}
+ );
+ 0x1A: umulcc({{
+ uint64_t resTemp;
+ Rd = resTemp = Rs1.udw<31:0> * Rs2_or_imm13.udw<31:0>;
+ YValue = resTemp<63:32>;}},
+ {{0}},{{0}},{{0}},{{0}});
+ 0x1B: smulcc({{
+ int64_t resTemp;
+ Rd = resTemp = Rs1.sdw<31:0> * Rs2_or_imm13.sdw<31:0>;
+ YValue = resTemp<63:32>;}},
+ {{0}},{{0}},{{0}},{{0}});
+ 0x1C: subccc({{
+ int64_t resTemp, val2 = Rs2_or_imm13;
+ int64_t carryin = CcrIccC;
+ Rd = resTemp = Rs1 + ~(val2 + carryin) + 1;}},
+ {{(~((Rs1<31:0> + (~(val2 + carryin))<31:0> + 1))<32:>)}},
+ {{Rs1<31:> != val2<31:> && Rs1<31:> != resTemp<31:>}},
+ {{(~((Rs1<63:1> + (~(val2 + carryin))<63:1>) + (Rs1<0:> + (~(val2+carryin))<0:> + 1)<63:1>))<63:>}},
+ {{Rs1<63:> != val2<63:> && Rs1<63:> != resTemp<63:>}}
+ );
+ 0x1D: udivxcc({{
+ if(Rs2_or_imm13.udw == 0) fault = new DivisionByZero;
+ else Rd = Rs1.udw / Rs2_or_imm13.udw;}}
+ ,{{0}},{{0}},{{0}},{{0}});
+ 0x1E: udivcc({{
+ uint32_t resTemp, val2 = Rs2_or_imm13.udw;
+ int32_t overflow;
+ if(val2 == 0) fault = new DivisionByZero;
+ else
+ {
+ resTemp = (uint64_t)((YValue << 32) | Rs1.udw<31:0>) / val2;
+ overflow = (resTemp<63:32> != 0);
+ if(overflow) Rd = resTemp = 0xFFFFFFFF;
+ else Rd = resTemp;
+ } }},
+ {{0}},
+ {{overflow}},
+ {{0}},
+ {{0}}
+ );
+ 0x1F: sdivcc({{
+ int32_t resTemp, val2 = Rs2_or_imm13.sdw;
+ int32_t overflow, underflow;
+ if(val2 == 0) fault = new DivisionByZero;
+ else
+ {
+ Rd = resTemp = (int64_t)((YValue << 32) | Rs1.sdw<31:0>) / val2;
+ overflow = (resTemp<63:31> != 0);
+ underflow = (resTemp<63:> && resTemp<62:31> != 0xFFFFFFFF);
+ if(overflow) Rd = resTemp = 0x7FFFFFFF;
+ else if(underflow) Rd = resTemp = 0xFFFFFFFF80000000ULL;
+ else Rd = resTemp;
+ } }},
+ {{0}},
+ {{overflow || underflow}},
+ {{0}},
+ {{0}}
+ );
+ 0x20: taddcc({{
+ int64_t resTemp, val2 = Rs2_or_imm13;
+ Rd = resTemp = Rs1 + val2;
+ int32_t overflow = Rs1<1:0> || val2<1:0> || (Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>);}},
+ {{((Rs1 & 0xFFFFFFFF + val2 & 0xFFFFFFFF) >> 31)}},
+ {{overflow}},
+ {{((Rs1 >> 1) + (val2 >> 1) + (Rs1 & val2 & 0x1))<63:>}},
+ {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}}
+ );
+ 0x21: tsubcc({{
+ int64_t resTemp, val2 = Rs2_or_imm13;
+ Rd = resTemp = Rs1 + val2;
+ int32_t overflow = Rs1<1:0> || val2<1:0> || (Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>);}},
+ {{(Rs1 & 0xFFFFFFFF + val2 & 0xFFFFFFFF) >> 31}},
+ {{overflow}},
+ {{((Rs1 >> 1) + (val2 >> 1) + (Rs1 & val2 & 0x1))<63:>}},
+ {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}}
+ );
+ 0x22: taddcctv({{
+ int64_t resTemp, val2 = Rs2_or_imm13;
+ Rd = resTemp = Rs1 + val2;
+ int32_t overflow = Rs1<1:0> || val2<1:0> || (Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>);
+ if(overflow) fault = new TagOverflow;}},
+ {{((Rs1 & 0xFFFFFFFF + val2 & 0xFFFFFFFF) >> 31)}},
+ {{overflow}},
+ {{((Rs1 >> 1) + (val2 >> 1) + (Rs1 & val2 & 0x1))<63:>}},
+ {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}}
+ );
+ 0x23: tsubcctv({{
+ int64_t resTemp, val2 = Rs2_or_imm13;
+ Rd = resTemp = Rs1 + val2;
+ int32_t overflow = Rs1<1:0> || val2<1:0> || (Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>);
+ if(overflow) fault = new TagOverflow;}},
+ {{((Rs1 & 0xFFFFFFFF + val2 & 0xFFFFFFFF) >> 31)}},
+ {{overflow}},
+ {{((Rs1 >> 1) + (val2 >> 1) + (Rs1 & val2 & 0x1))<63:>}},
+ {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}}
+ );
+ 0x24: mulscc({{
+ int64_t resTemp, multiplicand = Rs2_or_imm13;
+ int32_t multiplier = Rs1<31:0>;
+ int32_t savedLSB = Rs1<0:>;
+ multiplier = multiplier<31:1> |
+ ((CcrIccN
+ ^ CcrIccV) << 32);
+ if(!YValue<0:>)
+ multiplicand = 0;
+ Rd = resTemp = multiplicand + multiplier;
+ YValue = YValue<31:1> | (savedLSB << 31);}},
+ {{((multiplicand & 0xFFFFFFFF + multiplier & 0xFFFFFFFF) >> 31)}},
+ {{multiplicand<31:> == multiplier<31:> && multiplier<31:> != resTemp<31:>}},
+ {{((multiplicand >> 1) + (multiplier >> 1) + (multiplicand & multiplier & 0x1))<63:>}},
+ {{multiplicand<63:> == multiplier<63:> && multiplier<63:> != resTemp<63:>}}
+ );
+ }
+ format IntOp
+ {
+ 0x25: decode X {
+ 0x0: sll({{Rd = Rs1 << (I ? SHCNT32 : Rs2<4:0>);}});
+ 0x1: sllx({{Rd = Rs1 << (I ? SHCNT64 : Rs2<5:0>);}});
+ }
+ 0x26: decode X {
+ 0x0: srl({{Rd = Rs1.uw >> (I ? SHCNT32 : Rs2<4:0>);}});
+ 0x1: srlx({{Rd = Rs1.udw >> (I ? SHCNT64 : Rs2<5:0>);}});
+ }
+ 0x27: decode X {
+ 0x0: sra({{Rd = Rs1.sw >> (I ? SHCNT32 : Rs2<4:0>);}});
+ 0x1: srax({{Rd = Rs1.sdw >> (I ? SHCNT64 : Rs2<5:0>);}});
+ }
+ 0x28: decode RS1 {
+ 0x0: rdy({{Rd = YValue;}});
+ 0x2: rdccr({{Rd = Ccr;}});
+ 0x3: rdasi({{Rd = Asi;}});
+ 0x4: PrivTick::rdtick({{Rd = Tick;}});
+ 0x5: rdpc({{Rd = xc->readPC();}});
+ 0x6: rdfprs({{Rd = Fprs;}});
+ 0xF: decode I {
+ 0x0: Nop::membar({{/*Membar isn't needed yet*/}});
+ 0x1: Nop::stbar({{/*Stbar isn't needed yet*/}});
+ }
+ }
+ 0x2A: decode RS1 {
+ format Priv
+ {
+ 0x0: rdprtpc({{
+ Rd = xc->readMiscReg(MISCREG_TPC_BASE + Tl);
+ }});
+ 0x1: rdprtnpc({{
+ Rd = xc->readMiscReg(MISCREG_TNPC_BASE + Tl);
+ }});
+ 0x2: rdprtstate({{
+ Rd = xc->readMiscReg(MISCREG_TSTATE_BASE + Tl);
+ }});
+ 0x3: rdprtt({{
+ Rd = xc->readMiscReg(MISCREG_TT_BASE + Tl);
+ }});
+ 0x4: rdprtick({{Rd = Tick;}});
+ 0x5: rdprtba({{Rd = Tba;}});
+ 0x6: rdprpstate({{Rd = Pstate;}});
+ 0x7: rdprtl({{Rd = Tl;}});
+ 0x8: rdprpil({{Rd = Pil;}});
+ 0x9: rdprcwp({{Rd = Cwp;}});
+ 0xA: rdprcansave({{Rd = Cansave;}});
+ 0xB: rdprcanrestore({{Rd = Canrestore;}});
+ 0xC: rdprcleanwin({{Rd = Cleanwin;}});
+ 0xD: rdprotherwin({{Rd = Otherwin;}});
+ 0xE: rdprwstate({{Rd = Wstate;}});
+ }
+ //The floating point queue isn't implemented right now.
+ 0xF: Trap::rdprfq({{fault = new IllegalInstruction;}});
+ 0x1F: Priv::rdprver({{Rd = Ver;}});
+ }
+ 0x2B: BasicOperate::flushw({{
+ if(NWindows - 2 - Cansave == 0)
+ {
+ if(Otherwin)
+ fault = new SpillNOther(WstateOther);
+ else
+ fault = new SpillNNormal(WstateNormal);
+ }
+ }});
+ 0x2C: decode MOVCC3
+ {
+ 0x0: Trap::movccfcc({{fault = new FpDisabled;}});
+ 0x1: decode CC
+ {
+ 0x0: movcci({{
+ if(passesCondition(CcrIcc, COND4))
+ Rd = Rs2_or_imm11;
+ else
+ Rd = Rd;
+ }});
+ 0x2: movccx({{
+ if(passesCondition(CcrXcc, COND4))
+ Rd = Rs2_or_imm11;
+ else
+ Rd = Rd;
+ }});
+ }
+ }
+ 0x2D: sdivx({{
+ if(Rs2_or_imm13.sdw == 0) fault = new DivisionByZero;
+ else Rd.sdw = Rs1.sdw / Rs2_or_imm13.sdw;
+ }});
+ 0x2E: decode RS1 {
+ 0x0: IntOp::popc({{
+ int64_t count = 0;
+ uint64_t temp = Rs2_or_imm13;
+ //Count the 1s in the front 4bits until none are left
+ uint8_t oneBits[] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4};
+ while(temp)
+ {
+ count += oneBits[temp & 0xF];
+ temp = temp >> 4;
+ }
+ Rd = count;
+ }});
+ }
+ 0x2F: decode RCOND3
+ {
+ 0x1: movreq({{Rd = (Rs1.sdw == 0) ? Rs2_or_imm10 : Rd;}});
+ 0x2: movrle({{Rd = (Rs1.sdw <= 0) ? Rs2_or_imm10 : Rd;}});
+ 0x3: movrl({{Rd = (Rs1.sdw < 0) ? Rs2_or_imm10 : Rd;}});
+ 0x5: movrne({{Rd = (Rs1.sdw != 0) ? Rs2_or_imm10 : Rd;}});
+ 0x6: movrg({{Rd = (Rs1.sdw > 0) ? Rs2_or_imm10 : Rd;}});
+ 0x7: movrge({{Rd = (Rs1.sdw >= 0) ? Rs2_or_imm10 : Rd;}});
+ }
+ 0x30: decode RD {
+ 0x0: wry({{Y = Rs1 ^ Rs2_or_imm13;}});
+ 0x2: wrccr({{Ccr = Rs1 ^ Rs2_or_imm13;}});
+ 0x3: wrasi({{Asi = Rs1 ^ Rs2_or_imm13;}});
+ 0x6: wrfprs({{Asi = Rs1 ^ Rs2_or_imm13;}});
+ 0xF: Trap::sir({{fault = new SoftwareInitiatedReset;}});
+ }
+ 0x31: decode FCN {
+ 0x0: BasicOperate::saved({{/*Boogy Boogy*/}});
+ 0x1: BasicOperate::restored({{/*Boogy Boogy*/}});
+ }
+ 0x32: decode RD {
+ format Priv
+ {
+ 0x0: wrprtpc({{
+ xc->setMiscReg(MISCREG_TPC_BASE + Tl,
+ Rs1 ^ Rs2_or_imm13);
+ }});
+ 0x1: wrprtnpc({{
+ xc->setMiscReg(MISCREG_TNPC_BASE + Tl,
+ Rs1 ^ Rs2_or_imm13);
+ }});
+ 0x2: wrprtstate({{
+ xc->setMiscReg(MISCREG_TSTATE_BASE + Tl,
+ Rs1 ^ Rs2_or_imm13);
+ }});
+ 0x3: wrprtt({{
+ xc->setMiscReg(MISCREG_TT_BASE + Tl,
+ Rs1 ^ Rs2_or_imm13);
+ }});
+ 0x4: wrprtick({{Tick = Rs1 ^ Rs2_or_imm13;}});
+ 0x5: wrprtba({{Tba = Rs1 ^ Rs2_or_imm13;}});
+ 0x6: wrprpstate({{Pstate = Rs1 ^ Rs2_or_imm13;}});
+ 0x7: wrprtl({{Tl = Rs1 ^ Rs2_or_imm13;}});
+ 0x8: wrprpil({{Pil = Rs1 ^ Rs2_or_imm13;}});
+ 0x9: wrprcwp({{Cwp = Rs1 ^ Rs2_or_imm13;}});
+ 0xA: wrprcansave({{Cansave = Rs1 ^ Rs2_or_imm13;}});
+ 0xB: wrprcanrestore({{Canrestore = Rs1 ^ Rs2_or_imm13;}});
+ 0xC: wrprcleanwin({{Cleanwin = Rs1 ^ Rs2_or_imm13;}});
+ 0xD: wrprotherwin({{Otherwin = Rs1 ^ Rs2_or_imm13;}});
+ 0xE: wrprwstate({{Wstate = Rs1 ^ Rs2_or_imm13;}});
+ }
+ }
+ 0x34: Trap::fpop1({{fault = new FpDisabled;}});
+ 0x35: Trap::fpop2({{fault = new FpDisabled;}});
+ 0x38: Branch::jmpl({{
+ Addr target = Rs1 + Rs2_or_imm13;
+ if(target & 0x3)
+ fault = new MemAddressNotAligned;
+ else
+ {
+ Rd = xc->readPC();
+ NNPC = target;
+ }
+ }});
+ 0x39: Branch::return({{
+ //If both MemAddressNotAligned and
+ //a fill trap happen, it's not clear
+ //which one should be returned.
+ Addr target = Rs1 + Rs2_or_imm13;
+ if(target & 0x3)
+ fault = new MemAddressNotAligned;
+ else
+ NNPC = target;
+ if(fault == NoFault)
+ {
+ //CWP should be set directly so that it always happens
+ //Also, this will allow writing to the new window and
+ //reading from the old one
+ Cwp = (Cwp - 1 + NWindows) % NWindows;
+ if(Canrestore == 0)
+ {
+ if(Otherwin)
+ fault = new FillNOther(WstateOther);
+ else
+ fault = new FillNNormal(WstateNormal);
+ }
+ else
+ {
+ Rd = Rs1 + Rs2_or_imm13;
+ Cansave = Cansave + 1;
+ Canrestore = Canrestore - 1;
+ }
+ //This is here to make sure the CWP is written
+ //no matter what. This ensures that the results
+ //are written in the new window as well.
+ xc->setMiscRegWithEffect(MISCREG_CWP, Cwp);
+ }
+ }});
+ 0x3A: decode CC
+ {
+ 0x0: Trap::tcci({{
+ if(passesCondition(CcrIcc, COND2))
+ {
+ int lTrapNum = I ? (Rs1 + SW_TRAP) : (Rs1 + Rs2);
+ DPRINTF(Sparc, "The trap number is %d\n", lTrapNum);
+#if FULL_SYSTEM
+ fault = new TrapInstruction(lTrapNum);
+#else
+ DPRINTF(Sparc, "The syscall number is %d\n", R1);
+ xc->syscall(R1);
+#endif
+ }
+ }});
+ 0x2: Trap::tccx({{
+ if(passesCondition(CcrXcc, COND2))
+ {
+ int lTrapNum = I ? (Rs1 + SW_TRAP) : (Rs1 + Rs2);
+ DPRINTF(Sparc, "The trap number is %d\n", lTrapNum);
+#if FULL_SYSTEM
+ fault = new TrapInstruction(lTrapNum);
+#else
+ DPRINTF(Sparc, "The syscall number is %d\n", R1);
+ xc->syscall(R1);
+#endif
+ }
+ }});
+ }
+ 0x3B: Nop::flush({{/*Instruction memory flush*/}});
+ 0x3C: save({{
+ //CWP should be set directly so that it always happens
+ //Also, this will allow writing to the new window and
+ //reading from the old one
+ if(Cansave == 0)
+ {
+ if(Otherwin)
+ fault = new SpillNOther(WstateOther);
+ else
+ fault = new SpillNNormal(WstateNormal);
+ Cwp = (Cwp + 2) % NWindows;
+ }
+ else if(Cleanwin - Canrestore == 0)
+ {
+ Cwp = (Cwp + 1) % NWindows;
+ fault = new CleanWindow;
+ }
+ else
+ {
+ Cwp = (Cwp + 1) % NWindows;
+ Rd = Rs1 + Rs2_or_imm13;
+ Cansave = Cansave - 1;
+ Canrestore = Canrestore + 1;
+ }
+ //This is here to make sure the CWP is written
+ //no matter what. This ensures that the results
+ //are written in the new window as well.
+ xc->setMiscRegWithEffect(MISCREG_CWP, Cwp);
+ }});
+ 0x3D: restore({{
+ //CWP should be set directly so that it always happens
+ //Also, this will allow writing to the new window and
+ //reading from the old one
+ Cwp = (Cwp - 1 + NWindows) % NWindows;
+ if(Canrestore == 0)
+ {
+ if(Otherwin)
+ fault = new FillNOther(WstateOther);
+ else
+ fault = new FillNNormal(WstateNormal);
+ }
+ else
+ {
+ Rd = Rs1 + Rs2_or_imm13;
+ Cansave = Cansave + 1;
+ Canrestore = Canrestore - 1;
+ }
+ //This is here to make sure the CWP is written
+ //no matter what. This ensures that the results
+ //are written in the new window as well.
+ xc->setMiscRegWithEffect(MISCREG_CWP, Cwp);
+ }});
+ 0x3E: decode FCN {
+ 0x0: Priv::done({{
+ if(Tl == 0)
+ return new IllegalInstruction;
+ Cwp = xc->readMiscReg(MISCREG_TSTATE_CWP_BASE + Tl);
+ Asi = xc->readMiscReg(MISCREG_TSTATE_ASI_BASE + Tl);
+ Ccr = xc->readMiscReg(MISCREG_TSTATE_CCR_BASE + Tl);
+ Pstate = xc->readMiscReg(MISCREG_TSTATE_PSTATE_BASE + Tl);
+ NPC = xc->readMiscReg(MISCREG_TNPC_BASE + Tl);
+ NNPC = NPC + 4;
+ Tl = Tl - 1;
+ }});
+ 0x1: BasicOperate::retry({{
+ if(Tl == 0)
+ return new IllegalInstruction;
+ Cwp = xc->readMiscReg(MISCREG_TSTATE_CWP_BASE + Tl);
+ Asi = xc->readMiscReg(MISCREG_TSTATE_ASI_BASE + Tl);
+ Ccr = xc->readMiscReg(MISCREG_TSTATE_CCR_BASE + Tl);
+ Pstate = xc->readMiscReg(MISCREG_TSTATE_PSTATE_BASE + Tl);
+ NPC = xc->readMiscReg(MISCREG_TPC_BASE + Tl);
+ NNPC = xc->readMiscReg(MISCREG_TNPC_BASE + Tl);
+ Tl = Tl - 1;
+ }});
+ }
+ }
+ }
+ 0x3: decode OP3 {
+ format Load {
+ 0x00: lduw({{Rd = Mem;}}, {{32}});
+ 0x01: ldub({{Rd = Mem;}}, {{8}});
+ 0x02: lduh({{Rd = Mem;}}, {{16}});
+ 0x03: ldd({{
+ uint64_t val = Mem;
+ RdLow = val<31:0>;
+ RdHigh = val<63:32>;
+ }}, {{64}});
+ }
+ format Store {
+ 0x04: stw({{Mem = Rd.sw;}}, {{32}});
+ 0x05: stb({{Mem = Rd.sb;}}, {{8}});
+ 0x06: sth({{Mem = Rd.shw;}}, {{16}});
+ 0x07: std({{Mem = RdLow<31:0> | RdHigh<31:0> << 32;}}, {{64}});
+ }
+ format Load {
+ 0x08: ldsw({{Rd = (int32_t)Mem;}}, {{32}});
+ 0x09: ldsb({{Rd = (int8_t)Mem;}}, {{8}});
+ 0x0A: ldsh({{Rd = (int16_t)Mem;}}, {{16}});
+ 0x0B: ldx({{Rd = (int64_t)Mem;}}, {{64}});
+ 0x0D: ldstub({{
+ Rd = Mem;
+ Mem = 0xFF;
+ }}, {{8}});
+ }
+ 0x0E: Store::stx({{Mem = Rd}}, {{64}});
+ 0x0F: LoadStore::swap({{
+ uint32_t temp = Rd;
+ Rd = Mem;
+ Mem = temp;
+ }}, {{32}});
+ format Load {
+ 0x10: lduwa({{Rd = Mem;}}, {{32}});
+ 0x11: lduba({{Rd = Mem;}}, {{8}});
+ 0x12: lduha({{Rd = Mem;}}, {{16}});
+ 0x13: ldda({{
+ uint64_t val = Mem;
+ RdLow = val<31:0>;
+ RdHigh = val<63:32>;
+ }}, {{64}});
+ }
+ format Store {
+ 0x14: stwa({{Mem = Rd;}}, {{32}});
+ 0x15: stba({{Mem = Rd;}}, {{8}});
+ 0x16: stha({{Mem = Rd;}}, {{16}});
+ 0x17: stda({{Mem = RdLow<31:0> | RdHigh<31:0> << 32;}}, {{64}});
+ }
+ format Load {
+ 0x18: ldswa({{Rd = (int32_t)Mem;}}, {{32}});
+ 0x19: ldsba({{Rd = (int8_t)Mem;}}, {{8}});
+ 0x1A: ldsha({{Rd = (int16_t)Mem;}}, {{16}});
+ 0x1B: ldxa({{Rd = (int64_t)Mem;}}, {{64}});
+ }
+ 0x1D: LoadStore::ldstuba({{
+ Rd = Mem;
+ Mem = 0xFF;
+ }}, {{8}});
+ 0x1E: Store::stxa({{Mem = Rd}}, {{64}});
+ 0x1F: LoadStore::swapa({{
+ uint32_t temp = Rd;
+ Rd = Mem;
+ Mem = temp;
+ }}, {{32}});
+ format Trap {
+ 0x20: ldf({{fault = new FpDisabled;}});
+ 0x21: decode X {
+ 0x0: Load::ldfsr({{Fsr = Mem<31:0> | Fsr<63:32>;}}, {{32}});
+ 0x1: Load::ldxfsr({{Fsr = Mem;}}, {{64}});
+ }
+ 0x22: ldqf({{fault = new FpDisabled;}});
+ 0x23: lddf({{fault = new FpDisabled;}});
+ 0x24: stf({{fault = new FpDisabled;}});
+ 0x25: decode X {
+ 0x0: Store::stfsr({{Mem = Fsr<31:0>;}}, {{32}});
+ 0x1: Store::stxfsr({{Mem = Fsr;}}, {{64}});
+ }
+ 0x26: stqf({{fault = new FpDisabled;}});
+ 0x27: stdf({{fault = new FpDisabled;}});
+ 0x2D: Nop::prefetch({{ }});
+ 0x30: ldfa({{return new FpDisabled;}});
+ 0x32: ldqfa({{fault = new FpDisabled;}});
+ 0x33: lddfa({{fault = new FpDisabled;}});
+ 0x34: stfa({{fault = new FpDisabled;}});
+ 0x35: stqfa({{fault = new FpDisabled;}});
+ 0x36: stdfa({{fault = new FpDisabled;}});
+ 0x3C: Cas::casa({{
+ uint64_t val = Mem.uw;
+ if(Rs2.uw == val)
+ Mem.uw = Rd.uw;
+ Rd.uw = val;
+ }});
+ 0x3D: Nop::prefetcha({{ }});
+ 0x3E: Cas::casxa({{
+ uint64_t val = Mem.udw;
+ if(Rs2 == val)
+ Mem.udw = Rd;
+ Rd = val;
+ }});
+ }
+ }
+}
diff --git a/src/arch/sparc/isa/formats.isa b/src/arch/sparc/isa/formats.isa
new file mode 100644
index 000000000..17d68061b
--- /dev/null
+++ b/src/arch/sparc/isa/formats.isa
@@ -0,0 +1,28 @@
+//Include the basic format
+//Templates from this format are used later
+##include "formats/basic.isa"
+
+//Include the noop format
+##include "formats/nop.isa"
+
+//Include the integerOp and integerOpCc format
+##include "formats/integerop.isa"
+
+//Include the memory format
+##include "formats/mem.isa"
+
+//Include the compare and swap format
+##include "formats/cas.isa"
+
+//Include the trap format
+##include "formats/trap.isa"
+
+//Include the "unknown" format
+##include "formats/unknown.isa"
+
+//Include the priveleged mode format
+##include "formats/priv.isa"
+
+//Include the branch format
+##include "formats/branch.isa"
+
diff --git a/src/arch/sparc/isa/formats/basic.isa b/src/arch/sparc/isa/formats/basic.isa
new file mode 100644
index 000000000..60432cb6b
--- /dev/null
+++ b/src/arch/sparc/isa/formats/basic.isa
@@ -0,0 +1,97 @@
+// Copyright (c) 2006 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Ali Saidi
+// Gabe Black
+// Steve Reinhardt
+
+// Declarations for execute() methods.
+def template BasicExecDeclare {{
+ Fault execute(%(CPU_exec_context)s *, Trace::InstRecord *) const;
+}};
+
+// Basic instruction class declaration template.
+def template BasicDeclare {{
+ /**
+ * Static instruction class for "%(mnemonic)s".
+ */
+ class %(class_name)s : public %(base_class)s
+ {
+ public:
+ // Constructor.
+ %(class_name)s(MachInst machInst);
+ %(BasicExecDeclare)s
+ };
+}};
+
+// Basic instruction class constructor template.
+def template BasicConstructor {{
+ inline %(class_name)s::%(class_name)s(MachInst machInst)
+ : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s)
+ {
+ %(constructor)s;
+ }
+}};
+
+// Basic instruction class execute method template.
+def template BasicExecute {{
+ Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ Fault fault = NoFault;
+
+ %(fp_enable_check)s;
+ %(op_decl)s;
+ %(op_rd)s;
+ %(code)s;
+
+ if(fault == NoFault)
+ {
+ %(op_wb)s;
+ }
+ return fault;
+ }
+}};
+
+// Basic decode template.
+def template BasicDecode {{
+ return new %(class_name)s(machInst);
+}};
+
+// Basic decode template, passing mnemonic in as string arg to constructor.
+def template BasicDecodeWithMnemonic {{
+ return new %(class_name)s("%(mnemonic)s", machInst);
+}};
+
+// The most basic instruction format... used only for a few misc. insts
+def format BasicOperate(code, *flags) {{
+ iop = InstObjParams(name, Name, 'SparcStaticInst',
+ CodeBlock(code), flags)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
+}};
diff --git a/src/arch/sparc/isa/formats/branch.isa b/src/arch/sparc/isa/formats/branch.isa
new file mode 100644
index 000000000..7d46ce739
--- /dev/null
+++ b/src/arch/sparc/isa/formats/branch.isa
@@ -0,0 +1,337 @@
+// Copyright (c) 2006 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Gabe Black
+// Steve Reinhardt
+
+////////////////////////////////////////////////////////////////////
+//
+// Branch instructions
+//
+
+output header {{
+ /**
+ * Base class for branch operations.
+ */
+ class Branch : public SparcStaticInst
+ {
+ protected:
+ // Constructor
+ Branch(const char *mnem, MachInst _machInst, OpClass __opClass) :
+ SparcStaticInst(mnem, _machInst, __opClass)
+ {
+ }
+
+ std::string generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const;
+ };
+
+ /**
+ * Base class for branch operations with an immediate displacement.
+ */
+ class BranchDisp : public Branch
+ {
+ protected:
+ // Constructor
+ BranchDisp(const char *mnem, MachInst _machInst,
+ OpClass __opClass) :
+ Branch(mnem, _machInst, __opClass)
+ {
+ }
+
+ std::string generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const;
+
+ int32_t disp;
+ };
+
+ /**
+ * Base class for branches with 19 bit displacements.
+ */
+ class Branch19 : public BranchDisp
+ {
+ protected:
+ // Constructor
+ Branch19(const char *mnem, MachInst _machInst,
+ OpClass __opClass) :
+ BranchDisp(mnem, _machInst, __opClass)
+ {
+ disp = sign_ext(DISP19 << 2, 21);
+ }
+ };
+
+ /**
+ * Base class for branches with 22 bit displacements.
+ */
+ class Branch22 : public BranchDisp
+ {
+ protected:
+ // Constructor
+ Branch22(const char *mnem, MachInst _machInst,
+ OpClass __opClass) :
+ BranchDisp(mnem, _machInst, __opClass)
+ {
+ disp = sign_ext(DISP22 << 2, 24);
+ }
+ };
+
+ /**
+ * Base class for branches with 30 bit displacements.
+ */
+ class Branch30 : public BranchDisp
+ {
+ protected:
+ // Constructor
+ Branch30(const char *mnem, MachInst _machInst,
+ OpClass __opClass) :
+ BranchDisp(mnem, _machInst, __opClass)
+ {
+ disp = sign_ext(DISP30 << 2, 32);
+ }
+ };
+
+ /**
+ * Base class for 16bit split displacements.
+ */
+ class BranchSplit : public BranchDisp
+ {
+ protected:
+ // Constructor
+ BranchSplit(const char *mnem, MachInst _machInst,
+ OpClass __opClass) :
+ BranchDisp(mnem, _machInst, __opClass)
+ {
+ disp = sign_ext((D16HI << 16) | (D16LO << 2), 18);
+ }
+ };
+
+ /**
+ * Base class for branches that use an immediate and a register to
+ * compute their displacements.
+ */
+ class BranchImm13 : public Branch
+ {
+ protected:
+ // Constructor
+ BranchImm13(const char *mnem, MachInst _machInst, OpClass __opClass) :
+ Branch(mnem, _machInst, __opClass), imm(sign_ext(SIMM13, 13))
+ {
+ }
+
+ std::string generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const;
+
+ int32_t imm;
+ };
+}};
+
+output decoder {{
+ std::string Branch::generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+ {
+ std::stringstream response;
+
+ printMnemonic(response, mnemonic);
+
+ if (_numSrcRegs > 0)
+ {
+ printReg(response, _srcRegIdx[0]);
+ for(int x = 1; x < _numSrcRegs; x++)
+ {
+ response << ", ";
+ printReg(response, _srcRegIdx[x]);
+ }
+ }
+
+ if (_numDestRegs > 0)
+ {
+ if(_numSrcRegs > 0)
+ response << ", ";
+ printReg(response, _destRegIdx[0]);
+ }
+
+ return response.str();
+ }
+
+ std::string BranchImm13::generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+ {
+ std::stringstream response;
+
+ printMnemonic(response, mnemonic);
+
+ if (_numSrcRegs > 0)
+ {
+ printReg(response, _srcRegIdx[0]);
+ for(int x = 1; x < _numSrcRegs; x++)
+ {
+ response << ", ";
+ printReg(response, _srcRegIdx[x]);
+ }
+ }
+
+ if(_numSrcRegs > 0)
+ response << ", ";
+
+ ccprintf(response, "0x%x", imm);
+
+ if (_numDestRegs > 0)
+ {
+ response << ", ";
+ printReg(response, _destRegIdx[0]);
+ }
+
+ return response.str();
+ }
+
+ std::string BranchDisp::generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+ {
+ std::stringstream response;
+ std::string symbol;
+ Addr symbolAddr;
+
+ Addr target = disp + pc;
+
+ printMnemonic(response, mnemonic);
+ ccprintf(response, "0x%x", target);
+
+ if(symtab->findNearestSymbol(target, symbol, symbolAddr))
+ {
+ ccprintf(response, " <%s", symbol);
+ if(symbolAddr != target)
+ ccprintf(response, "+%d>", target - symbolAddr);
+ else
+ ccprintf(response, ">");
+ }
+
+ return response.str();
+ }
+}};
+
+def template BranchExecute {{
+ Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ //Attempt to execute the instruction
+ Fault fault = NoFault;
+
+ %(op_decl)s;
+ %(op_rd)s;
+
+ NNPC = xc->readNextNPC();
+ %(code)s;
+
+ if(fault == NoFault)
+ {
+ //Write the resulting state to the execution context
+ %(op_wb)s;
+ }
+
+ return fault;
+ }
+}};
+
+let {{
+ handle_annul = '''
+ {
+ if(A)
+ {
+ NPC = xc->readNextNPC();
+ NNPC = NPC + 4;
+ }
+ else
+ {
+ NPC = xc->readNextPC();
+ NNPC = xc->readNextNPC();
+ }
+ }'''
+}};
+
+// Primary format for branch instructions:
+def format Branch(code, *opt_flags) {{
+ code = re.sub(r'handle_annul', handle_annul, code)
+ (usesImm, code, immCode,
+ rString, iString) = splitOutImm(code)
+ iop = InstObjParams(name, Name, 'Branch', code, opt_flags)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ exec_output = BranchExecute.subst(iop)
+ if usesImm:
+ imm_iop = InstObjParams(name, Name + 'Imm', 'BranchImm' + iString,
+ immCode, opt_flags)
+ header_output += BasicDeclare.subst(imm_iop)
+ decoder_output += BasicConstructor.subst(imm_iop)
+ exec_output += BranchExecute.subst(imm_iop)
+ decode_block = ROrImmDecode.subst(iop)
+ else:
+ decode_block = BasicDecode.subst(iop)
+}};
+
+// Primary format for branch instructions:
+def format Branch19(code, *opt_flags) {{
+ code = re.sub(r'handle_annul', handle_annul, code)
+ codeBlk = CodeBlock(code)
+ iop = InstObjParams(name, Name, 'Branch19', codeBlk, opt_flags)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ exec_output = BranchExecute.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+}};
+
+// Primary format for branch instructions:
+def format Branch22(code, *opt_flags) {{
+ code = re.sub(r'handle_annul', handle_annul, code)
+ codeBlk = CodeBlock(code)
+ iop = InstObjParams(name, Name, 'Branch22', codeBlk, opt_flags)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ exec_output = BranchExecute.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+}};
+
+// Primary format for branch instructions:
+def format Branch30(code, *opt_flags) {{
+ code = re.sub(r'handle_annul', handle_annul, code)
+ codeBlk = CodeBlock(code)
+ iop = InstObjParams(name, Name, 'Branch30', codeBlk, opt_flags)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ exec_output = BranchExecute.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+}};
+
+// Primary format for branch instructions:
+def format BranchSplit(code, *opt_flags) {{
+ code = re.sub(r'handle_annul', handle_annul, code)
+ codeBlk = CodeBlock(code)
+ iop = InstObjParams(name, Name, 'BranchSplit', codeBlk, opt_flags)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ exec_output = BranchExecute.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+}};
+
diff --git a/src/arch/sparc/isa/formats/integerop.isa b/src/arch/sparc/isa/formats/integerop.isa
new file mode 100644
index 000000000..1fd87b1d3
--- /dev/null
+++ b/src/arch/sparc/isa/formats/integerop.isa
@@ -0,0 +1,379 @@
+// Copyright (c) 2006 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Ali Saidi
+// Gabe Black
+// Steve Reinhardt
+
+////////////////////////////////////////////////////////////////////
+//
+// Integer operate instructions
+//
+
+output header {{
+ /**
+ * Base class for integer operations.
+ */
+ class IntOp : public SparcStaticInst
+ {
+ protected:
+ // Constructor
+ IntOp(const char *mnem, ExtMachInst _machInst,
+ OpClass __opClass) :
+ SparcStaticInst(mnem, _machInst, __opClass)
+ {
+ }
+
+ std::string generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const;
+
+ virtual bool printPseudoOps(std::ostream &os, Addr pc,
+ const SymbolTable *symtab) const;
+ };
+
+ /**
+ * Base class for immediate integer operations.
+ */
+ class IntOpImm : public IntOp
+ {
+ protected:
+ // Constructor
+ IntOpImm(const char *mnem, ExtMachInst _machInst,
+ OpClass __opClass) :
+ IntOp(mnem, _machInst, __opClass)
+ {
+ }
+
+ int32_t imm;
+
+ std::string generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const;
+
+ virtual bool printPseudoOps(std::ostream &os, Addr pc,
+ const SymbolTable *symtab) const;
+ };
+
+ /**
+ * Base class for 10 bit immediate integer operations.
+ */
+ class IntOpImm10 : public IntOpImm
+ {
+ protected:
+ // Constructor
+ IntOpImm10(const char *mnem, ExtMachInst _machInst,
+ OpClass __opClass) :
+ IntOpImm(mnem, _machInst, __opClass)
+ {
+ imm = sign_ext(SIMM10, 10);
+ }
+ };
+
+ /**
+ * Base class for 11 bit immediate integer operations.
+ */
+ class IntOpImm11 : public IntOpImm
+ {
+ protected:
+ // Constructor
+ IntOpImm11(const char *mnem, ExtMachInst _machInst,
+ OpClass __opClass) :
+ IntOpImm(mnem, _machInst, __opClass)
+ {
+ imm = sign_ext(SIMM11, 11);
+ }
+ };
+
+ /**
+ * Base class for 13 bit immediate integer operations.
+ */
+ class IntOpImm13 : public IntOpImm
+ {
+ protected:
+ // Constructor
+ IntOpImm13(const char *mnem, ExtMachInst _machInst,
+ OpClass __opClass) :
+ IntOpImm(mnem, _machInst, __opClass)
+ {
+ imm = sign_ext(SIMM13, 13);
+ }
+ };
+
+ /**
+ * Base class for sethi.
+ */
+ class SetHi : public IntOpImm
+ {
+ protected:
+ // Constructor
+ SetHi(const char *mnem, ExtMachInst _machInst,
+ OpClass __opClass) :
+ IntOpImm(mnem, _machInst, __opClass)
+ {
+ imm = (IMM22 << 10) & 0xFFFFFC00;
+ }
+
+ std::string generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const;
+ };
+}};
+
+def template SetHiDecode {{
+ {
+ if(RD == 0 && IMM22 == 0)
+ return (SparcStaticInst *)(new Nop("nop", machInst, No_OpClass));
+ else
+ return (SparcStaticInst *)(new %(class_name)s(machInst));
+ }
+}};
+
+output decoder {{
+
+ bool IntOp::printPseudoOps(std::ostream &os, Addr pc,
+ const SymbolTable *symbab) const
+ {
+ if(!strcmp(mnemonic, "or") && _srcRegIdx[0] == 0)
+ {
+ printMnemonic(os, "mov");
+ if(_numSrcRegs > 0)
+ printReg(os, _srcRegIdx[1]);
+ ccprintf(os, ", ");
+ if(_numDestRegs > 0)
+ printReg(os, _destRegIdx[0]);
+
+ return true;
+ }
+ return false;
+ }
+
+ bool IntOpImm::printPseudoOps(std::ostream &os, Addr pc,
+ const SymbolTable *symbab) const
+ {
+ if(!strcmp(mnemonic, "or"))
+ {
+ if(_srcRegIdx[0] == 0)
+ {
+ if(imm == 0)
+ {
+ printMnemonic(os, "clr");
+ if(_numDestRegs > 0)
+ printReg(os, _destRegIdx[0]);
+ return true;
+ }
+ else
+ {
+ printMnemonic(os, "mov");
+ ccprintf(os, ", 0x%x, ", imm);
+ if(_numDestRegs > 0)
+ printReg(os, _destRegIdx[0]);
+ return true;
+ }
+ }
+ else if(imm == 0)
+ {
+ printMnemonic(os, "mov");
+ if(_numSrcRegs > 0)
+ printReg(os, _srcRegIdx[0]);
+ ccprintf(os, ", ");
+ if(_numDestRegs > 0)
+ printReg(os, _destRegIdx[0]);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ std::string IntOp::generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+ {
+ std::stringstream response;
+
+ if(!printPseudoOps(response, pc, symtab))
+ {
+ printMnemonic(response, mnemonic);
+ if (_numSrcRegs > 0)
+ {
+ printReg(response, _srcRegIdx[0]);
+ for(int x = 1; x < _numSrcRegs; x++)
+ {
+ response << ", ";
+ printReg(response, _srcRegIdx[x]);
+ }
+ }
+ if (_numDestRegs > 0)
+ {
+ if(_numSrcRegs > 0)
+ response << ", ";
+ printReg(response, _destRegIdx[0]);
+ }
+ }
+ return response.str();
+ }
+
+ std::string IntOpImm::generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+ {
+ std::stringstream response;
+
+ if(!printPseudoOps(response, pc, symtab))
+ {
+ printMnemonic(response, mnemonic);
+ if (_numSrcRegs > 0)
+ {
+ printReg(response, _srcRegIdx[0]);
+ for(int x = 1; x < _numSrcRegs - 1; x++)
+ {
+ response << ", ";
+ printReg(response, _srcRegIdx[x]);
+ }
+ }
+ if(_numSrcRegs > 0)
+ response << ", ";
+ ccprintf(response, "0x%x", imm);
+ if (_numDestRegs > 0)
+ {
+ response << ", ";
+ printReg(response, _destRegIdx[0]);
+ }
+ }
+ return response.str();
+ }
+
+ std::string SetHi::generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+ {
+ std::stringstream response;
+
+ printMnemonic(response, mnemonic);
+ if(_numSrcRegs > 0)
+ response << ", ";
+ ccprintf(response, "%%hi(0x%x), ", imm);
+ printReg(response, _destRegIdx[0]);
+ return response.str();
+ }
+}};
+
+def template IntOpExecute {{
+ Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ Fault fault = NoFault;
+
+ %(op_decl)s;
+ %(op_rd)s;
+ %(code)s;
+
+ //Write the resulting state to the execution context
+ if(fault == NoFault)
+ {
+ %(cc_code)s;
+ %(op_wb)s;
+ }
+ return fault;
+ }
+}};
+
+let {{
+ def doIntFormat(code, ccCode, name, Name, opt_flags):
+ (usesImm, code, immCode,
+ rString, iString) = splitOutImm(code)
+ iop = InstObjParams(name, Name, 'IntOp', code,
+ opt_flags, ("cc_code", ccCode))
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ exec_output = IntOpExecute.subst(iop)
+ if usesImm:
+ imm_iop = InstObjParams(name, Name + 'Imm', 'IntOpImm' + iString,
+ immCode, opt_flags, ("cc_code", ccCode))
+ header_output += BasicDeclare.subst(imm_iop)
+ decoder_output += BasicConstructor.subst(imm_iop)
+ exec_output += IntOpExecute.subst(imm_iop)
+ decode_block = ROrImmDecode.subst(iop)
+ else:
+ decode_block = BasicDecode.subst(iop)
+ return (header_output, decoder_output, exec_output, decode_block)
+
+ calcCcCode = '''
+ CcrIccN = (Rd >> 31) & 1;
+ CcrIccZ = ((Rd & 0xFFFFFFFF) == 0);
+ CcrXccN = (Rd >> 63) & 1;
+ CcrXccZ = (Rd == 0);
+ CcrIccV = %(ivValue)s;
+ CcrIccC = %(icValue)s;
+ CcrXccV = %(xvValue)s;
+ CcrXccC = %(xcValue)s;
+ DPRINTF(Sparc, "in = %%d\\n", CcrIccN);
+ DPRINTF(Sparc, "iz = %%d\\n", CcrIccZ);
+ DPRINTF(Sparc, "xn = %%d\\n", CcrXccN);
+ DPRINTF(Sparc, "xz = %%d\\n", CcrXccZ);
+ DPRINTF(Sparc, "iv = %%d\\n", CcrIccV);
+ DPRINTF(Sparc, "ic = %%d\\n", CcrIccC);
+ DPRINTF(Sparc, "xv = %%d\\n", CcrXccV);
+ DPRINTF(Sparc, "xc = %%d\\n", CcrXccC);
+ '''
+}};
+
+// Primary format for integer operate instructions:
+def format IntOp(code, *opt_flags) {{
+ ccCode = ''
+ (header_output,
+ decoder_output,
+ exec_output,
+ decode_block) = doIntFormat(code, ccCode,
+ name, Name, opt_flags)
+}};
+
+// Primary format for integer operate instructions:
+def format IntOpCc(code, icValue, ivValue, xcValue, xvValue, *opt_flags) {{
+ ccCode = calcCcCode % vars()
+ (header_output,
+ decoder_output,
+ exec_output,
+ decode_block) = doIntFormat(code, ccCode,
+ name, Name, opt_flags)
+}};
+
+// Primary format for integer operate instructions:
+def format IntOpCcRes(code, *opt_flags) {{
+ ccCode = calcCcCode % {"icValue":"0",
+ "ivValue":"0",
+ "xcValue":"0",
+ "xvValue":"0"}
+ (header_output,
+ decoder_output,
+ exec_output,
+ decode_block) = doIntFormat(code, ccCode,
+ name, Name, opt_flags)
+}};
+
+def format SetHi(code, *opt_flags) {{
+ iop = InstObjParams(name, Name, 'SetHi',
+ code, opt_flags, ("cc_code", ''))
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ exec_output = IntOpExecute.subst(iop)
+ decode_block = SetHiDecode.subst(iop)
+}};
+
diff --git a/src/arch/sparc/isa/formats/mem.isa b/src/arch/sparc/isa/formats/mem.isa
new file mode 100644
index 000000000..12dae57e5
--- /dev/null
+++ b/src/arch/sparc/isa/formats/mem.isa
@@ -0,0 +1,171 @@
+////////////////////////////////////////////////////////////////////
+//
+// Mem instructions
+//
+
+output header {{
+ /**
+ * Base class for memory operations.
+ */
+ class Mem : public SparcStaticInst
+ {
+ protected:
+
+ // Constructor
+ Mem(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
+ SparcStaticInst(mnem, _machInst, __opClass)
+ {
+ }
+
+ std::string generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const;
+ };
+
+ /**
+ * Class for memory operations which use an immediate offset.
+ */
+ class MemImm : public Mem
+ {
+ protected:
+
+ // Constructor
+ MemImm(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
+ Mem(mnem, _machInst, __opClass)
+ {
+ imm = sign_ext(SIMM13, 13);
+ }
+
+ std::string generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const;
+
+ int32_t imm;
+ };
+}};
+
+output decoder {{
+ std::string Mem::generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+ {
+ std::stringstream response;
+ bool load = flags[IsLoad];
+ bool save = flags[IsStore];
+
+ printMnemonic(response, mnemonic);
+ if(save)
+ {
+ printReg(response, _srcRegIdx[0]);
+ ccprintf(response, ", ");
+ }
+ ccprintf(response, "[ ");
+ printReg(response, _srcRegIdx[!save ? 0 : 1]);
+ ccprintf(response, " + ");
+ printReg(response, _srcRegIdx[!save ? 1 : 2]);
+ ccprintf(response, " ]");
+ if(load)
+ {
+ ccprintf(response, ", ");
+ printReg(response, _destRegIdx[0]);
+ }
+
+ return response.str();
+ }
+
+ std::string MemImm::generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+ {
+ std::stringstream response;
+ bool load = flags[IsLoad];
+ bool save = flags[IsStore];
+
+ printMnemonic(response, mnemonic);
+ if(save)
+ {
+ printReg(response, _srcRegIdx[0]);
+ ccprintf(response, ", ");
+ }
+ ccprintf(response, "[ ");
+ printReg(response, _srcRegIdx[!save ? 0 : 1]);
+ if(imm >= 0)
+ ccprintf(response, " + 0x%x ]", imm);
+ else
+ ccprintf(response, " + -0x%x ]", -imm);
+ if(load)
+ {
+ ccprintf(response, ", ");
+ printReg(response, _destRegIdx[0]);
+ }
+
+ return response.str();
+ }
+}};
+
+def template MemExecute {{
+ Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ Fault fault = NoFault;
+ Addr EA;
+ %(op_decl)s;
+ %(op_rd)s;
+ %(ea_code)s;
+ DPRINTF(Sparc, "The address is 0x%x\n", EA);
+ %(load)s;
+ %(code)s;
+ %(store)s;
+
+ if(fault == NoFault)
+ {
+ //Write the resulting state to the execution context
+ %(op_wb)s;
+ }
+
+ return fault;
+ }
+}};
+
+let {{
+ # Leave memAccessFlags at 0 for now
+ loadString = "xc->read(EA, (uint%(width)s_t&)Mem, 0);"
+ storeString = "uint64_t write_result = 0; \
+ xc->write((uint%(width)s_t)Mem, EA, 0, &write_result);"
+
+ def doMemFormat(code, load, store, name, Name, opt_flags):
+ addrCalcReg = 'EA = Rs1 + Rs2;'
+ addrCalcImm = 'EA = Rs1 + imm;'
+ iop = InstObjParams(name, Name, 'Mem', code,
+ opt_flags, ("ea_code", addrCalcReg),
+ ("load", load), ("store", store))
+ iop_imm = InstObjParams(name, Name + 'Imm', 'MemImm', code,
+ opt_flags, ("ea_code", addrCalcImm),
+ ("load", load), ("store", store))
+ header_output = BasicDeclare.subst(iop) + BasicDeclare.subst(iop_imm)
+ decoder_output = BasicConstructor.subst(iop) + BasicConstructor.subst(iop_imm)
+ decode_block = ROrImmDecode.subst(iop)
+ exec_output = MemExecute.subst(iop) + MemExecute.subst(iop_imm)
+ return (header_output, decoder_output, exec_output, decode_block)
+}};
+
+def format Load(code, width, *opt_flags) {{
+ (header_output,
+ decoder_output,
+ exec_output,
+ decode_block) = doMemFormat(code,
+ loadString % {"width":width}, '', name, Name, opt_flags)
+}};
+
+def format Store(code, width, *opt_flags) {{
+ (header_output,
+ decoder_output,
+ exec_output,
+ decode_block) = doMemFormat(code, '',
+ storeString % {"width":width}, name, Name, opt_flags)
+}};
+
+def format LoadStore(code, width, *opt_flags) {{
+ (header_output,
+ decoder_output,
+ exec_output,
+ decode_block) = doMemFormat(code,
+ loadString % {"width":width}, storeString % {"width":width},
+ name, Name, opt_flags)
+}};
diff --git a/src/arch/sparc/isa/formats/nop.isa b/src/arch/sparc/isa/formats/nop.isa
new file mode 100644
index 000000000..7fd1a3b21
--- /dev/null
+++ b/src/arch/sparc/isa/formats/nop.isa
@@ -0,0 +1,91 @@
+// Copyright (c) 2006 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Gabe Black
+// Steve Reinhardt
+
+////////////////////////////////////////////////////////////////////
+//
+// Nop instruction
+//
+
+output header {{
+ /**
+ * Nop class.
+ */
+ class Nop : public SparcStaticInst
+ {
+ public:
+ // Constructor
+ Nop(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
+ SparcStaticInst(mnem, _machInst, __opClass)
+ {
+ }
+
+ // All Nop instructions do the same thing, so this can be
+ // defined here. Nops can be defined directly, so there needs
+ // to be a default implementation
+ Fault execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ //Nothing to see here, move along
+ return NoFault;
+ }
+
+ std::string generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const;
+ };
+}};
+
+output decoder {{
+ std::string Nop::generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+ {
+ std::stringstream response;
+ printMnemonic(response, mnemonic);
+ return response.str();
+ }
+}};
+
+def template NopExecute {{
+ Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ //Nothing to see here, move along
+ return NoFault;
+ }
+}};
+
+// Primary format for integer operate instructions:
+def format Nop(code, *opt_flags) {{
+ orig_code = code
+ cblk = CodeBlock(code)
+ iop = InstObjParams(name, Name, 'Nop', cblk, opt_flags)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ exec_output = NopExecute.subst(iop)
+}};
diff --git a/src/arch/sparc/isa/formats/priv.isa b/src/arch/sparc/isa/formats/priv.isa
new file mode 100644
index 000000000..a8de22c0e
--- /dev/null
+++ b/src/arch/sparc/isa/formats/priv.isa
@@ -0,0 +1,169 @@
+// Copyright (c) 2006 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Ali Saidi
+// Gabe Black
+// Steve Reinhardt
+
+////////////////////////////////////////////////////////////////////
+//
+// Privilege mode instructions
+//
+
+output header {{
+ /**
+ * Base class for privelege mode operations.
+ */
+ class Priv : public SparcStaticInst
+ {
+ protected:
+ // Constructor
+ Priv(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
+ SparcStaticInst(mnem, _machInst, __opClass)
+ {
+ }
+
+ std::string generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const;
+ };
+
+ /**
+ * Base class for user mode "tick" access.
+ */
+ class PrivTick : public SparcStaticInst
+ {
+ protected:
+ // Constructor
+ PrivTick(const char *mnem, ExtMachInst _machInst,
+ OpClass __opClass) :
+ SparcStaticInst(mnem, _machInst, __opClass)
+ {
+ }
+
+ std::string generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const;
+ };
+
+ /**
+ * Base class for privelege mode operations with immediates.
+ */
+ class PrivImm : public Priv
+ {
+ protected:
+ // Constructor
+ PrivImm(const char *mnem, ExtMachInst _machInst,
+ OpClass __opClass) :
+ Priv(mnem, _machInst, __opClass), imm(SIMM13)
+ {
+ }
+
+ int32_t imm;
+ };
+
+ /**
+ * Base class for user mode "tick" access with immediates.
+ */
+ class PrivTickImm : public PrivTick
+ {
+ protected:
+ // Constructor
+ PrivTickImm(const char *mnem, ExtMachInst _machInst,
+ OpClass __opClass) :
+ PrivTick(mnem, _machInst, __opClass), imm(SIMM13)
+ {
+ }
+
+ int32_t imm;
+ };
+}};
+
+output decoder {{
+ std::string Priv::generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+ {
+ return "Privileged Instruction";
+ }
+
+ std::string PrivTick::generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+ {
+ return "Regular access to Tick";
+ }
+}};
+
+def template PrivExecute {{
+ Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ %(op_decl)s;
+ %(op_rd)s;
+
+ //If the processor isn't in privileged mode, fault out right away
+ if(%(check)s)
+ return new PrivilegedAction;
+
+ %(code)s;
+ %(op_wb)s;
+ return NoFault;
+ }
+}};
+
+let {{
+ def doPrivFormat(code, checkCode, name, Name, opt_flags):
+ (usesImm, code, immCode,
+ rString, iString) = splitOutImm(code)
+ iop = InstObjParams(name, Name, 'Priv', code,
+ opt_flags, ("check", checkCode))
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ exec_output = PrivExecute.subst(iop)
+ if usesImm:
+ imm_iop = InstObjParams(name, Name + 'Imm', 'PrivImm',
+ immCode, opt_flags, ("check", checkCode))
+ header_output += BasicDeclare.subst(imm_iop)
+ decoder_output += BasicConstructor.subst(imm_iop)
+ exec_output += PrivExecute.subst(imm_iop)
+ decode_block = ROrImmDecode.subst(iop)
+ else:
+ decode_block = BasicDecode.subst(iop)
+ return (header_output, decoder_output, exec_output, decode_block)
+}};
+
+// Primary format for integer operate instructions:
+def format Priv(code, *opt_flags) {{
+ checkCode = "(!PstatePriv)"
+ (header_output, decoder_output,
+ exec_output, decode_block) = doPrivFormat(code,
+ checkCode, name, Name, opt_flags)
+}};
+
+// Primary format for integer operate instructions:
+def format PrivTick(code, *opt_flags) {{
+ checkCode = "(!PstatePriv && TickNpt)"
+ (header_output, decoder_output,
+ exec_output, decode_block) = doPrivFormat(code,
+ checkCode, name, Name, opt_flags)
+}};
diff --git a/src/arch/sparc/isa/formats/trap.isa b/src/arch/sparc/isa/formats/trap.isa
new file mode 100644
index 000000000..04d467cfe
--- /dev/null
+++ b/src/arch/sparc/isa/formats/trap.isa
@@ -0,0 +1,93 @@
+// Copyright (c) 2006 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Gabe Black
+// Steve Reinhardt
+
+////////////////////////////////////////////////////////////////////
+//
+// Trap instructions
+//
+
+output header {{
+ /**
+ * Base class for trap instructions,
+ * or instructions that always fault.
+ */
+ class Trap : public SparcStaticInst
+ {
+ protected:
+
+ // Constructor
+ Trap(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
+ SparcStaticInst(mnem, _machInst, __opClass), trapNum(SW_TRAP)
+ {
+ }
+
+ std::string generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const;
+
+ int trapNum;
+ };
+}};
+
+output decoder {{
+ std::string Trap::generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+ {
+ std::stringstream response;
+
+ printMnemonic(response, mnemonic);
+ ccprintf(response, " ");
+ printReg(response, _srcRegIdx[0]);
+ ccprintf(response, ", 0x%x", trapNum);
+ ccprintf(response, ", or ");
+ printReg(response, _srcRegIdx[1]);
+ return response.str();
+ }
+}};
+
+def template TrapExecute {{
+ Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ Fault fault = NoFault;
+ %(op_decl)s;
+ %(op_rd)s;
+ %(code)s
+ return fault;
+ }
+}};
+
+def format Trap(code, *opt_flags) {{
+ orig_code = code
+ cblk = CodeBlock(code)
+ iop = InstObjParams(name, Name, 'Trap', cblk, opt_flags)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ exec_output = TrapExecute.subst(iop)
+}};
diff --git a/src/arch/sparc/isa/formats/unknown.isa b/src/arch/sparc/isa/formats/unknown.isa
new file mode 100644
index 000000000..8541d6a62
--- /dev/null
+++ b/src/arch/sparc/isa/formats/unknown.isa
@@ -0,0 +1,75 @@
+// Copyright (c) 2006 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Gabe Black
+// Steve Reinhardt
+
+////////////////////////////////////////////////////////////////////
+//
+// Unknown instructions
+//
+
+output header {{
+ /**
+ * Class for Unknown/Illegal instructions
+ */
+ class Unknown : public SparcStaticInst
+ {
+ public:
+
+ // Constructor
+ Unknown(ExtMachInst _machInst) :
+ SparcStaticInst("unknown", _machInst, No_OpClass)
+ {
+ }
+
+ %(BasicExecDeclare)s
+
+ std::string generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const;
+
+ };
+}};
+
+output decoder {{
+ std::string Unknown::generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+ {
+ return "Unknown instruction";
+ }
+}};
+
+output exec {{
+ Fault Unknown::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ return new IllegalInstruction;
+ }
+}};
+
+def format Unknown() {{
+ decode_block = 'return new Unknown(machInst);\n'
+}};
diff --git a/src/arch/sparc/isa/includes.isa b/src/arch/sparc/isa/includes.isa
new file mode 100644
index 000000000..762de243a
--- /dev/null
+++ b/src/arch/sparc/isa/includes.isa
@@ -0,0 +1,76 @@
+// Copyright (c) 2006 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Ali Saidi
+// Gabe Black
+// Steve Reinhardt
+
+////////////////////////////////////////////////////////////////////
+//
+// Output include file directives.
+//
+
+output header {{
+#include <sstream>
+#include <iostream>
+#include <iomanip>
+
+#include "cpu/static_inst.hh"
+#include "arch/sparc/faults.hh"
+#include "mem/request.hh" // some constructors use MemReq flags
+#include "arch/sparc/isa_traits.hh"
+#include "arch/sparc/regfile.hh"
+}};
+
+output decoder {{
+#include "base/cprintf.hh"
+#include "base/loader/symtab.hh"
+#include "cpu/exec_context.hh" // for Jump::branchTarget()
+
+#include <math.h>
+#if defined(linux)
+#include <fenv.h>
+#endif
+
+using namespace SparcISA;
+}};
+
+output exec {{
+#include <math.h>
+#if defined(linux)
+#include <fenv.h>
+#endif
+
+#ifdef FULL_SYSTEM
+//#include "sim/pseudo_inst.hh"
+#endif
+#include "cpu/base.hh"
+#include "cpu/exetrace.hh"
+#include "sim/sim_exit.hh"
+
+using namespace SparcISA;
+}};
+
diff --git a/src/arch/sparc/isa/main.isa b/src/arch/sparc/isa/main.isa
new file mode 100644
index 000000000..35167d6b7
--- /dev/null
+++ b/src/arch/sparc/isa/main.isa
@@ -0,0 +1,52 @@
+// -*- mode:c++ -*-
+
+// Copyright (c) 2003-2005 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+##include "includes.isa"
+
+////////////////////////////////////////////////////////////////////
+//
+// Namespace statement. Everything below this line will be in the
+// SparcISAInst namespace.
+//
+
+namespace SparcISA;
+
+//Include the bitfield definitions
+##include "bitfields.isa"
+
+//Include the operand_types and operand definitions
+##include "operands.isa"
+
+//Include the base class for sparc instructions, and some support code
+##include "base.isa"
+
+//Include the definitions for the instruction formats
+##include "formats.isa"
+
+//Include the decoder definition
+##include "decoder.isa"
diff --git a/src/arch/sparc/isa/operands.isa b/src/arch/sparc/isa/operands.isa
new file mode 100644
index 000000000..a89034e30
--- /dev/null
+++ b/src/arch/sparc/isa/operands.isa
@@ -0,0 +1,145 @@
+// Copyright (c) 2006 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Ali Saidi
+// Gabe Black
+// Steve Reinhardt
+
+def operand_types {{
+ 'sb' : ('signed int', 8),
+ 'ub' : ('unsigned int', 8),
+ 'shw' : ('signed int', 16),
+ 'uhw' : ('unsigned int', 16),
+ 'sw' : ('signed int', 32),
+ 'uw' : ('unsigned int', 32),
+ 'sdw' : ('signed int', 64),
+ 'udw' : ('unsigned int', 64),
+ 'sf' : ('float', 32),
+ 'df' : ('float', 64),
+ 'qf' : ('float', 128)
+}};
+
+def operands {{
+ # Int regs default to unsigned, but code should not count on this.
+ # For clarity, descriptions that depend on unsigned behavior should
+ # explicitly specify '.uq'.
+ 'Rd': ('IntReg', 'udw', 'RD', 'IsInteger', 1),
+ 'RdLow': ('IntReg', 'udw', 'RD & (~1)', 'IsInteger', 2),
+ 'RdHigh': ('IntReg', 'udw', 'RD | 1', 'IsInteger', 3),
+ 'Rs1': ('IntReg', 'udw', 'RS1', 'IsInteger', 4),
+ 'Rs2': ('IntReg', 'udw', 'RS2', 'IsInteger', 5),
+ #'Fa': ('FloatReg', 'df', 'FA', 'IsFloating', 1),
+ #'Fb': ('FloatReg', 'df', 'FB', 'IsFloating', 2),
+ #'Fc': ('FloatReg', 'df', 'FC', 'IsFloating', 3),
+ 'Mem': ('Mem', 'udw', None, ('IsMemRef', 'IsLoad', 'IsStore'), 4),
+ 'NPC': ('NPC', 'udw', None, ( None, None, 'IsControl' ), 4),
+ 'NNPC': ('NNPC', 'udw', None, (None, None, 'IsControl' ), 4),
+ #'Runiq': ('ControlReg', 'uq', 'Uniq', None, 1),
+ #'FPCR': ('ControlReg', 'uq', 'Fpcr', None, 1),
+ 'R0': ('IntReg', 'udw', '0', None, 6),
+ 'R1': ('IntReg', 'udw', '1', None, 7),
+ 'R15': ('IntReg', 'udw', '15', 'IsInteger', 8),
+ 'R16': ('IntReg', 'udw', '16', None, 9),
+ # Control registers
+ 'Pstate': ('ControlReg', 'udw', 'MISCREG_PSTATE', None, 1),
+ 'PstateAg': ('ControlReg', 'udw', 'MISCREG_PSTATE_AG', None, 2),
+ 'PstateIe': ('ControlReg', 'udw', 'MISCREG_PSTATE_IE', None, 3),
+ 'PstatePriv': ('ControlReg', 'udw', 'MISCREG_PSTATE_PRIV', None, 4),
+ 'PstateAm': ('ControlReg', 'udw', 'MISCREG_PSTATE_AM', None, 5),
+ 'PstatePef': ('ControlReg', 'udw', 'MISCREG_PSTATE_PEF', None, 6),
+ 'PstateRed': ('ControlReg', 'udw', 'MISCREG_PSTATE_RED', None, 7),
+ 'PstateMm': ('ControlReg', 'udw', 'MISCREG_PSTATE_MM', None, 8),
+ 'PstateTle': ('ControlReg', 'udw', 'MISCREG_PSTATE_TLE', None, 9),
+ 'PstateCle': ('ControlReg', 'udw', 'MISCREG_PSTATE_CLE', None, 10),
+ 'Tba': ('ControlReg', 'udw', 'MISCREG_TBA', None, 11),
+ 'Y': ('ControlReg', 'udw', 'MISCREG_Y', None, 12),
+ 'YValue': ('ControlReg', 'udw', 'MISCREG_Y_VALUE', None, 13),
+ 'Pil': ('ControlReg', 'udw', 'MISCREG_PIL', None, 14),
+ 'Cwp': ('ControlReg', 'udw', 'MISCREG_CWP', None, 15),
+ #'Tt': ('ControlReg', 'udw', 'MISCREG_TT_BASE + tl', None, 16),
+ 'Ccr': ('ControlReg', 'udw', 'MISCREG_CCR', None, 17),
+ 'CcrIcc': ('ControlReg', 'udw', 'MISCREG_CCR_ICC', None, 18),
+ 'CcrIccC': ('ControlReg', 'udw', 'MISCREG_CCR_ICC_C', None, 19),
+ 'CcrIccV': ('ControlReg', 'udw', 'MISCREG_CCR_ICC_V', None, 20),
+ 'CcrIccZ': ('ControlReg', 'udw', 'MISCREG_CCR_ICC_Z', None, 21),
+ 'CcrIccN': ('ControlReg', 'udw', 'MISCREG_CCR_ICC_N', None, 22),
+ 'CcrXcc': ('ControlReg', 'udw', 'MISCREG_CCR_XCC', None, 23),
+ 'CcrXccC': ('ControlReg', 'udw', 'MISCREG_CCR_XCC_C', None, 22),
+ 'CcrXccV': ('ControlReg', 'udw', 'MISCREG_CCR_XCC_V', None, 23),
+ 'CcrXccZ': ('ControlReg', 'udw', 'MISCREG_CCR_XCC_Z', None, 24),
+ 'CcrXccN': ('ControlReg', 'udw', 'MISCREG_CCR_XCC_N', None, 25),
+ 'Asi': ('ControlReg', 'udw', 'MISCREG_ASI', None, 26),
+ 'Tl': ('ControlReg', 'udw', 'MISCREG_TL', None, 27),
+ #'Tpc': ('ControlReg', 'udw', 'MISCREG_TPC', None, 28),
+ 'Tick': ('ControlReg', 'udw', 'MISCREG_TICK', None, 29),
+ 'TickCounter': ('ControlReg', 'udw', 'MISCREG_TICK_COUNTER', None, 32),
+ 'TickNpt': ('ControlReg', 'udw', 'MISCREG_TICK_NPT', None, 33),
+ 'Cansave': ('ControlReg', 'udw', 'MISCREG_CANSAVE', None, 34),
+ 'Canrestore': ('ControlReg', 'udw', 'MISCREG_CANRESTORE', None, 35),
+ 'Otherwin': ('ControlReg', 'udw', 'MISCREG_OTHERWIN', None, 36),
+ 'Cleanwin': ('ControlReg', 'udw', 'MISCREG_CLEANWIN', None, 37),
+ 'Wstate': ('ControlReg', 'udw', 'MISCREG_WSTATE', None, 38),
+ 'WstateNormal': ('ControlReg', 'udw', 'MISCREG_WSTATE_NORMAL', None,39),
+ 'WstateOther': ('ControlReg', 'udw', 'MISCREG_WSTATE_OTHER', None, 40),
+ 'Ver': ('ControlReg', 'udw', 'MISCREG_VER', None, 41),
+ 'VerMaxwin': ('ControlReg', 'udw', 'MISCREG_VER_MAXWIN', None, 42),
+ 'VerMaxtl': ('ControlReg', 'udw', 'MISCREG_VER_MAXTL', None, 43),
+ 'VerMask': ('ControlReg', 'udw', 'MISCREG_VER_MASK', None, 44),
+ 'VerImpl': ('ControlReg', 'udw', 'MISCREG_VER_MASK', None, 45),
+ 'VerManuf': ('ControlReg', 'udw', 'MISCREG_VER_MANUF', None, 46),
+ 'Fsr': ('ControlReg', 'udw', 'MISCREG_FSR', None, 47),
+ 'FsrCexc': ('ControlReg', 'udw', 'MISCREG_FSR_CEXC', None, 48),
+ 'FsrCexcNxc': ('ControlReg', 'udw', 'MISCREG_FSR_CEXC_NXC', None, 49),
+ 'FsrCexcDzc': ('ControlReg', 'udw', 'MISCREG_FSR_CEXC_DZC', None, 50),
+ 'FsrCexcUfc': ('ControlReg', 'udw', 'MISCREG_FSR_CEXC_UFC', None, 51),
+ 'FsrCexcOfc': ('ControlReg', 'udw', 'MISCREG_FSR_CEXC_OFC', None, 52),
+ 'FsrCexcNvc': ('ControlReg', 'udw', 'MISCREG_FSR_CEXC_NVC', None, 53),
+ 'FsrAexc': ('ControlReg', 'udw', 'MISCREG_FSR_AEXC', None, 54),
+ 'FsrAexcNxc': ('ControlReg', 'udw', 'MISCREG_FSR_AEXC_NXC', None, 55),
+ 'FsrAexcDzc': ('ControlReg', 'udw', 'MISCREG_FSR_AEXC_DZC', None, 56),
+ 'FsrAexcUfc': ('ControlReg', 'udw', 'MISCREG_FSR_AEXC_UFC', None, 57),
+ 'FsrAexcOfc': ('ControlReg', 'udw', 'MISCREG_FSR_AEXC_OFC', None, 58),
+ 'FsrAexcNvc': ('ControlReg', 'udw', 'MISCREC_FSR_AEXC_NVC', None, 59),
+ 'FsrFcc0': ('ControlReg', 'udw', 'MISCREG_FSR_FCC0', None, 60),
+ 'FsrQne': ('ControlReg', 'udw', 'MISCREG_FSR_QNE', None, 61),
+ 'FsrFtt': ('ControlReg', 'udw', 'MISCREG_FSR_FTT', None, 62),
+ 'FsrVer': ('ControlReg', 'udw', 'MISCREG_FSR_VER', None, 63),
+ 'FsrNs': ('ControlReg', 'udw', 'MISCREG_FSR_NS', None, 64),
+ 'FsrTem': ('ControlReg', 'udw', 'MISCREG_FSR_TEM', None, 65),
+ 'FsrTemNxm': ('ControlReg', 'udw', 'MISCREG_FSR_TEM_NXM', None, 66),
+ 'FsrTemDzm': ('ControlReg', 'udw', 'MISCREG_FSR_TEM_DZM', None, 67),
+ 'FsrTemUfm': ('ControlReg', 'udw', 'MISCREG_FSR_TEM_UFM', None, 68),
+ 'FsrTemOfm': ('ControlReg', 'udw', 'MISCREG_FSR_TEM_OFM', None, 69),
+ 'FsrTemNvm': ('ControlReg', 'udw', 'MISCREG_FSR_TEM_NVM', None, 70),
+ 'FsrRd': ('ControlReg', 'udw', 'MISCREG_FSR_RD', None, 71),
+ 'FsrFcc1': ('ControlReg', 'udw', 'MISCREG_FSR_FCC1', None, 72),
+ 'FsrFcc2': ('ControlReg', 'udw', 'MISCREG_FSR_FCC2', None, 73),
+ 'FsrFcc3': ('ControlReg', 'udw', 'MISCREG_FSR_FCC3', None, 74),
+ 'Fprs': ('ControlReg', 'udw', 'MISCREG_FPRS', None, 75),
+ 'FprsDl': ('ControlReg', 'udw', 'MISCREG_FPRS_DL', None, 76),
+ 'FprsDu': ('ControlReg', 'udw', 'MISCREG_FPRS_DU', None, 77),
+ 'FprsFef': ('ControlReg', 'udw', 'MISCREG_FPRS_FEF', None, 78)
+}};
diff --git a/src/arch/sparc/isa_traits.hh b/src/arch/sparc/isa_traits.hh
new file mode 100644
index 000000000..453d14664
--- /dev/null
+++ b/src/arch/sparc/isa_traits.hh
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ARCH_SPARC_ISA_TRAITS_HH__
+#define __ARCH_SPARC_ISA_TRAITS_HH__
+
+#include "base/misc.hh"
+#include "config/full_system.hh"
+#include "sim/host.hh"
+
+class ExecContext;
+class FastCPU;
+//class FullCPU;
+class Checkpoint;
+
+class StaticInst;
+class StaticInstPtr;
+
+namespace BigEndianGuest {}
+
+#if !FULL_SYSTEM
+class SyscallReturn
+{
+ public:
+ template <class T>
+ SyscallReturn(T v, bool s)
+ {
+ retval = (uint64_t)v;
+ success = s;
+ }
+
+ template <class T>
+ SyscallReturn(T v)
+ {
+ success = (v >= 0);
+ retval = (uint64_t)v;
+ }
+
+ ~SyscallReturn() {}
+
+ SyscallReturn& operator=(const SyscallReturn& s)
+ {
+ retval = s.retval;
+ success = s.success;
+ return *this;
+ }
+
+ bool successful() { return success; }
+ uint64_t value() { return retval; }
+
+ private:
+ uint64_t retval;
+ bool success;
+};
+
+#endif
+
+
+namespace SparcISA
+{
+
+ // These enumerate all the registers for dependence tracking.
+ enum DependenceTags {
+ // 0..31 are the integer regs 0..31
+ // 32..63 are the FP regs 0..31, i.e. use (reg + FP_Base_DepTag)
+ FP_Base_DepTag = 32,
+ Ctrl_Base_DepTag = 96,
+ //XXX These are here solely to get compilation and won't work
+ Fpcr_DepTag = 0,
+ Uniq_DepTag = 0
+ };
+
+ //This makes sure the big endian versions of certain functions are used.
+ using namespace BigEndianGuest;
+
+ typedef uint32_t MachInst;
+ typedef uint64_t ExtMachInst;
+
+ const int NumIntRegs = 32;
+ const int NumFloatRegs = 64;
+ const int NumMiscRegs = 32;
+
+ // semantically meaningful register indices
+ const int ZeroReg = 0; // architecturally meaningful
+ // the rest of these depend on the ABI
+ const int StackPointerReg = 14;
+ const int ReturnAddressReg = 31; // post call, precall is 15
+ const int ReturnValueReg = 8; // Post return, 24 is pre-return.
+ const int FramePointerReg = 30;
+ const int ArgumentReg0 = 8;
+ const int ArgumentReg1 = 9;
+ const int ArgumentReg2 = 10;
+ const int ArgumentReg3 = 11;
+ const int ArgumentReg4 = 12;
+ const int ArgumentReg5 = 13;
+ // Some OS syscall use a second register (o1) to return a second value
+ const int SyscallPseudoReturnReg = ArgumentReg1;
+
+ //XXX These numbers are bogus
+ const int MaxInstSrcRegs = 8;
+ const int MaxInstDestRegs = 9;
+
+ typedef uint64_t IntReg;
+
+ // control register file contents
+ typedef uint64_t MiscReg;
+
+ typedef double FloatReg;
+ typedef uint64_t FloatRegBits;
+
+ //8K. This value is implmentation specific; and should probably
+ //be somewhere else.
+ const int LogVMPageSize = 13;
+ const int VMPageSize = (1 << LogVMPageSize);
+
+ //Why does both the previous set of constants and this one exist?
+ const int PageShift = 13;
+ const int PageBytes = ULL(1) << PageShift;
+
+ const int BranchPredAddrShiftAmt = 2;
+
+ const int MachineBytes = 8;
+ const int WordBytes = 4;
+ const int HalfwordBytes = 2;
+ const int ByteBytes = 1;
+
+ void serialize(std::ostream & os);
+
+ void unserialize(Checkpoint *cp, const std::string &section);
+
+ StaticInstPtr decodeInst(ExtMachInst);
+
+ // return a no-op instruction... used for instruction fetch faults
+ extern const MachInst NoopMachInst;
+}
+
+#include "arch/sparc/regfile.hh"
+
+namespace SparcISA
+{
+
+#if !FULL_SYSTEM
+ static inline void setSyscallReturn(SyscallReturn return_value,
+ RegFile *regs)
+ {
+ // check for error condition. SPARC syscall convention is to
+ // indicate success/failure in reg the carry bit of the ccr
+ // and put the return value itself in the standard return value reg ().
+ if (return_value.successful()) {
+ // no error
+ regs->setMiscReg(MISCREG_CCR_XCC_C, 0);
+ regs->setIntReg(ReturnValueReg, return_value.value());
+ } else {
+ // got an error, return details
+ regs->setMiscReg(MISCREG_CCR_XCC_C, 1);
+ regs->setIntReg(ReturnValueReg, return_value.value());
+ }
+ }
+#endif
+};
+
+#endif // __ARCH_SPARC_ISA_TRAITS_HH__
diff --git a/src/arch/sparc/linux/linux.cc b/src/arch/sparc/linux/linux.cc
new file mode 100644
index 000000000..c7ed29358
--- /dev/null
+++ b/src/arch/sparc/linux/linux.cc
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "arch/sparc/linux/linux.hh"
+
+// open(2) flags translation table
+OpenFlagTransTable SparcLinux::openFlagTable[] = {
+#ifdef _MSC_VER
+ { SparcLinux::TGT_O_RDONLY, _O_RDONLY },
+ { SparcLinux::TGT_O_WRONLY, _O_WRONLY },
+ { SparcLinux::TGT_O_RDWR, _O_RDWR },
+ { SparcLinux::TGT_O_APPEND, _O_APPEND },
+ { SparcLinux::TGT_O_CREAT, _O_CREAT },
+ { SparcLinux::TGT_O_TRUNC, _O_TRUNC },
+ { SparcLinux::TGT_O_EXCL, _O_EXCL },
+#ifdef _O_NONBLOCK
+ { SparcLinux::TGT_O_NONBLOCK, _O_NONBLOCK },
+#endif
+#ifdef _O_NOCTTY
+ { SparcLinux::TGT_O_NOCTTY, _O_NOCTTY },
+#endif
+#ifdef _O_SYNC
+ { SparcLinux::TGT_O_SYNC, _O_SYNC },
+#endif
+#else /* !_MSC_VER */
+ { SparcLinux::TGT_O_RDONLY, O_RDONLY },
+ { SparcLinux::TGT_O_WRONLY, O_WRONLY },
+ { SparcLinux::TGT_O_RDWR, O_RDWR },
+ { SparcLinux::TGT_O_APPEND, O_APPEND },
+ { SparcLinux::TGT_O_CREAT, O_CREAT },
+ { SparcLinux::TGT_O_TRUNC, O_TRUNC },
+ { SparcLinux::TGT_O_EXCL, O_EXCL },
+ { SparcLinux::TGT_O_NONBLOCK, O_NONBLOCK },
+ { SparcLinux::TGT_O_NOCTTY, O_NOCTTY },
+#ifdef O_SYNC
+ { SparcLinux::TGT_O_SYNC, O_SYNC },
+#endif
+#endif /* _MSC_VER */
+};
+
+const int SparcLinux::NUM_OPEN_FLAGS =
+ (sizeof(SparcLinux::openFlagTable)/sizeof(SparcLinux::openFlagTable[0]));
+
diff --git a/src/arch/sparc/linux/linux.hh b/src/arch/sparc/linux/linux.hh
new file mode 100644
index 000000000..9cde5bb9c
--- /dev/null
+++ b/src/arch/sparc/linux/linux.hh
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ARCH_SPARC_LINUX_LINUX_HH__
+#define __ARCH_SPARC_LINUX_LINUX_HH__
+
+#include "kern/linux/linux.hh"
+
+class SparcLinux : public Linux
+{
+ public:
+
+ static OpenFlagTransTable openFlagTable[];
+
+ static const int TGT_O_RDONLY = 0x00000000; //!< O_RDONLY
+ static const int TGT_O_WRONLY = 0x00000001; //!< O_WRONLY
+ static const int TGT_O_RDWR = 0x00000002; //!< O_RDWR
+ static const int TGT_O_NONBLOCK = 0x00004000; //!< O_NONBLOCK
+ static const int TGT_O_APPEND = 0x00000008; //!< O_APPEND
+ static const int TGT_O_CREAT = 0x00000200; //!< O_CREAT
+ static const int TGT_O_TRUNC = 0x00000400; //!< O_TRUNC
+ static const int TGT_O_EXCL = 0x00000800; //!< O_EXCL
+ static const int TGT_O_NOCTTY = 0x00008000; //!< O_NOCTTY
+ static const int TGT_O_SYNC = 0x00002000; //!< O_SYNC
+// static const int TGT_O_DRD = 0x00010000; //!< O_DRD
+// static const int TGT_O_DIRECTIO = 0x00020000; //!< O_DIRECTIO
+// static const int TGT_O_CACHE = 0x00002000; //!< O_CACHE
+// static const int TGT_O_DSYNC = 0x00008000; //!< O_DSYNC
+// static const int TGT_O_RSYNC = 0x00040000; //!< O_RSYNC
+
+ static const int NUM_OPEN_FLAGS;
+
+ static const unsigned TGT_MAP_ANONYMOUS = 0x20;
+};
+
+#endif
diff --git a/src/arch/sparc/linux/process.cc b/src/arch/sparc/linux/process.cc
new file mode 100644
index 000000000..71be6a83a
--- /dev/null
+++ b/src/arch/sparc/linux/process.cc
@@ -0,0 +1,407 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "arch/sparc/isa_traits.hh"
+#include "arch/sparc/linux/process.hh"
+#include "arch/sparc/regfile.hh"
+
+#include "base/trace.hh"
+#include "cpu/exec_context.hh"
+#include "kern/linux/linux.hh"
+
+#include "sim/process.hh"
+#include "sim/syscall_emul.hh"
+
+using namespace std;
+using namespace SparcISA;
+
+
+/// Target uname() handler.
+static SyscallReturn
+unameFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ TypedBufferArg<Linux::utsname> name(xc->getSyscallArg(0));
+
+ strcpy(name->sysname, "Linux");
+ strcpy(name->nodename, "m5.eecs.umich.edu");
+ strcpy(name->release, "2.4.20");
+ strcpy(name->version, "#1 Mon Aug 18 11:32:15 EDT 2003");
+ strcpy(name->machine, "sparc");
+
+ name.copyOut(xc->getMemPort());
+
+ return 0;
+}
+
+
+SyscallReturn SparcISA::getresuidFunc(SyscallDesc *desc, int num,
+ Process *p, ExecContext *xc)
+{
+ const IntReg id = htog(100);
+ Addr ruid = xc->getSyscallArg(0);
+ Addr euid = xc->getSyscallArg(1);
+ Addr suid = xc->getSyscallArg(2);
+ //Handle the EFAULT case
+ //Set the ruid
+ if(ruid)
+ {
+ BufferArg ruidBuff(ruid, sizeof(IntReg));
+ memcpy(ruidBuff.bufferPtr(), &id, sizeof(IntReg));
+ ruidBuff.copyOut(xc->getMemPort());
+ }
+ //Set the euid
+ if(euid)
+ {
+ BufferArg euidBuff(euid, sizeof(IntReg));
+ memcpy(euidBuff.bufferPtr(), &id, sizeof(IntReg));
+ euidBuff.copyOut(xc->getMemPort());
+ }
+ //Set the suid
+ if(suid)
+ {
+ BufferArg suidBuff(suid, sizeof(IntReg));
+ memcpy(suidBuff.bufferPtr(), &id, sizeof(IntReg));
+ suidBuff.copyOut(xc->getMemPort());
+ }
+ return 0;
+}
+
+SyscallDesc SparcLinuxProcess::syscallDescs[] = {
+ /* 0 */ SyscallDesc("restart_syscall", unimplementedFunc),
+ /* 1 */ SyscallDesc("exit", exitFunc),
+ /* 2 */ SyscallDesc("fork", unimplementedFunc),
+ /* 3 */ SyscallDesc("read", readFunc),
+ /* 4 */ SyscallDesc("write", writeFunc),
+ /* 5 */ SyscallDesc("open", openFunc<SparcLinux>),
+ /* 6 */ SyscallDesc("close", closeFunc),
+ /* 7 */ SyscallDesc("wait4", unimplementedFunc),
+ /* 8 */ SyscallDesc("creat", unimplementedFunc),
+ /* 9 */ SyscallDesc("link", unimplementedFunc),
+ /* 10 */ SyscallDesc("unlink", unlinkFunc),
+ /* 11 */ SyscallDesc("execv", unimplementedFunc),
+ /* 12 */ SyscallDesc("chdir", unimplementedFunc),
+ /* 13 */ SyscallDesc("chown", chownFunc),
+ /* 14 */ SyscallDesc("mknod", unimplementedFunc),
+ /* 15 */ SyscallDesc("chmod", chmodFunc<Linux>),
+ /* 16 */ SyscallDesc("lchown", unimplementedFunc),
+ /* 17 */ SyscallDesc("brk", obreakFunc),
+ /* 18 */ SyscallDesc("perfctr", unimplementedFunc),
+ /* 19 */ SyscallDesc("lseek", lseekFunc),
+ /* 20 */ SyscallDesc("getpid", getpidFunc),
+ /* 21 */ SyscallDesc("capget", unimplementedFunc),
+ /* 22 */ SyscallDesc("capset", unimplementedFunc),
+ /* 23 */ SyscallDesc("setuid", setuidFunc),
+ /* 24 */ SyscallDesc("getuid", getuidFunc),
+ /* 25 */ SyscallDesc("time", unimplementedFunc),
+ /* 26 */ SyscallDesc("ptrace", unimplementedFunc),
+ /* 27 */ SyscallDesc("alarm", unimplementedFunc),
+ /* 28 */ SyscallDesc("sigaltstack", unimplementedFunc),
+ /* 29 */ SyscallDesc("pause", unimplementedFunc),
+ /* 30 */ SyscallDesc("utime", unimplementedFunc),
+ /* 31 */ SyscallDesc("lchown32", unimplementedFunc),
+ /* 32 */ SyscallDesc("fchown32", unimplementedFunc),
+ /* 33 */ SyscallDesc("access", unimplementedFunc),
+ /* 34 */ SyscallDesc("nice", unimplementedFunc),
+ /* 35 */ SyscallDesc("chown32", unimplementedFunc),
+ /* 36 */ SyscallDesc("sync", unimplementedFunc),
+ /* 37 */ SyscallDesc("kill", unimplementedFunc),
+ /* 38 */ SyscallDesc("stat", unimplementedFunc),
+ /* 39 */ SyscallDesc("sendfile", unimplementedFunc),
+ /* 40 */ SyscallDesc("lstat", unimplementedFunc),
+ /* 41 */ SyscallDesc("dup", unimplementedFunc),
+ /* 42 */ SyscallDesc("pipe", pipePseudoFunc),
+ /* 43 */ SyscallDesc("times", unimplementedFunc),
+ /* 44 */ SyscallDesc("getuid32", unimplementedFunc),
+ /* 45 */ SyscallDesc("umount2", unimplementedFunc),
+ /* 46 */ SyscallDesc("setgid", unimplementedFunc),
+ /* 47 */ SyscallDesc("getgid", getgidFunc),
+ /* 48 */ SyscallDesc("signal", unimplementedFunc),
+ /* 49 */ SyscallDesc("geteuid", geteuidFunc),
+ /* 50 */ SyscallDesc("getegid", getegidFunc),
+ /* 51 */ SyscallDesc("acct", unimplementedFunc),
+ /* 52 */ SyscallDesc("memory_ordering", unimplementedFunc),
+ /* 53 */ SyscallDesc("getgid32", unimplementedFunc),
+ /* 54 */ SyscallDesc("ioctl", unimplementedFunc),
+ /* 55 */ SyscallDesc("reboot", unimplementedFunc),
+ /* 56 */ SyscallDesc("mmap2", unimplementedFunc),
+ /* 57 */ SyscallDesc("symlink", unimplementedFunc),
+ /* 58 */ SyscallDesc("readlink", unimplementedFunc),
+ /* 59 */ SyscallDesc("execve", unimplementedFunc),
+ /* 60 */ SyscallDesc("umask", unimplementedFunc),
+ /* 61 */ SyscallDesc("chroot", unimplementedFunc),
+ /* 62 */ SyscallDesc("fstat", fstatFunc<SparcLinux>),
+ /* 63 */ SyscallDesc("fstat64", unimplementedFunc),
+ /* 64 */ SyscallDesc("getpagesize", unimplementedFunc),
+ /* 65 */ SyscallDesc("msync", unimplementedFunc),
+ /* 66 */ SyscallDesc("vfork", unimplementedFunc),
+ /* 67 */ SyscallDesc("pread64", unimplementedFunc),
+ /* 68 */ SyscallDesc("pwrite64", unimplementedFunc),
+ /* 69 */ SyscallDesc("geteuid32", unimplementedFunc),
+ /* 70 */ SyscallDesc("getdgid32", unimplementedFunc),
+ /* 71 */ SyscallDesc("mmap", mmapFunc<SparcLinux>),
+ /* 72 */ SyscallDesc("setreuid32", unimplementedFunc),
+ /* 73 */ SyscallDesc("munmap", munmapFunc),
+ /* 74 */ SyscallDesc("mprotect", unimplementedFunc),
+ /* 75 */ SyscallDesc("madvise", unimplementedFunc),
+ /* 76 */ SyscallDesc("vhangup", unimplementedFunc),
+ /* 77 */ SyscallDesc("truncate64", unimplementedFunc),
+ /* 78 */ SyscallDesc("mincore", unimplementedFunc),
+ /* 79 */ SyscallDesc("getgroups", unimplementedFunc),
+ /* 80 */ SyscallDesc("setgroups", unimplementedFunc),
+ /* 81 */ SyscallDesc("getpgrp", unimplementedFunc),
+ /* 82 */ SyscallDesc("setgroups32", unimplementedFunc),
+ /* 83 */ SyscallDesc("setitimer", unimplementedFunc),
+ /* 84 */ SyscallDesc("ftruncate64", unimplementedFunc),
+ /* 85 */ SyscallDesc("swapon", unimplementedFunc),
+ /* 86 */ SyscallDesc("getitimer", unimplementedFunc),
+ /* 87 */ SyscallDesc("setuid32", unimplementedFunc),
+ /* 88 */ SyscallDesc("sethostname", unimplementedFunc),
+ /* 89 */ SyscallDesc("setgid32", unimplementedFunc),
+ /* 90 */ SyscallDesc("dup2", unimplementedFunc),
+ /* 91 */ SyscallDesc("setfsuid32", unimplementedFunc),
+ /* 92 */ SyscallDesc("fcntl", unimplementedFunc),
+ /* 93 */ SyscallDesc("select", unimplementedFunc),
+ /* 94 */ SyscallDesc("setfsgid32", unimplementedFunc),
+ /* 95 */ SyscallDesc("fsync", unimplementedFunc),
+ /* 96 */ SyscallDesc("setpriority", unimplementedFunc),
+ /* 97 */ SyscallDesc("socket", unimplementedFunc),
+ /* 98 */ SyscallDesc("connect", unimplementedFunc),
+ /* 99 */ SyscallDesc("accept", unimplementedFunc),
+ /* 100 */ SyscallDesc("getpriority", unimplementedFunc),
+ /* 101 */ SyscallDesc("rt_sigreturn", unimplementedFunc),
+ /* 102 */ SyscallDesc("rt_sigaction", unimplementedFunc),
+ /* 103 */ SyscallDesc("rt_sigprocmask", unimplementedFunc),
+ /* 104 */ SyscallDesc("rt_sigpending", unimplementedFunc),
+ /* 105 */ SyscallDesc("rt_sigtimedwait", unimplementedFunc),
+ /* 106 */ SyscallDesc("rt_sigqueueinfo", unimplementedFunc),
+ /* 107 */ SyscallDesc("rt_sigsuspend", unimplementedFunc),
+ /* 108 */ SyscallDesc("setresuid", unimplementedFunc),
+ /* 109 */ SyscallDesc("getresuid", getresuidFunc),
+ /* 110 */ SyscallDesc("setresgid", unimplementedFunc),
+ /* 111 */ SyscallDesc("getresgid", unimplementedFunc),
+ /* 112 */ SyscallDesc("setregid32", unimplementedFunc),
+ /* 113 */ SyscallDesc("recvmsg", unimplementedFunc),
+ /* 114 */ SyscallDesc("sendmsg", unimplementedFunc),
+ /* 115 */ SyscallDesc("getgroups32", unimplementedFunc),
+ /* 116 */ SyscallDesc("gettimeofday", unimplementedFunc),
+ /* 117 */ SyscallDesc("getrusage", unimplementedFunc),
+ /* 118 */ SyscallDesc("getsockopt", unimplementedFunc),
+ /* 119 */ SyscallDesc("getcwd", unimplementedFunc),
+ /* 120 */ SyscallDesc("readv", unimplementedFunc),
+ /* 121 */ SyscallDesc("writev", unimplementedFunc),
+ /* 122 */ SyscallDesc("settimeofday", unimplementedFunc),
+ /* 123 */ SyscallDesc("fchown", unimplementedFunc),
+ /* 124 */ SyscallDesc("fchmod", unimplementedFunc),
+ /* 125 */ SyscallDesc("recvfrom", unimplementedFunc),
+ /* 126 */ SyscallDesc("setreuid", unimplementedFunc),
+ /* 127 */ SyscallDesc("setregid", unimplementedFunc),
+ /* 128 */ SyscallDesc("rename", unimplementedFunc),
+ /* 129 */ SyscallDesc("truncate", unimplementedFunc),
+ /* 130 */ SyscallDesc("ftruncate", unimplementedFunc),
+ /* 131 */ SyscallDesc("flock", unimplementedFunc),
+ /* 132 */ SyscallDesc("lstat64", unimplementedFunc),
+ /* 133 */ SyscallDesc("sendto", unimplementedFunc),
+ /* 134 */ SyscallDesc("shutdown", unimplementedFunc),
+ /* 135 */ SyscallDesc("socketpair", unimplementedFunc),
+ /* 136 */ SyscallDesc("mkdir", unimplementedFunc),
+ /* 137 */ SyscallDesc("rmdir", unimplementedFunc),
+ /* 138 */ SyscallDesc("utimes", unimplementedFunc),
+ /* 139 */ SyscallDesc("stat64", unimplementedFunc),
+ /* 140 */ SyscallDesc("sendfile64", unimplementedFunc),
+ /* 141 */ SyscallDesc("getpeername", unimplementedFunc),
+ /* 142 */ SyscallDesc("futex", unimplementedFunc),
+ /* 143 */ SyscallDesc("gettid", unimplementedFunc),
+ /* 144 */ SyscallDesc("getrlimit", unimplementedFunc),
+ /* 145 */ SyscallDesc("setrlimit", unimplementedFunc),
+ /* 146 */ SyscallDesc("pivot_root", unimplementedFunc),
+ /* 147 */ SyscallDesc("prctl", unimplementedFunc),
+ /* 148 */ SyscallDesc("pciconfig_read", unimplementedFunc),
+ /* 149 */ SyscallDesc("pciconfig_write", unimplementedFunc),
+ /* 150 */ SyscallDesc("getsockname", unimplementedFunc),
+ /* 151 */ SyscallDesc("inotify_init", unimplementedFunc),
+ /* 152 */ SyscallDesc("inotify_add_watch", unimplementedFunc),
+ /* 153 */ SyscallDesc("poll", unimplementedFunc),
+ /* 154 */ SyscallDesc("getdents64", unimplementedFunc),
+ /* 155 */ SyscallDesc("fcntl64", unimplementedFunc),
+ /* 156 */ SyscallDesc("inotify_rm_watch", unimplementedFunc),
+ /* 157 */ SyscallDesc("statfs", unimplementedFunc),
+ /* 158 */ SyscallDesc("fstatfs", unimplementedFunc),
+ /* 159 */ SyscallDesc("umount", unimplementedFunc),
+ /* 160 */ SyscallDesc("sched_set_affinity", unimplementedFunc),
+ /* 161 */ SyscallDesc("sched_get_affinity", unimplementedFunc),
+ /* 162 */ SyscallDesc("getdomainname", unimplementedFunc),
+ /* 163 */ SyscallDesc("setdomainname", unimplementedFunc),
+ /* 164 */ SyscallDesc("utrap_install", unimplementedFunc),
+ /* 165 */ SyscallDesc("quotactl", unimplementedFunc),
+ /* 166 */ SyscallDesc("set_tid_address", unimplementedFunc),
+ /* 167 */ SyscallDesc("mount", unimplementedFunc),
+ /* 168 */ SyscallDesc("ustat", unimplementedFunc),
+ /* 169 */ SyscallDesc("setxattr", unimplementedFunc),
+ /* 170 */ SyscallDesc("lsetxattr", unimplementedFunc),
+ /* 171 */ SyscallDesc("fsetxattr", unimplementedFunc),
+ /* 172 */ SyscallDesc("getxattr", unimplementedFunc),
+ /* 173 */ SyscallDesc("lgetxattr", unimplementedFunc),
+ /* 174 */ SyscallDesc("getdents", unimplementedFunc),
+ /* 175 */ SyscallDesc("setsid", unimplementedFunc),
+ /* 176 */ SyscallDesc("fchdir", unimplementedFunc),
+ /* 177 */ SyscallDesc("fgetxattr", unimplementedFunc),
+ /* 178 */ SyscallDesc("listxattr", unimplementedFunc),
+ /* 179 */ SyscallDesc("llistxattr", unimplementedFunc),
+ /* 180 */ SyscallDesc("flistxattr", unimplementedFunc),
+ /* 181 */ SyscallDesc("removexattr", unimplementedFunc),
+ /* 182 */ SyscallDesc("lremovexattr", unimplementedFunc),
+ /* 183 */ SyscallDesc("sigpending", unimplementedFunc),
+ /* 184 */ SyscallDesc("query_module", unimplementedFunc),
+ /* 185 */ SyscallDesc("setpgid", unimplementedFunc),
+ /* 186 */ SyscallDesc("fremovexattr", unimplementedFunc),
+ /* 187 */ SyscallDesc("tkill", unimplementedFunc),
+ /* 188 */ SyscallDesc("exit_group", exitFunc),
+ /* 189 */ SyscallDesc("uname", unameFunc),
+ /* 190 */ SyscallDesc("init_module", unimplementedFunc),
+ /* 191 */ SyscallDesc("personality", unimplementedFunc),
+ /* 192 */ SyscallDesc("remap_file_pages", unimplementedFunc),
+ /* 193 */ SyscallDesc("epoll_create", unimplementedFunc),
+ /* 194 */ SyscallDesc("epoll_ctl", unimplementedFunc),
+ /* 195 */ SyscallDesc("epoll_wait", unimplementedFunc),
+ /* 196 */ SyscallDesc("ioprio_set", unimplementedFunc),
+ /* 197 */ SyscallDesc("getppid", getppidFunc),
+ /* 198 */ SyscallDesc("sigaction", unimplementedFunc),
+ /* 199 */ SyscallDesc("sgetmask", unimplementedFunc),
+ /* 200 */ SyscallDesc("ssetmask", unimplementedFunc),
+ /* 201 */ SyscallDesc("sigsuspend", unimplementedFunc),
+ /* 202 */ SyscallDesc("oldlstat", unimplementedFunc),
+ /* 203 */ SyscallDesc("uselib", unimplementedFunc),
+ /* 204 */ SyscallDesc("readdir", unimplementedFunc),
+ /* 205 */ SyscallDesc("readahead", unimplementedFunc),
+ /* 206 */ SyscallDesc("socketcall", unimplementedFunc),
+ /* 207 */ SyscallDesc("syslog", unimplementedFunc),
+ /* 208 */ SyscallDesc("lookup_dcookie", unimplementedFunc),
+ /* 209 */ SyscallDesc("fadvise64", unimplementedFunc),
+ /* 210 */ SyscallDesc("fadvise64_64", unimplementedFunc),
+ /* 211 */ SyscallDesc("tgkill", unimplementedFunc),
+ /* 212 */ SyscallDesc("waitpid", unimplementedFunc),
+ /* 213 */ SyscallDesc("swapoff", unimplementedFunc),
+ /* 214 */ SyscallDesc("sysinfo", unimplementedFunc),
+ /* 215 */ SyscallDesc("ipc", unimplementedFunc),
+ /* 216 */ SyscallDesc("sigreturn", unimplementedFunc),
+ /* 217 */ SyscallDesc("clone", unimplementedFunc),
+ /* 218 */ SyscallDesc("ioprio_get", unimplementedFunc),
+ /* 219 */ SyscallDesc("adjtimex", unimplementedFunc),
+ /* 220 */ SyscallDesc("sigprocmask", unimplementedFunc),
+ /* 221 */ SyscallDesc("create_module", unimplementedFunc),
+ /* 222 */ SyscallDesc("delete_module", unimplementedFunc),
+ /* 223 */ SyscallDesc("get_kernel_syms", unimplementedFunc),
+ /* 224 */ SyscallDesc("getpgid", unimplementedFunc),
+ /* 225 */ SyscallDesc("bdflush", unimplementedFunc),
+ /* 226 */ SyscallDesc("sysfs", unimplementedFunc),
+ /* 227 */ SyscallDesc("afs_syscall", unimplementedFunc),
+ /* 228 */ SyscallDesc("setfsuid", unimplementedFunc),
+ /* 229 */ SyscallDesc("setfsgid", unimplementedFunc),
+ /* 230 */ SyscallDesc("_newselect", unimplementedFunc),
+ /* 231 */ SyscallDesc("time", unimplementedFunc),
+ /* 232 */ SyscallDesc("oldstat", unimplementedFunc),
+ /* 233 */ SyscallDesc("stime", unimplementedFunc),
+ /* 234 */ SyscallDesc("statfs64", unimplementedFunc),
+ /* 235 */ SyscallDesc("fstatfs64", unimplementedFunc),
+ /* 236 */ SyscallDesc("_llseek", unimplementedFunc),
+ /* 237 */ SyscallDesc("mlock", unimplementedFunc),
+ /* 238 */ SyscallDesc("munlock", unimplementedFunc),
+ /* 239 */ SyscallDesc("mlockall", unimplementedFunc),
+ /* 240 */ SyscallDesc("munlockall", unimplementedFunc),
+ /* 241 */ SyscallDesc("sched_setparam", unimplementedFunc),
+ /* 242 */ SyscallDesc("sched_getparam", unimplementedFunc),
+ /* 243 */ SyscallDesc("sched_setscheduler", unimplementedFunc),
+ /* 244 */ SyscallDesc("sched_getscheduler", unimplementedFunc),
+ /* 245 */ SyscallDesc("sched_yield", unimplementedFunc),
+ /* 246 */ SyscallDesc("sched_get_priority_max", unimplementedFunc),
+ /* 247 */ SyscallDesc("sched_get_priority_min", unimplementedFunc),
+ /* 248 */ SyscallDesc("sched_rr_get_interval", unimplementedFunc),
+ /* 249 */ SyscallDesc("nanosleep", unimplementedFunc),
+ /* 250 */ SyscallDesc("mremap", unimplementedFunc),
+ /* 251 */ SyscallDesc("_sysctl", unimplementedFunc),
+ /* 252 */ SyscallDesc("getsid", unimplementedFunc),
+ /* 253 */ SyscallDesc("fdatasync", unimplementedFunc),
+ /* 254 */ SyscallDesc("nfsservctl", unimplementedFunc),
+ /* 255 */ SyscallDesc("aplib", unimplementedFunc),
+ /* 256 */ SyscallDesc("clock_settime", unimplementedFunc),
+ /* 257 */ SyscallDesc("clock_gettime", unimplementedFunc),
+ /* 258 */ SyscallDesc("clock_getres", unimplementedFunc),
+ /* 259 */ SyscallDesc("clock_nanosleep", unimplementedFunc),
+ /* 260 */ SyscallDesc("sched_getaffinity", unimplementedFunc),
+ /* 261 */ SyscallDesc("sched_setaffinity", unimplementedFunc),
+ /* 262 */ SyscallDesc("timer_settime", unimplementedFunc),
+ /* 263 */ SyscallDesc("timer_gettime", unimplementedFunc),
+ /* 264 */ SyscallDesc("timer_getoverrun", unimplementedFunc),
+ /* 265 */ SyscallDesc("timer_delete", unimplementedFunc),
+ /* 266 */ SyscallDesc("timer_create", unimplementedFunc),
+ /* 267 */ SyscallDesc("vserver", unimplementedFunc),
+ /* 268 */ SyscallDesc("io_setup", unimplementedFunc),
+ /* 269 */ SyscallDesc("io_destroy", unimplementedFunc),
+ /* 270 */ SyscallDesc("io_submit", unimplementedFunc),
+ /* 271 */ SyscallDesc("io_cancel", unimplementedFunc),
+ /* 272 */ SyscallDesc("io_getevents", unimplementedFunc),
+ /* 273 */ SyscallDesc("mq_open", unimplementedFunc),
+ /* 274 */ SyscallDesc("mq_unlink", unimplementedFunc),
+ /* 275 */ SyscallDesc("mq_timedsend", unimplementedFunc),
+ /* 276 */ SyscallDesc("mq_timedreceive", unimplementedFunc),
+ /* 277 */ SyscallDesc("mq_notify", unimplementedFunc),
+ /* 278 */ SyscallDesc("mq_getsetattr", unimplementedFunc),
+ /* 279 */ SyscallDesc("waitid", unimplementedFunc),
+ /* 280 */ SyscallDesc("sys_setaltroot", unimplementedFunc),
+ /* 281 */ SyscallDesc("add_key", unimplementedFunc),
+ /* 282 */ SyscallDesc("request_key", unimplementedFunc),
+ /* 283 */ SyscallDesc("keyctl", unimplementedFunc)
+};
+
+SparcLinuxProcess::SparcLinuxProcess(const std::string &name,
+ ObjectFile *objFile,
+ System * system,
+ int stdin_fd,
+ int stdout_fd,
+ int stderr_fd,
+ std::vector<std::string> &argv,
+ std::vector<std::string> &envp)
+ : SparcLiveProcess(name, objFile, system,
+ stdin_fd, stdout_fd, stderr_fd, argv, envp),
+ Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc))
+{
+ // The sparc syscall table must be <= 284 entries because that is all there
+ // is space for.
+ assert(Num_Syscall_Descs <= 284);
+}
+
+
+
+SyscallDesc*
+SparcLinuxProcess::getDesc(int callnum)
+{
+ if (callnum < 0 || callnum > Num_Syscall_Descs)
+ return NULL;
+ return &syscallDescs[callnum];
+}
diff --git a/src/arch/sparc/linux/process.hh b/src/arch/sparc/linux/process.hh
new file mode 100644
index 000000000..23ce66d02
--- /dev/null
+++ b/src/arch/sparc/linux/process.hh
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2003-2004 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SPARC_LINUX_PROCESS_HH__
+#define __SPARC_LINUX_PROCESS_HH__
+
+#include "arch/sparc/linux/linux.hh"
+#include "arch/sparc/process.hh"
+#include "sim/process.hh"
+
+namespace SparcISA {
+
+/// A process with emulated SPARC/Linux syscalls.
+class SparcLinuxProcess : public SparcLiveProcess
+{
+ public:
+ /// Constructor.
+ SparcLinuxProcess(const std::string &name,
+ ObjectFile *objFile,
+ System * system,
+ int stdin_fd, int stdout_fd, int stderr_fd,
+ std::vector<std::string> &argv,
+ std::vector<std::string> &envp);
+
+ virtual SyscallDesc* getDesc(int callnum);
+
+ /// The target system's hostname.
+ static const char *hostname;
+
+ /// Array of syscall descriptors, indexed by call number.
+ static SyscallDesc syscallDescs[];
+
+ const int Num_Syscall_Descs;
+};
+
+SyscallReturn getresuidFunc(SyscallDesc *desc, int num,
+ Process *p, ExecContext *xc);
+
+} // namespace SparcISA
+#endif // __ALPHA_LINUX_PROCESS_HH__
diff --git a/src/arch/sparc/process.cc b/src/arch/sparc/process.cc
new file mode 100644
index 000000000..250c1bec4
--- /dev/null
+++ b/src/arch/sparc/process.cc
@@ -0,0 +1,388 @@
+/*
+ * Copyright (c) 2003-2004 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "arch/sparc/isa_traits.hh"
+#include "arch/sparc/process.hh"
+#include "arch/sparc/linux/process.hh"
+#include "arch/sparc/solaris/process.hh"
+#include "base/loader/object_file.hh"
+#include "base/misc.hh"
+#include "cpu/exec_context.hh"
+#include "mem/page_table.hh"
+#include "mem/translating_port.hh"
+#include "sim/builder.hh"
+#include "sim/system.hh"
+
+using namespace std;
+using namespace SparcISA;
+
+SparcLiveProcess *
+SparcLiveProcess::create(const std::string &nm, System *system, int stdin_fd,
+ int stdout_fd, int stderr_fd, std::string executable,
+ std::vector<std::string> &argv, std::vector<std::string> &envp)
+{
+ SparcLiveProcess *process = NULL;
+
+ ObjectFile *objFile = createObjectFile(executable);
+ if (objFile == NULL) {
+ fatal("Can't load object file %s", executable);
+ }
+
+
+ if (objFile->getArch() != ObjectFile::SPARC)
+ fatal("Object file with arch %x does not match architecture %x.",
+ objFile->getArch(), ObjectFile::SPARC);
+ switch (objFile->getOpSys()) {
+ case ObjectFile::Linux:
+ process = new SparcLinuxProcess(nm, objFile, system,
+ stdin_fd, stdout_fd, stderr_fd,
+ argv, envp);
+ break;
+
+
+ case ObjectFile::Solaris:
+ process = new SparcSolarisProcess(nm, objFile, system,
+ stdin_fd, stdout_fd, stderr_fd,
+ argv, envp);
+ break;
+ default:
+ fatal("Unknown/unsupported operating system.");
+ }
+
+ if (process == NULL)
+ fatal("Unknown error creating process object.");
+ return process;
+}
+
+SparcLiveProcess::SparcLiveProcess(const std::string &nm, ObjectFile *objFile,
+ System *_system, int stdin_fd, int stdout_fd, int stderr_fd,
+ std::vector<std::string> &argv, std::vector<std::string> &envp)
+ : LiveProcess(nm, objFile, _system, stdin_fd, stdout_fd, stderr_fd,
+ argv, envp)
+{
+
+ // XXX all the below need to be updated for SPARC - Ali
+ brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize();
+ brk_point = roundUp(brk_point, VMPageSize);
+
+ // Set up stack. On SPARC Linux, stack goes from the top of memory
+ // downward, less the hole for the kernel address space.
+ stack_base = ((Addr)0x80000000000ULL);
+
+ // Set up region for mmaps. Tru64 seems to start just above 0 and
+ // grow up from there.
+ mmap_start = mmap_end = 0x800000;
+
+ // Set pointer for next thread stack. Reserve 8M for main stack.
+ next_thread_stack_base = stack_base - (8 * 1024 * 1024);
+}
+
+void
+SparcLiveProcess::startup()
+{
+ argsInit(MachineBytes, VMPageSize);
+
+ //From the SPARC ABI
+
+ //The process runs in user mode
+ execContexts[0]->setMiscRegWithEffect(MISCREG_PSTATE_PRIV, 0);
+ //Interrupts are enabled
+ execContexts[0]->setMiscRegWithEffect(MISCREG_PSTATE_IE, 1);
+ //Round to nearest
+ execContexts[0]->setMiscRegWithEffect(MISCREG_FSR_RD, 0);
+ //Floating point traps are not enabled
+ execContexts[0]->setMiscRegWithEffect(MISCREG_FSR_TEM, 0);
+ //Turn non standard mode off
+ execContexts[0]->setMiscRegWithEffect(MISCREG_FSR_NS, 0);
+ //The floating point queue is empty
+ execContexts[0]->setMiscRegWithEffect(MISCREG_FSR_QNE, 0);
+ //There are no accrued eexecContext[0]eptions
+ execContexts[0]->setMiscRegWithEffect(MISCREG_FSR_AEXC, 0);
+ //There are no current eexecContext[0]eptions
+ execContexts[0]->setMiscRegWithEffect(MISCREG_FSR_CEXC, 0);
+
+ /*
+ * Register window management registers
+ */
+
+ //No windows contain info from other programs
+ execContexts[0]->setMiscRegWithEffect(MISCREG_OTHERWIN, 0);
+ //There are no windows to pop
+ execContexts[0]->setMiscRegWithEffect(MISCREG_CANRESTORE, 0);
+ //All windows are available to save into
+ execContexts[0]->setMiscRegWithEffect(MISCREG_CANSAVE, NWindows - 2);
+ //All windows are "clean"
+ execContexts[0]->setMiscRegWithEffect(MISCREG_CLEANWIN, NWindows);
+ //Start with register window 0
+ execContexts[0]->setMiscRegWithEffect(MISCREG_CWP, 0);
+}
+
+m5_auxv_t buildAuxVect(int64_t type, int64_t val)
+{
+ m5_auxv_t result;
+ result.a_type = TheISA::htog(type);
+ result.a_val = TheISA::htog(val);
+ return result;
+}
+
+void
+SparcLiveProcess::argsInit(int intSize, int pageSize)
+{
+ Process::startup();
+
+ Addr alignmentMask = ~(intSize - 1);
+
+ // load object file into target memory
+ objFile->loadSections(initVirtMem);
+
+ //These are the auxilliary vector types
+ enum auxTypes
+ {
+ SPARC_AT_HWCAP = 16,
+ SPARC_AT_PAGESZ = 6,
+ SPARC_AT_CLKTCK = 17,
+ SPARC_AT_PHDR = 3,
+ SPARC_AT_PHENT = 4,
+ SPARC_AT_PHNUM = 5,
+ SPARC_AT_BASE = 7,
+ SPARC_AT_FLAGS = 8,
+ SPARC_AT_ENTRY = 9,
+ SPARC_AT_UID = 11,
+ SPARC_AT_EUID = 12,
+ SPARC_AT_GID = 13,
+ SPARC_AT_EGID = 14
+ };
+
+ enum hardwareCaps
+ {
+ M5_HWCAP_SPARC_FLUSH = 1,
+ M5_HWCAP_SPARC_STBAR = 2,
+ M5_HWCAP_SPARC_SWAP = 4,
+ M5_HWCAP_SPARC_MULDIV = 8,
+ M5_HWCAP_SPARC_V9 = 16,
+ //This one should technically only be set
+ //if there is a cheetah or cheetah_plus tlb,
+ //but we'll use it all the time
+ M5_HWCAP_SPARC_ULTRA3 = 32
+ };
+
+ const int64_t hwcap =
+ M5_HWCAP_SPARC_FLUSH |
+ M5_HWCAP_SPARC_STBAR |
+ M5_HWCAP_SPARC_SWAP |
+ M5_HWCAP_SPARC_MULDIV |
+ M5_HWCAP_SPARC_V9 |
+ M5_HWCAP_SPARC_ULTRA3;
+
+ //Setup the auxilliary vectors. These will already have
+ //endian conversion.
+ auxv.push_back(buildAuxVect(SPARC_AT_EGID, 100));
+ auxv.push_back(buildAuxVect(SPARC_AT_GID, 100));
+ auxv.push_back(buildAuxVect(SPARC_AT_EUID, 100));
+ auxv.push_back(buildAuxVect(SPARC_AT_UID, 100));
+ //This would work, but the entry point is a protected member
+ //auxv.push_back(buildAuxVect(SPARC_AT_ENTRY, objFile->entry));
+ auxv.push_back(buildAuxVect(SPARC_AT_FLAGS, 0));
+ //This is the address of the elf "interpreter", which I don't
+ //think we currently set up. It should be set to 0 (I think)
+ //auxv.push_back(buildAuxVect(SPARC_AT_BASE, 0));
+ //This is the number of headers which were in the original elf
+ //file. This information isn't avaibale by this point.
+ //auxv.push_back(buildAuxVect(SPARC_AT_PHNUM, 3));
+ //This is the size of a program header entry. This isn't easy
+ //to compute here.
+ //auxv.push_back(buildAuxVect(SPARC_AT_PHENT, blah));
+ //This is should be set to load_addr (whatever that is) +
+ //e_phoff. I think it's a pointer to the program headers.
+ //auxv.push_back(buildAuxVect(SPARC_AT_PHDR, blah));
+ //This should be easy to get right, but I won't set it for now
+ //auxv.push_back(buildAuxVect(SPARC_AT_CLKTCK, blah));
+ auxv.push_back(buildAuxVect(SPARC_AT_PAGESZ, SparcISA::VMPageSize));
+ auxv.push_back(buildAuxVect(SPARC_AT_HWCAP, hwcap));
+
+ //Figure out how big the initial stack needs to be
+
+ //Each auxilliary vector is two 8 byte words
+ int aux_data_size = 2 * intSize * auxv.size();
+ int env_data_size = 0;
+ for (int i = 0; i < envp.size(); ++i) {
+ env_data_size += envp[i].size() + 1;
+ }
+ int arg_data_size = 0;
+ for (int i = 0; i < argv.size(); ++i) {
+ arg_data_size += argv[i].size() + 1;
+ }
+
+ int aux_array_size = intSize * 2 * (auxv.size() + 1);
+
+ int argv_array_size = intSize * (argv.size() + 1);
+ int envp_array_size = intSize * (envp.size() + 1);
+
+ int argc_size = intSize;
+ int window_save_size = intSize * 16;
+
+ int info_block_size =
+ (aux_data_size +
+ env_data_size +
+ arg_data_size +
+ ~alignmentMask) & alignmentMask;
+
+ int info_block_padding =
+ info_block_size -
+ aux_data_size -
+ env_data_size -
+ arg_data_size;
+
+ int space_needed =
+ info_block_size +
+ aux_array_size +
+ envp_array_size +
+ argv_array_size +
+ argc_size +
+ window_save_size;
+
+ stack_min = stack_base - space_needed;
+ stack_min &= alignmentMask;
+ stack_size = stack_base - stack_min;
+
+ // map memory
+ pTable->allocate(roundDown(stack_min, pageSize),
+ roundUp(stack_size, pageSize));
+
+ // map out initial stack contents
+ Addr aux_data_base = stack_base - aux_data_size - info_block_padding;
+ Addr env_data_base = aux_data_base - env_data_size;
+ Addr arg_data_base = env_data_base - arg_data_size;
+ Addr auxv_array_base = arg_data_base - aux_array_size;
+ Addr envp_array_base = auxv_array_base - envp_array_size;
+ Addr argv_array_base = envp_array_base - argv_array_size;
+ Addr argc_base = argv_array_base - argc_size;
+ Addr window_save_base = argc_base - window_save_size;
+
+ DPRINTF(Sparc, "The addresses of items on the initial stack:\n");
+ DPRINTF(Sparc, "0x%x - aux data\n", aux_data_base);
+ DPRINTF(Sparc, "0x%x - env data\n", env_data_base);
+ DPRINTF(Sparc, "0x%x - arg data\n", arg_data_base);
+ DPRINTF(Sparc, "0x%x - auxv array\n", auxv_array_base);
+ DPRINTF(Sparc, "0x%x - envp array\n", envp_array_base);
+ DPRINTF(Sparc, "0x%x - argv array\n", argv_array_base);
+ DPRINTF(Sparc, "0x%x - argc \n", argc_base);
+ DPRINTF(Sparc, "0x%x - window save\n", window_save_base);
+ DPRINTF(Sparc, "0x%x - stack min\n", stack_min);
+
+ // write contents to stack
+ uint64_t argc = argv.size();
+ uint64_t guestArgc = TheISA::htog(argc);
+
+ //Copy the aux stuff
+ for(int x = 0; x < auxv.size(); x++)
+ {
+ initVirtMem->writeBlob(auxv_array_base + x * 2 * intSize,
+ (uint8_t*)&(auxv[x].a_type), intSize);
+ initVirtMem->writeBlob(auxv_array_base + (x * 2 + 1) * intSize,
+ (uint8_t*)&(auxv[x].a_val), intSize);
+ }
+ //Write out the terminating zeroed auxilliary vector
+ const uint64_t zero = 0;
+ initVirtMem->writeBlob(auxv_array_base + 2 * intSize * auxv.size(),
+ (uint8_t*)&zero, 2 * intSize);
+
+ copyStringArray(envp, envp_array_base, env_data_base, initVirtMem);
+ copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem);
+
+ initVirtMem->writeBlob(argc_base, (uint8_t*)&guestArgc, intSize);
+
+ execContexts[0]->setIntReg(ArgumentReg0, argc);
+ execContexts[0]->setIntReg(ArgumentReg1, argv_array_base);
+ execContexts[0]->setIntReg(StackPointerReg, stack_min - StackBias);
+
+ Addr prog_entry = objFile->entryPoint();
+ execContexts[0]->setPC(prog_entry);
+ execContexts[0]->setNextPC(prog_entry + sizeof(MachInst));
+ execContexts[0]->setNextNPC(prog_entry + (2 * sizeof(MachInst)));
+
+// num_processes++;
+}
+
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(SparcLiveProcess)
+
+ VectorParam<string> cmd;
+ Param<string> executable;
+ Param<string> input;
+ Param<string> output;
+ VectorParam<string> env;
+ SimObjectParam<System *> system;
+
+END_DECLARE_SIM_OBJECT_PARAMS(SparcLiveProcess)
+
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(SparcLiveProcess)
+
+ INIT_PARAM(cmd, "command line (executable plus arguments)"),
+ INIT_PARAM(executable, "executable (overrides cmd[0] if set)"),
+ INIT_PARAM(input, "filename for stdin (dflt: use sim stdin)"),
+ INIT_PARAM(output, "filename for stdout/stderr (dflt: use sim stdout)"),
+ INIT_PARAM(env, "environment settings"),
+ INIT_PARAM(system, "system")
+
+END_INIT_SIM_OBJECT_PARAMS(SparcLiveProcess)
+
+
+CREATE_SIM_OBJECT(SparcLiveProcess)
+{
+ string in = input;
+ string out = output;
+
+ // initialize file descriptors to default: same as simulator
+ int stdin_fd, stdout_fd, stderr_fd;
+
+ if (in == "stdin" || in == "cin")
+ stdin_fd = STDIN_FILENO;
+ else
+ stdin_fd = Process::openInputFile(input);
+
+ if (out == "stdout" || out == "cout")
+ stdout_fd = STDOUT_FILENO;
+ else if (out == "stderr" || out == "cerr")
+ stdout_fd = STDERR_FILENO;
+ else
+ stdout_fd = Process::openOutputFile(out);
+
+ stderr_fd = (stdout_fd != STDOUT_FILENO) ? stdout_fd : STDERR_FILENO;
+
+ return SparcLiveProcess::create(getInstanceName(), system,
+ stdin_fd, stdout_fd, stderr_fd,
+ (string)executable == "" ? cmd[0] : executable,
+ cmd, env);
+}
+
+
+REGISTER_SIM_OBJECT("SparcLiveProcess", SparcLiveProcess)
+
+
diff --git a/src/arch/sparc/process.hh b/src/arch/sparc/process.hh
new file mode 100644
index 000000000..c177f20a5
--- /dev/null
+++ b/src/arch/sparc/process.hh
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2003-2004 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SPARC_PROCESS_HH__
+#define __SPARC_PROCESS_HH__
+
+#include <string>
+#include <vector>
+#include "sim/process.hh"
+
+class ObjectFile;
+class System;
+
+typedef struct
+{
+ int64_t a_type;
+ union {
+ int64_t a_val;
+ Addr a_ptr;
+ Addr a_fcn;
+ };
+} m5_auxv_t;
+
+class SparcLiveProcess : public LiveProcess
+{
+ protected:
+
+ static const Addr StackBias = 2047;
+
+ std::vector<m5_auxv_t> auxv;
+
+ SparcLiveProcess(const std::string &nm, ObjectFile *objFile,
+ System *_system, int stdin_fd, int stdout_fd, int stderr_fd,
+ std::vector<std::string> &argv,
+ std::vector<std::string> &envp);
+
+ void startup();
+
+ public:
+ // this function is used to create the LiveProcess object, since
+ // we can't tell which subclass of LiveProcess to use until we
+ // open and look at the object file.
+ static SparcLiveProcess *create(const std::string &nm,
+ System *_system,
+ int stdin_fd, int stdout_fd, int stderr_fd,
+ std::string executable,
+ std::vector<std::string> &argv,
+ std::vector<std::string> &envp);
+
+ void argsInit(int intSize, int pageSize);
+
+};
+
+#endif // __SPARC_PROCESS_HH__
diff --git a/src/arch/sparc/regfile.hh b/src/arch/sparc/regfile.hh
new file mode 100644
index 000000000..5169a332f
--- /dev/null
+++ b/src/arch/sparc/regfile.hh
@@ -0,0 +1,812 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ARCH_SPARC_REGFILE_HH__
+#define __ARCH_SPARC_REGFILE_HH__
+
+#include "arch/sparc/faults.hh"
+#include "base/trace.hh"
+#include "sim/byteswap.hh"
+#include "sim/host.hh"
+
+class Checkpoint;
+
+namespace SparcISA
+{
+
+ typedef uint8_t RegIndex;
+
+ // MAXTL - maximum trap level
+ const int MaxTL = 4;
+
+ // NWINDOWS - number of register windows, can be 3 to 32
+ const int NWindows = 32;
+
+ class IntRegFile
+ {
+ protected:
+ static const int FrameOffsetBits = 3;
+ static const int FrameNumBits = 2;
+
+ static const int RegsPerFrame = 1 << FrameOffsetBits;
+ static const int FrameNumMask =
+ (FrameNumBits == sizeof(int)) ?
+ (unsigned int)(-1) :
+ (1 << FrameNumBits) - 1;
+ static const int FrameOffsetMask =
+ (FrameOffsetBits == sizeof(int)) ?
+ (unsigned int)(-1) :
+ (1 << FrameOffsetBits) - 1;
+
+ IntReg regGlobals[RegsPerFrame];
+ IntReg altGlobals[RegsPerFrame];
+ IntReg regSegments[2 * NWindows][RegsPerFrame];
+
+ enum regFrame {Globals, Outputs, Locals, Inputs, NumFrames};
+
+ IntReg * regView[NumFrames];
+
+ static const int RegGlobalOffset = 0;
+ static const int AltGlobalOffset = 8;
+ static const int FrameOffset = 16;
+ int offset[NumFrames];
+
+ public:
+
+ int flattenIndex(int reg)
+ {
+ int flatIndex = offset[reg >> FrameOffsetBits]
+ | (reg & FrameOffsetMask);
+ DPRINTF(Sparc, "Flattened index %d into %d.\n", reg, flatIndex);
+ return flatIndex;
+ }
+
+ void clear()
+ {
+ bzero(regGlobals, sizeof(regGlobals));
+ bzero(altGlobals, sizeof(altGlobals));
+ for(int x = 0; x < 2 * NWindows; x++)
+ bzero(regSegments[x], sizeof(regSegments[x]));
+ }
+
+ IntRegFile()
+ {
+ offset[Globals] = 0;
+ regView[Globals] = regGlobals;
+ setCWP(0);
+ clear();
+ }
+
+ IntReg readReg(int intReg)
+ {
+ IntReg val =
+ regView[intReg >> FrameOffsetBits][intReg & FrameOffsetMask];
+ DPRINTF(Sparc, "Read register %d = 0x%x\n", intReg, val);
+ return val;
+ }
+
+ Fault setReg(int intReg, const IntReg &val)
+ {
+ if(intReg)
+ DPRINTF(Sparc, "Wrote register %d = 0x%x\n", intReg, val);
+ regView[intReg >> FrameOffsetBits][intReg & FrameOffsetMask] = val;
+ return NoFault;
+ }
+
+ //This doesn't effect the actual CWP register.
+ //It's purpose is to adjust the view of the register file
+ //to what it would be if CWP = cwp.
+ void setCWP(int cwp)
+ {
+ int index = ((NWindows - cwp) % NWindows) * 2;
+ offset[Outputs] = FrameOffset + (index * RegsPerFrame);
+ offset[Locals] = FrameOffset + ((index+1) * RegsPerFrame);
+ offset[Inputs] = FrameOffset +
+ (((index+2) % (NWindows * 2)) * RegsPerFrame);
+ regView[Outputs] = regSegments[index];
+ regView[Locals] = regSegments[index+1];
+ regView[Inputs] = regSegments[(index+2) % (NWindows * 2)];
+
+ DPRINTF(Sparc, "Changed the CWP value to %d\n", cwp);
+ }
+
+ void setAltGlobals(bool useAlt)
+ {
+ DPRINTF(Sparc, "Now using %s globals",
+ useAlt ? "alternate" : "regular");
+ regView[Globals] = useAlt ? altGlobals : regGlobals;
+
+ // You have not included an out-of-class definition of your static
+ // members. See [9.4.2]/4 and about a billion gcc bug reports. If
+ // statements get around the problem through some magic, and than
+ // seems nicer that putting a definition of them in a c file
+ // somewhere.
+ if (useAlt)
+ offset[Globals] = AltGlobalOffset;
+ else
+ offset[Globals] = RegGlobalOffset;
+ }
+
+ void serialize(std::ostream &os);
+
+ void unserialize(Checkpoint *cp, const std::string &section);
+ };
+
+ typedef float float32_t;
+ typedef double float64_t;
+ //FIXME long double refers to a 10 byte float, rather than a
+ //16 byte float as required. This data type may have to be emulated.
+ typedef double float128_t;
+
+ class FloatRegFile
+ {
+ public:
+ static const int SingleWidth = 32;
+ static const int DoubleWidth = 64;
+ static const int QuadWidth = 128;
+
+ protected:
+
+ //Since the floating point registers overlap each other,
+ //A generic storage space is used. The float to be returned is
+ //pulled from the appropriate section of this region.
+ char regSpace[SingleWidth / 8 * NumFloatRegs];
+
+ public:
+
+ void clear()
+ {
+ bzero(regSpace, sizeof(regSpace));
+ }
+
+ FloatReg readReg(int floatReg, int width)
+ {
+ //In each of these cases, we have to copy the value into a temporary
+ //variable. This is because we may otherwise try to access an
+ //unaligned portion of memory.
+ switch(width)
+ {
+ case SingleWidth:
+ float32_t result32;
+ memcpy(&result32, regSpace + 4 * floatReg, width);
+ return htog(result32);
+ case DoubleWidth:
+ float64_t result64;
+ memcpy(&result64, regSpace + 4 * floatReg, width);
+ return htog(result64);
+ case QuadWidth:
+ float128_t result128;
+ memcpy(&result128, regSpace + 4 * floatReg, width);
+ return htog(result128);
+ default:
+ panic("Attempted to read a %d bit floating point register!", width);
+ }
+ }
+
+ FloatRegBits readRegBits(int floatReg, int width)
+ {
+ //In each of these cases, we have to copy the value into a temporary
+ //variable. This is because we may otherwise try to access an
+ //unaligned portion of memory.
+ switch(width)
+ {
+ case SingleWidth:
+ uint32_t result32;
+ memcpy(&result32, regSpace + 4 * floatReg, width);
+ return htog(result32);
+ case DoubleWidth:
+ uint64_t result64;
+ memcpy(&result64, regSpace + 4 * floatReg, width);
+ return htog(result64);
+ case QuadWidth:
+ uint64_t result128;
+ memcpy(&result128, regSpace + 4 * floatReg, width);
+ return htog(result128);
+ default:
+ panic("Attempted to read a %d bit floating point register!", width);
+ }
+ }
+
+ Fault setReg(int floatReg, const FloatReg &val, int width)
+ {
+ //In each of these cases, we have to copy the value into a temporary
+ //variable. This is because we may otherwise try to access an
+ //unaligned portion of memory.
+ switch(width)
+ {
+ case SingleWidth:
+ uint32_t result32 = gtoh((uint32_t)val);
+ memcpy(regSpace + 4 * floatReg, &result32, width);
+ case DoubleWidth:
+ uint64_t result64 = gtoh((uint64_t)val);
+ memcpy(regSpace + 4 * floatReg, &result64, width);
+ case QuadWidth:
+ uint64_t result128 = gtoh((uint64_t)val);
+ memcpy(regSpace + 4 * floatReg, &result128, width);
+ default:
+ panic("Attempted to read a %d bit floating point register!", width);
+ }
+ return NoFault;
+ }
+
+ Fault setRegBits(int floatReg, const FloatRegBits &val, int width)
+ {
+ //In each of these cases, we have to copy the value into a temporary
+ //variable. This is because we may otherwise try to access an
+ //unaligned portion of memory.
+ switch(width)
+ {
+ case SingleWidth:
+ uint32_t result32 = gtoh((uint32_t)val);
+ memcpy(regSpace + 4 * floatReg, &result32, width);
+ case DoubleWidth:
+ uint64_t result64 = gtoh((uint64_t)val);
+ memcpy(regSpace + 4 * floatReg, &result64, width);
+ case QuadWidth:
+ uint64_t result128 = gtoh((uint64_t)val);
+ memcpy(regSpace + 4 * floatReg, &result128, width);
+ default:
+ panic("Attempted to read a %d bit floating point register!", width);
+ }
+ return NoFault;
+ }
+
+ void serialize(std::ostream &os);
+
+ void unserialize(Checkpoint *cp, const std::string &section);
+ };
+
+ enum MiscRegIndex
+ {
+ MISCREG_PSTATE,
+ MISCREG_PSTATE_AG,
+ MISCREG_PSTATE_IE,
+ MISCREG_PSTATE_PRIV,
+ MISCREG_PSTATE_AM,
+ MISCREG_PSTATE_PEF,
+ MISCREG_PSTATE_RED,
+ MISCREG_PSTATE_MM,
+ MISCREG_PSTATE_TLE,
+ MISCREG_PSTATE_CLE,
+ MISCREG_TBA,
+ MISCREG_Y,
+ MISCREG_Y_VALUE,
+ MISCREG_PIL,
+ MISCREG_CWP,
+ MISCREG_TT_BASE,
+ MISCREG_TT_END = MISCREG_TT_BASE + MaxTL,
+ MISCREG_CCR,
+ MISCREG_CCR_ICC,
+ MISCREG_CCR_ICC_C,
+ MISCREG_CCR_ICC_V,
+ MISCREG_CCR_ICC_Z,
+ MISCREG_CCR_ICC_N,
+ MISCREG_CCR_XCC,
+ MISCREG_CCR_XCC_C,
+ MISCREG_CCR_XCC_V,
+ MISCREG_CCR_XCC_Z,
+ MISCREG_CCR_XCC_N,
+ MISCREG_ASI,
+ MISCREG_TL,
+ MISCREG_TPC_BASE,
+ MISCREG_TPC_END = MISCREG_TPC_BASE + MaxTL,
+ MISCREG_TNPC_BASE,
+ MISCREG_TNPC_END = MISCREG_TNPC_BASE + MaxTL,
+ MISCREG_TSTATE_BASE,
+ MISCREG_TSTATE_END = MISCREG_TSTATE_BASE + MaxTL,
+ MISCREG_TSTATE_CWP_BASE,
+ MISCREG_TSTATE_CWP_END = MISCREG_TSTATE_CWP_BASE + MaxTL,
+ MISCREG_TSTATE_PSTATE_BASE,
+ MISCREG_TSTATE_PSTATE_END = MISCREG_TSTATE_PSTATE_BASE + MaxTL,
+ MISCREG_TSTATE_ASI_BASE,
+ MISCREG_TSTATE_ASI_END = MISCREG_TSTATE_ASI_BASE + MaxTL,
+ MISCREG_TSTATE_CCR_BASE,
+ MISCREG_TSTATE_CCR_END = MISCREG_TSTATE_CCR_BASE + MaxTL,
+ MISCREG_TICK,
+ MISCREG_TICK_COUNTER,
+ MISCREG_TICK_NPT,
+ MISCREG_CANSAVE,
+ MISCREG_CANRESTORE,
+ MISCREG_OTHERWIN,
+ MISCREG_CLEANWIN,
+ MISCREG_WSTATE,
+ MISCREG_WSTATE_NORMAL,
+ MISCREG_WSTATE_OTHER,
+ MISCREG_VER,
+ MISCREG_VER_MAXWIN,
+ MISCREG_VER_MAXTL,
+ MISCREG_VER_MASK,
+ MISCREG_VER_IMPL,
+ MISCREG_VER_MANUF,
+ MISCREG_FSR,
+ MISCREG_FSR_CEXC,
+ MISCREG_FSR_CEXC_NXC,
+ MISCREG_FSR_CEXC_DZC,
+ MISCREG_FSR_CEXC_UFC,
+ MISCREG_FSR_CEXC_OFC,
+ MISCREG_FSR_CEXC_NVC,
+ MISCREG_FSR_AEXC,
+ MISCREG_FSR_AEXC_NXC,
+ MISCREG_FSR_AEXC_DZC,
+ MISCREG_FSR_AEXC_UFC,
+ MISCREG_FSR_AEXC_OFC,
+ MISCREG_FSR_AEXC_NVC,
+ MISCREG_FSR_FCC0,
+ MISCREG_FSR_QNE,
+ MISCREG_FSR_FTT,
+ MISCREG_FSR_VER,
+ MISCREG_FSR_NS,
+ MISCREG_FSR_TEM,
+ MISCREG_FSR_TEM_NXM,
+ MISCREG_FSR_TEM_DZM,
+ MISCREG_FSR_TEM_UFM,
+ MISCREG_FSR_TEM_OFM,
+ MISCREG_FSR_TEM_NVM,
+ MISCREG_FSR_RD,
+ MISCREG_FSR_FCC1,
+ MISCREG_FSR_FCC2,
+ MISCREG_FSR_FCC3,
+ MISCREG_FPRS,
+ MISCREG_FPRS_DL,
+ MISCREG_FPRS_DU,
+ MISCREG_FPRS_FEF,
+ numMiscRegs
+ };
+
+ // The control registers, broken out into fields
+ class MiscRegFile
+ {
+ private:
+ union
+ {
+ uint16_t pstate; // Process State Register
+ struct
+ {
+ uint16_t ag:1; // Alternate Globals
+ uint16_t ie:1; // Interrupt enable
+ uint16_t priv:1; // Privelege mode
+ uint16_t am:1; // Address mask
+ uint16_t pef:1; // PSTATE enable floating-point
+ uint16_t red:1; // RED (reset, error, debug) state
+ uint16_t mm:2; // Memory Model
+ uint16_t tle:1; // Trap little-endian
+ uint16_t cle:1; // Current little-endian
+ } pstateFields;
+ };
+ uint64_t tba; // Trap Base Address
+ union
+ {
+ uint64_t y; // Y (used in obsolete multiplication)
+ struct
+ {
+ uint64_t value:32; // The actual value stored in y
+ uint64_t :32; // reserved bits
+ } yFields;
+ };
+ uint8_t pil; // Process Interrupt Register
+ uint8_t cwp; // Current Window Pointer
+ uint16_t tt[MaxTL]; // Trap Type (Type of trap which occured
+ // on the previous level)
+ union
+ {
+ uint8_t ccr; // Condition Code Register
+ struct
+ {
+ union
+ {
+ uint8_t icc:4; // 32-bit condition codes
+ struct
+ {
+ uint8_t c:1; // Carry
+ uint8_t v:1; // Overflow
+ uint8_t z:1; // Zero
+ uint8_t n:1; // Negative
+ } iccFields;
+ };
+ union
+ {
+ uint8_t xcc:4; // 64-bit condition codes
+ struct
+ {
+ uint8_t c:1; // Carry
+ uint8_t v:1; // Overflow
+ uint8_t z:1; // Zero
+ uint8_t n:1; // Negative
+ } xccFields;
+ };
+ } ccrFields;
+ };
+ uint8_t asi; // Address Space Identifier
+ uint8_t tl; // Trap Level
+ uint64_t tpc[MaxTL]; // Trap Program Counter (value from
+ // previous trap level)
+ uint64_t tnpc[MaxTL]; // Trap Next Program Counter (value from
+ // previous trap level)
+ union
+ {
+ uint64_t tstate[MaxTL]; // Trap State
+ struct
+ {
+ //Values are from previous trap level
+ uint64_t cwp:5; // Current Window Pointer
+ uint64_t :2; // Reserved bits
+ uint64_t pstate:10; // Process State
+ uint64_t :6; // Reserved bits
+ uint64_t asi:8; // Address Space Identifier
+ uint64_t ccr:8; // Condition Code Register
+ } tstateFields[MaxTL];
+ };
+ union
+ {
+ uint64_t tick; // Hardware clock-tick counter
+ struct
+ {
+ uint64_t counter:63; // Clock-tick count
+ uint64_t npt:1; // Non-priveleged trap
+ } tickFields;
+ };
+ uint8_t cansave; // Savable windows
+ uint8_t canrestore; // Restorable windows
+ uint8_t otherwin; // Other windows
+ uint8_t cleanwin; // Clean windows
+ union
+ {
+ uint8_t wstate; // Window State
+ struct
+ {
+ uint8_t normal:3; // Bits TT<4:2> are set to on a normal
+ // register window trap
+ uint8_t other:3; // Bits TT<4:2> are set to on an "otherwin"
+ // register window trap
+ } wstateFields;
+ };
+ union
+ {
+ uint64_t ver; // Version
+ struct
+ {
+ uint64_t maxwin:5; // Max CWP value
+ uint64_t :2; // Reserved bits
+ uint64_t maxtl:8; // Maximum trap level
+ uint64_t :8; // Reserved bits
+ uint64_t mask:8; // Processor mask set revision number
+ uint64_t impl:16; // Implementation identification number
+ uint64_t manuf:16; // Manufacturer code
+ } verFields;
+ };
+ union
+ {
+ uint64_t fsr; // Floating-Point State Register
+ struct
+ {
+ union
+ {
+ uint64_t cexc:5; // Current excpetion
+ struct
+ {
+ uint64_t nxc:1; // Inexact
+ uint64_t dzc:1; // Divide by zero
+ uint64_t ufc:1; // Underflow
+ uint64_t ofc:1; // Overflow
+ uint64_t nvc:1; // Invalid operand
+ } cexcFields;
+ };
+ union
+ {
+ uint64_t aexc:5; // Accrued exception
+ struct
+ {
+ uint64_t nxc:1; // Inexact
+ uint64_t dzc:1; // Divide by zero
+ uint64_t ufc:1; // Underflow
+ uint64_t ofc:1; // Overflow
+ uint64_t nvc:1; // Invalid operand
+ } aexcFields;
+ };
+ uint64_t fcc0:2; // Floating-Point condtion codes
+ uint64_t :1; // Reserved bits
+ uint64_t qne:1; // Deferred trap queue not empty
+ // with no queue, it should read 0
+ uint64_t ftt:3; // Floating-Point trap type
+ uint64_t ver:3; // Version (of the FPU)
+ uint64_t :2; // Reserved bits
+ uint64_t ns:1; // Nonstandard floating point
+ union
+ {
+ uint64_t tem:5; // Trap Enable Mask
+ struct
+ {
+ uint64_t nxm:1; // Inexact
+ uint64_t dzm:1; // Divide by zero
+ uint64_t ufm:1; // Underflow
+ uint64_t ofm:1; // Overflow
+ uint64_t nvm:1; // Invalid operand
+ } temFields;
+ };
+ uint64_t :2; // Reserved bits
+ uint64_t rd:2; // Rounding direction
+ uint64_t fcc1:2; // Floating-Point condition codes
+ uint64_t fcc2:2; // Floating-Point condition codes
+ uint64_t fcc3:2; // Floating-Point condition codes
+ uint64_t :26; // Reserved bits
+ } fsrFields;
+ };
+ union
+ {
+ uint8_t fprs; // Floating-Point Register State
+ struct
+ {
+ uint8_t dl:1; // Dirty lower
+ uint8_t du:1; // Dirty upper
+ uint8_t fef:1; // FPRS enable floating-Point
+ } fprsFields;
+ };
+
+ public:
+
+ void reset()
+ {
+ pstateFields.pef = 0; //No FPU
+ //pstateFields.pef = 1; //FPU
+#if FULL_SYSTEM
+ //For SPARC, when a system is first started, there is a power
+ //on reset Trap which sets the processor into the following state.
+ //Bits that aren't set aren't defined on startup.
+ tl = MaxTL;
+ tt[tl] = PowerOnReset.trapType();
+ pstateFields.mm = 0; //Total Store Order
+ pstateFields.red = 1; //Enter RED_State
+ pstateFields.am = 0; //Address Masking is turned off
+ pstateFields.priv = 1; //Processor enters privileged mode
+ pstateFields.ie = 0; //Interrupts are disabled
+ pstateFields.ag = 1; //Globals are replaced with alternate globals
+ pstateFields.tle = 0; //Big Endian mode for traps
+ pstateFields.cle = 0; //Big Endian mode for non-traps
+ tickFields.npt = 1; //The TICK register is unreadable by
+ //non-priveleged software
+#else
+/* //This sets up the initial state of the processor for usermode processes
+ pstateFields.priv = 0; //Process runs in user mode
+ pstateFields.ie = 1; //Interrupts are enabled
+ fsrFields.rd = 0; //Round to nearest
+ fsrFields.tem = 0; //Floating point traps not enabled
+ fsrFields.ns = 0; //Non standard mode off
+ fsrFields.qne = 0; //Floating point queue is empty
+ fsrFields.aexc = 0; //No accrued exceptions
+ fsrFields.cexc = 0; //No current exceptions
+
+ //Register window management registers
+ otherwin = 0; //No windows contain info from other programs
+ canrestore = 0; //There are no windows to pop
+ cansave = MaxTL - 2; //All windows are available to save into
+ cleanwin = MaxTL;*/
+#endif
+ }
+
+ MiscRegFile()
+ {
+ reset();
+ }
+
+ MiscReg readReg(int miscReg);
+
+ MiscReg readRegWithEffect(int miscReg, Fault &fault, ExecContext *xc);
+
+ Fault setReg(int miscReg, const MiscReg &val);
+
+ Fault setRegWithEffect(int miscReg,
+ const MiscReg &val, ExecContext * xc);
+
+ void serialize(std::ostream & os);
+
+ void unserialize(Checkpoint * cp, const std::string & section);
+
+ void copyMiscRegs(ExecContext * xc);
+ };
+
+ typedef union
+ {
+ IntReg intreg;
+ FloatReg fpreg;
+ MiscReg ctrlreg;
+ } AnyReg;
+
+ class RegFile
+ {
+ protected:
+ Addr pc; // Program Counter
+ Addr npc; // Next Program Counter
+ Addr nnpc;
+
+ public:
+ Addr readPC()
+ {
+ return pc;
+ }
+
+ void setPC(Addr val)
+ {
+ pc = val;
+ }
+
+ Addr readNextPC()
+ {
+ return npc;
+ }
+
+ void setNextPC(Addr val)
+ {
+ npc = val;
+ }
+
+ Addr readNextNPC()
+ {
+ return nnpc;
+ }
+
+ void setNextNPC(Addr val)
+ {
+ nnpc = val;
+ }
+
+ protected:
+ IntRegFile intRegFile; // integer register file
+ FloatRegFile floatRegFile; // floating point register file
+ MiscRegFile miscRegFile; // control register file
+
+ public:
+
+ void clear()
+ {
+ intRegFile.clear();
+ floatRegFile.clear();
+ }
+
+ int flattenIntIndex(int reg)
+ {
+ return intRegFile.flattenIndex(reg);
+ }
+
+ MiscReg readMiscReg(int miscReg)
+ {
+ return miscRegFile.readReg(miscReg);
+ }
+
+ MiscReg readMiscRegWithEffect(int miscReg,
+ Fault &fault, ExecContext *xc)
+ {
+ return miscRegFile.readRegWithEffect(miscReg, fault, xc);
+ }
+
+ Fault setMiscReg(int miscReg, const MiscReg &val)
+ {
+ return miscRegFile.setReg(miscReg, val);
+ }
+
+ Fault setMiscRegWithEffect(int miscReg, const MiscReg &val,
+ ExecContext * xc)
+ {
+ return miscRegFile.setRegWithEffect(miscReg, val, xc);
+ }
+
+ FloatReg readFloatReg(int floatReg, int width)
+ {
+ return floatRegFile.readReg(floatReg, width);
+ }
+
+ FloatReg readFloatReg(int floatReg)
+ {
+ //Use the "natural" width of a single float
+ return floatRegFile.readReg(floatReg, FloatRegFile::SingleWidth);
+ }
+
+ FloatRegBits readFloatRegBits(int floatReg, int width)
+ {
+ return floatRegFile.readRegBits(floatReg, width);
+ }
+
+ FloatRegBits readFloatRegBits(int floatReg)
+ {
+ //Use the "natural" width of a single float
+ return floatRegFile.readRegBits(floatReg,
+ FloatRegFile::SingleWidth);
+ }
+
+ Fault setFloatReg(int floatReg, const FloatReg &val, int width)
+ {
+ return floatRegFile.setReg(floatReg, val, width);
+ }
+
+ Fault setFloatReg(int floatReg, const FloatReg &val)
+ {
+ //Use the "natural" width of a single float
+ return setFloatReg(floatReg, val, FloatRegFile::SingleWidth);
+ }
+
+ Fault setFloatRegBits(int floatReg, const FloatRegBits &val, int width)
+ {
+ return floatRegFile.setRegBits(floatReg, val, width);
+ }
+
+ Fault setFloatRegBits(int floatReg, const FloatRegBits &val)
+ {
+ //Use the "natural" width of a single float
+ return floatRegFile.setRegBits(floatReg, val,
+ FloatRegFile::SingleWidth);
+ }
+
+ IntReg readIntReg(int intReg)
+ {
+ return intRegFile.readReg(intReg);
+ }
+
+ Fault setIntReg(int intReg, const IntReg &val)
+ {
+ return intRegFile.setReg(intReg, val);
+ }
+
+ void serialize(std::ostream &os);
+ void unserialize(Checkpoint *cp, const std::string &section);
+
+ public:
+
+ enum ContextParam
+ {
+ CONTEXT_CWP,
+ CONTEXT_GLOBALS
+ };
+
+ union ContextVal
+ {
+ MiscReg reg;
+ bool altGlobals;
+ };
+
+ void changeContext(ContextParam param, ContextVal val)
+ {
+ switch(param)
+ {
+ case CONTEXT_CWP:
+ intRegFile.setCWP(val.reg);
+ break;
+ case CONTEXT_GLOBALS:
+ intRegFile.setAltGlobals(val.altGlobals);
+ break;
+ default:
+ panic("Tried to set illegal context parameter in the SPARC regfile.\n");
+ }
+ }
+ };
+
+ void copyRegs(ExecContext *src, ExecContext *dest);
+
+ void copyMiscRegs(ExecContext *src, ExecContext *dest);
+
+} // namespace SparcISA
+
+#endif
diff --git a/src/arch/sparc/solaris/process.cc b/src/arch/sparc/solaris/process.cc
new file mode 100644
index 000000000..95cdb0bd5
--- /dev/null
+++ b/src/arch/sparc/solaris/process.cc
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "arch/sparc/isa_traits.hh"
+#include "arch/sparc/solaris/process.hh"
+#include "arch/sparc/regfile.hh"
+
+#include "base/trace.hh"
+#include "cpu/exec_context.hh"
+#include "kern/solaris/solaris.hh"
+
+#include "sim/process.hh"
+#include "sim/syscall_emul.hh"
+
+using namespace std;
+using namespace SparcISA;
+
+
+/// Target uname() handler.
+static SyscallReturn
+unameFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ TypedBufferArg<Solaris::utsname> name(xc->getSyscallArg(0));
+
+ strcpy(name->sysname, "SunOS");
+ strcpy(name->nodename, "m5.eecs.umich.edu");
+ strcpy(name->release, "5.9"); //?? do we want this or something newer?
+ strcpy(name->version, "Generic_118558-21");
+ strcpy(name->machine, "sun4u");
+
+ name.copyOut(xc->getMemPort());
+
+ return 0;
+}
+
+
+SyscallDesc SparcSolarisProcess::syscallDescs[] = {
+ /* 0 */ SyscallDesc("syscall", unimplementedFunc),
+ /* 1 */ SyscallDesc("exit", exitFunc),
+ /* 2 */ SyscallDesc("fork", unimplementedFunc),
+ /* 3 */ SyscallDesc("read", readFunc),
+ /* 4 */ SyscallDesc("write", writeFunc),
+ /* 5 */ SyscallDesc("open", openFunc<SparcSolaris>),
+ /* 6 */ SyscallDesc("close", closeFunc),
+ /* 7 */ SyscallDesc("wait", unimplementedFunc),
+ /* 8 */ SyscallDesc("creat", unimplementedFunc),
+ /* 9 */ SyscallDesc("link", unimplementedFunc),
+ /* 10 */ SyscallDesc("unlink", unlinkFunc),
+ /* 11 */ SyscallDesc("exec", unimplementedFunc),
+ /* 12 */ SyscallDesc("chdir", unimplementedFunc),
+ /* 13 */ SyscallDesc("time", unimplementedFunc),
+ /* 14 */ SyscallDesc("mknod", unimplementedFunc),
+ /* 15 */ SyscallDesc("chmod", chmodFunc<Solaris>),
+ /* 16 */ SyscallDesc("chown", chownFunc),
+ /* 17 */ SyscallDesc("brk", obreakFunc),
+ /* 18 */ SyscallDesc("stat", unimplementedFunc),
+ /* 19 */ SyscallDesc("lseek", lseekFunc),
+ /* 20 */ SyscallDesc("getpid", getpidFunc),
+ /* 21 */ SyscallDesc("mount", unimplementedFunc),
+ /* 22 */ SyscallDesc("umount", unimplementedFunc),
+ /* 23 */ SyscallDesc("setuid", setuidFunc),
+ /* 24 */ SyscallDesc("getuid", getuidFunc),
+ /* 25 */ SyscallDesc("stime", unimplementedFunc),
+ /* 26 */ SyscallDesc("pcsample", unimplementedFunc),
+ /* 27 */ SyscallDesc("alarm", unimplementedFunc),
+ /* 28 */ SyscallDesc("fstat", fstatFunc<SparcSolaris>),
+ /* 29 */ SyscallDesc("pause", unimplementedFunc),
+ /* 30 */ SyscallDesc("utime", unimplementedFunc),
+ /* 31 */ SyscallDesc("stty", unimplementedFunc),
+ /* 32 */ SyscallDesc("gtty", unimplementedFunc),
+ /* 33 */ SyscallDesc("access", unimplementedFunc),
+ /* 34 */ SyscallDesc("nice", unimplementedFunc),
+ /* 35 */ SyscallDesc("statfs", unimplementedFunc),
+ /* 36 */ SyscallDesc("sync", unimplementedFunc),
+ /* 37 */ SyscallDesc("kill", unimplementedFunc),
+ /* 38 */ SyscallDesc("fstatfs", unimplementedFunc),
+ /* 39 */ SyscallDesc("pgrpsys", unimplementedFunc),
+ /* 40 */ SyscallDesc("xenix", unimplementedFunc),
+ /* 41 */ SyscallDesc("dup", unimplementedFunc),
+ /* 42 */ SyscallDesc("pipe", pipePseudoFunc),
+ /* 43 */ SyscallDesc("times", unimplementedFunc),
+ /* 44 */ SyscallDesc("profil", unimplementedFunc),
+ /* 45 */ SyscallDesc("plock", unimplementedFunc),
+ /* 46 */ SyscallDesc("setgid", unimplementedFunc),
+ /* 47 */ SyscallDesc("getgid", getgidFunc),
+ /* 48 */ SyscallDesc("signal", unimplementedFunc),
+ /* 49 */ SyscallDesc("msgsys", unimplementedFunc),
+ /* 50 */ SyscallDesc("syssun", unimplementedFunc),
+ /* 51 */ SyscallDesc("acct", unimplementedFunc),
+ /* 52 */ SyscallDesc("shmsys", unimplementedFunc),
+ /* 53 */ SyscallDesc("semsys", unimplementedFunc),
+ /* 54 */ SyscallDesc("ioctl", unimplementedFunc),
+ /* 55 */ SyscallDesc("uadmin", unimplementedFunc),
+ /* 56 */ SyscallDesc("RESERVED", unimplementedFunc),
+ /* 57 */ SyscallDesc("utssys", unimplementedFunc),
+ /* 58 */ SyscallDesc("fdsync", unimplementedFunc),
+ /* 59 */ SyscallDesc("execve", unimplementedFunc),
+ /* 60 */ SyscallDesc("umask", unimplementedFunc),
+ /* 61 */ SyscallDesc("chroot", unimplementedFunc),
+ /* 62 */ SyscallDesc("fcntl", unimplementedFunc),
+ /* 63 */ SyscallDesc("ulimit", unimplementedFunc),
+ /* 64 */ SyscallDesc("reserved_64", unimplementedFunc),
+ /* 65 */ SyscallDesc("reserved_65", unimplementedFunc),
+ /* 66 */ SyscallDesc("reserved_66", unimplementedFunc),
+ /* 67 */ SyscallDesc("reserved_67", unimplementedFunc),
+ /* 68 */ SyscallDesc("reserved_68", unimplementedFunc),
+ /* 69 */ SyscallDesc("reserved_69", unimplementedFunc),
+ /* 70 */ SyscallDesc("tasksys", unimplementedFunc),
+ /* 71 */ SyscallDesc("acctctl", unimplementedFunc),
+ /* 72 */ SyscallDesc("reserved_72", unimplementedFunc),
+ /* 73 */ SyscallDesc("getpagesizes", unimplementedFunc),
+ /* 74 */ SyscallDesc("rctlsys", unimplementedFunc),
+ /* 75 */ SyscallDesc("issetugid", unimplementedFunc),
+ /* 76 */ SyscallDesc("fsat", unimplementedFunc),
+ /* 77 */ SyscallDesc("lwp_park", unimplementedFunc),
+ /* 78 */ SyscallDesc("sendfilev", unimplementedFunc),
+ /* 79 */ SyscallDesc("rmdir", unimplementedFunc),
+ /* 80 */ SyscallDesc("mkdir", unimplementedFunc),
+ /* 81 */ SyscallDesc("getdents", unimplementedFunc),
+ /* 82 */ SyscallDesc("reserved_82", unimplementedFunc),
+ /* 83 */ SyscallDesc("reserved_83", unimplementedFunc),
+ /* 84 */ SyscallDesc("sysfs", unimplementedFunc),
+ /* 85 */ SyscallDesc("getmsg", unimplementedFunc),
+ /* 86 */ SyscallDesc("putmsg", unimplementedFunc),
+ /* 87 */ SyscallDesc("poll", unimplementedFunc),
+ /* 88 */ SyscallDesc("lstat", unimplementedFunc),
+ /* 89 */ SyscallDesc("symlink", unimplementedFunc),
+ /* 90 */ SyscallDesc("readlink", unimplementedFunc),
+ /* 91 */ SyscallDesc("setgroups", unimplementedFunc),
+ /* 92 */ SyscallDesc("getgroups", unimplementedFunc),
+ /* 93 */ SyscallDesc("fchmod", unimplementedFunc),
+ /* 94 */ SyscallDesc("fchown", unimplementedFunc),
+ /* 95 */ SyscallDesc("sigprocmask", unimplementedFunc),
+ /* 96 */ SyscallDesc("sigsuspend", unimplementedFunc),
+ /* 97 */ SyscallDesc("sigaltstack", unimplementedFunc),
+ /* 98 */ SyscallDesc("sigaction", unimplementedFunc),
+ /* 99 */ SyscallDesc("sigpending", unimplementedFunc),
+ /* 100 */ SyscallDesc("context", unimplementedFunc),
+ /* 101 */ SyscallDesc("evsys", unimplementedFunc),
+ /* 102 */ SyscallDesc("evtrapret", unimplementedFunc),
+ /* 103 */ SyscallDesc("statvfs", unimplementedFunc),
+ /* 104 */ SyscallDesc("fstatvfs", unimplementedFunc),
+ /* 105 */ SyscallDesc("getloadavg", unimplementedFunc),
+ /* 106 */ SyscallDesc("nfssys", unimplementedFunc),
+ /* 107 */ SyscallDesc("waitsys", unimplementedFunc),
+ /* 108 */ SyscallDesc("sigsendsys", unimplementedFunc),
+ /* 109 */ SyscallDesc("hrtsys", unimplementedFunc),
+ /* 110 */ SyscallDesc("acancel", unimplementedFunc),
+ /* 111 */ SyscallDesc("async", unimplementedFunc),
+ /* 112 */ SyscallDesc("priocntlsys", unimplementedFunc),
+ /* 113 */ SyscallDesc("pathconf", unimplementedFunc),
+ /* 114 */ SyscallDesc("mincore", unimplementedFunc),
+ /* 115 */ SyscallDesc("mmap", mmapFunc<SparcSolaris>),
+ /* 116 */ SyscallDesc("mprotect", unimplementedFunc),
+ /* 117 */ SyscallDesc("munmap", munmapFunc),
+ /* 118 */ SyscallDesc("fpathconf", unimplementedFunc),
+ /* 119 */ SyscallDesc("vfork", unimplementedFunc),
+ /* 120 */ SyscallDesc("fchdir", unimplementedFunc),
+ /* 121 */ SyscallDesc("readv", unimplementedFunc),
+ /* 122 */ SyscallDesc("writev", unimplementedFunc),
+ /* 123 */ SyscallDesc("xstat", unimplementedFunc),
+ /* 124 */ SyscallDesc("lxstat", unimplementedFunc),
+ /* 125 */ SyscallDesc("fxstat", unimplementedFunc),
+ /* 126 */ SyscallDesc("xmknod", unimplementedFunc),
+ /* 127 */ SyscallDesc("clocal", unimplementedFunc),
+ /* 128 */ SyscallDesc("setrlimit", unimplementedFunc),
+ /* 129 */ SyscallDesc("getrlimit", unimplementedFunc),
+ /* 130 */ SyscallDesc("lchown", unimplementedFunc),
+ /* 131 */ SyscallDesc("memcntl", unimplementedFunc),
+ /* 132 */ SyscallDesc("getpmsg", unimplementedFunc),
+ /* 133 */ SyscallDesc("putpmsg", unimplementedFunc),
+ /* 134 */ SyscallDesc("rename", unimplementedFunc),
+ /* 135 */ SyscallDesc("uname", unameFunc),
+ /* 136 */ SyscallDesc("setegid", unimplementedFunc),
+ /* 137 */ SyscallDesc("sysconfig", unimplementedFunc),
+ /* 138 */ SyscallDesc("adjtime", unimplementedFunc),
+ /* 139 */ SyscallDesc("systeminfo", unimplementedFunc),
+ /* 140 */ SyscallDesc("reserved_140", unimplementedFunc),
+ /* 141 */ SyscallDesc("seteuid", unimplementedFunc),
+ /* 142 */ SyscallDesc("vtrace", unimplementedFunc),
+ /* 143 */ SyscallDesc("fork1", unimplementedFunc),
+ /* 144 */ SyscallDesc("sigtimedwait", unimplementedFunc),
+ /* 145 */ SyscallDesc("lwp_info", unimplementedFunc),
+ /* 146 */ SyscallDesc("yield", unimplementedFunc),
+ /* 147 */ SyscallDesc("lwp_sema_wait", unimplementedFunc),
+ /* 148 */ SyscallDesc("lwp_sema_post", unimplementedFunc),
+ /* 149 */ SyscallDesc("lwp_sema_trywait", unimplementedFunc),
+ /* 150 */ SyscallDesc("lwp_detach", unimplementedFunc),
+ /* 151 */ SyscallDesc("corectl", unimplementedFunc),
+ /* 152 */ SyscallDesc("modctl", unimplementedFunc),
+ /* 153 */ SyscallDesc("fchroot", unimplementedFunc),
+ /* 154 */ SyscallDesc("utimes", unimplementedFunc),
+ /* 155 */ SyscallDesc("vhangup", unimplementedFunc),
+ /* 156 */ SyscallDesc("gettimeofday", unimplementedFunc),
+ /* 157 */ SyscallDesc("getitimer", unimplementedFunc),
+ /* 158 */ SyscallDesc("setitimer", unimplementedFunc),
+ /* 159 */ SyscallDesc("lwp_create", unimplementedFunc),
+ /* 160 */ SyscallDesc("lwp_exit", unimplementedFunc),
+ /* 161 */ SyscallDesc("lwp_suspend", unimplementedFunc),
+ /* 162 */ SyscallDesc("lwp_continue", unimplementedFunc),
+ /* 163 */ SyscallDesc("lwp_kill", unimplementedFunc),
+ /* 164 */ SyscallDesc("lwp_self", unimplementedFunc),
+ /* 165 */ SyscallDesc("lwp_setprivate", unimplementedFunc),
+ /* 166 */ SyscallDesc("lwp_getprivate", unimplementedFunc),
+ /* 167 */ SyscallDesc("lwp_wait", unimplementedFunc),
+ /* 168 */ SyscallDesc("lwp_mutex_wakeup", unimplementedFunc),
+ /* 169 */ SyscallDesc("lwp_mutex_lock", unimplementedFunc),
+ /* 170 */ SyscallDesc("lwp_cond_wait", unimplementedFunc),
+ /* 171 */ SyscallDesc("lwp_cond_signal", unimplementedFunc),
+ /* 172 */ SyscallDesc("lwp_cond_broadcast", unimplementedFunc),
+ /* 173 */ SyscallDesc("pread", unimplementedFunc),
+ /* 174 */ SyscallDesc("pwrite", unimplementedFunc),
+ /* 175 */ SyscallDesc("llseek", unimplementedFunc),
+ /* 176 */ SyscallDesc("inst_sync", unimplementedFunc),
+ /* 177 */ SyscallDesc("srmlimitsys", unimplementedFunc),
+ /* 178 */ SyscallDesc("kaio", unimplementedFunc),
+ /* 179 */ SyscallDesc("cpc", unimplementedFunc),
+ /* 180 */ SyscallDesc("lgrpsys_meminfosys", unimplementedFunc),
+ /* 181 */ SyscallDesc("rusagesys", unimplementedFunc),
+ /* 182 */ SyscallDesc("reserved_182", unimplementedFunc),
+ /* 183 */ SyscallDesc("reserved_183", unimplementedFunc),
+ /* 184 */ SyscallDesc("tsolsys", unimplementedFunc),
+ /* 185 */ SyscallDesc("acl", unimplementedFunc),
+ /* 186 */ SyscallDesc("auditsys", unimplementedFunc),
+ /* 187 */ SyscallDesc("processor_bind", unimplementedFunc),
+ /* 188 */ SyscallDesc("processor_info", unimplementedFunc),
+ /* 189 */ SyscallDesc("p_online", unimplementedFunc),
+ /* 190 */ SyscallDesc("sigqueue", unimplementedFunc),
+ /* 191 */ SyscallDesc("clock_gettime", unimplementedFunc),
+ /* 192 */ SyscallDesc("clock_settime", unimplementedFunc),
+ /* 193 */ SyscallDesc("clock_getres", unimplementedFunc),
+ /* 194 */ SyscallDesc("timer_create", unimplementedFunc),
+ /* 195 */ SyscallDesc("timer_delete", unimplementedFunc),
+ /* 196 */ SyscallDesc("timer_settime", unimplementedFunc),
+ /* 197 */ SyscallDesc("timer_gettime", unimplementedFunc),
+ /* 198 */ SyscallDesc("timer_getoverrun", unimplementedFunc),
+ /* 199 */ SyscallDesc("nanosleep", unimplementedFunc),
+ /* 200 */ SyscallDesc("facl", unimplementedFunc),
+ /* 201 */ SyscallDesc("door", unimplementedFunc),
+ /* 202 */ SyscallDesc("setreuid", unimplementedFunc),
+ /* 203 */ SyscallDesc("setregid", unimplementedFunc),
+ /* 204 */ SyscallDesc("install_utrap", unimplementedFunc),
+ /* 205 */ SyscallDesc("signotify", unimplementedFunc),
+ /* 206 */ SyscallDesc("schedctl", unimplementedFunc),
+ /* 207 */ SyscallDesc("pset", unimplementedFunc),
+ /* 208 */ SyscallDesc("sparc_utrap_install", unimplementedFunc),
+ /* 209 */ SyscallDesc("resolvepath", unimplementedFunc),
+ /* 210 */ SyscallDesc("signotifywait", unimplementedFunc),
+ /* 211 */ SyscallDesc("lwp_sigredirect", unimplementedFunc),
+ /* 212 */ SyscallDesc("lwp_alarm", unimplementedFunc),
+ /* 213 */ SyscallDesc("getdents64", unimplementedFunc),
+ /* 214 */ SyscallDesc("mmap64", unimplementedFunc),
+ /* 215 */ SyscallDesc("stat64", unimplementedFunc),
+ /* 216 */ SyscallDesc("lstat64", unimplementedFunc),
+ /* 217 */ SyscallDesc("fstat64", unimplementedFunc),
+ /* 218 */ SyscallDesc("statvfs64", unimplementedFunc),
+ /* 219 */ SyscallDesc("fstatvfs64", unimplementedFunc),
+ /* 220 */ SyscallDesc("setrlimit64", unimplementedFunc),
+ /* 221 */ SyscallDesc("getrlimit64", unimplementedFunc),
+ /* 222 */ SyscallDesc("pread64", unimplementedFunc),
+ /* 223 */ SyscallDesc("pwrite64", unimplementedFunc),
+ /* 224 */ SyscallDesc("creat64", unimplementedFunc),
+ /* 225 */ SyscallDesc("open64", unimplementedFunc),
+ /* 226 */ SyscallDesc("rpcsys", unimplementedFunc),
+ /* 227 */ SyscallDesc("reserved_227", unimplementedFunc),
+ /* 228 */ SyscallDesc("reserved_228", unimplementedFunc),
+ /* 229 */ SyscallDesc("reserved_229", unimplementedFunc),
+ /* 230 */ SyscallDesc("so_socket", unimplementedFunc),
+ /* 231 */ SyscallDesc("so_socketpair", unimplementedFunc),
+ /* 232 */ SyscallDesc("bind", unimplementedFunc),
+ /* 233 */ SyscallDesc("listen", unimplementedFunc),
+ /* 234 */ SyscallDesc("accept", unimplementedFunc),
+ /* 235 */ SyscallDesc("connect", unimplementedFunc),
+ /* 236 */ SyscallDesc("shutdown", unimplementedFunc),
+ /* 237 */ SyscallDesc("recv", unimplementedFunc),
+ /* 238 */ SyscallDesc("recvfrom", unimplementedFunc),
+ /* 239 */ SyscallDesc("recvmsg", unimplementedFunc),
+ /* 240 */ SyscallDesc("send", unimplementedFunc),
+ /* 241 */ SyscallDesc("sendmsg", unimplementedFunc),
+ /* 242 */ SyscallDesc("sendto", unimplementedFunc),
+ /* 243 */ SyscallDesc("getpeername", unimplementedFunc),
+ /* 244 */ SyscallDesc("getsockname", unimplementedFunc),
+ /* 245 */ SyscallDesc("getsockopt", unimplementedFunc),
+ /* 246 */ SyscallDesc("setsockopt", unimplementedFunc),
+ /* 247 */ SyscallDesc("sockconfig", unimplementedFunc),
+ /* 248 */ SyscallDesc("ntp_gettime", unimplementedFunc),
+ /* 249 */ SyscallDesc("ntp_adjtime", unimplementedFunc),
+ /* 250 */ SyscallDesc("lwp_mutex_unlock", unimplementedFunc),
+ /* 251 */ SyscallDesc("lwp_mutex_trylock", unimplementedFunc),
+ /* 252 */ SyscallDesc("lwp_mutex_init", unimplementedFunc),
+ /* 253 */ SyscallDesc("cladm", unimplementedFunc),
+ /* 254 */ SyscallDesc("lwp_sigtimedwait", unimplementedFunc),
+ /* 255 */ SyscallDesc("umount2", unimplementedFunc)
+};
+
+SparcSolarisProcess::SparcSolarisProcess(const std::string &name,
+ ObjectFile *objFile,
+ System * system,
+ int stdin_fd,
+ int stdout_fd,
+ int stderr_fd,
+ std::vector<std::string> &argv,
+ std::vector<std::string> &envp)
+ : SparcLiveProcess(name, objFile, system,
+ stdin_fd, stdout_fd, stderr_fd, argv, envp),
+ Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc))
+{
+ // The sparc syscall table must be <= 284 entries because that is all there
+ // is space for.
+ assert(Num_Syscall_Descs <= 284);
+}
+
+
+
+SyscallDesc*
+SparcSolarisProcess::getDesc(int callnum)
+{
+ if (callnum < 0 || callnum > Num_Syscall_Descs)
+ return NULL;
+ return &syscallDescs[callnum];
+}
diff --git a/src/arch/sparc/solaris/process.hh b/src/arch/sparc/solaris/process.hh
new file mode 100644
index 000000000..24dffdaf0
--- /dev/null
+++ b/src/arch/sparc/solaris/process.hh
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2003-2004 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SPARC_SOLARIS_PROCESS_HH__
+#define __SPARC_SOLARIS_PROCESS_HH__
+
+#include "arch/sparc/solaris/solaris.hh"
+#include "arch/sparc/process.hh"
+#include "sim/process.hh"
+
+namespace SparcISA {
+
+/// A process with emulated SPARC/Solaris syscalls.
+class SparcSolarisProcess : public SparcLiveProcess
+{
+ public:
+ /// Constructor.
+ SparcSolarisProcess(const std::string &name,
+ ObjectFile *objFile,
+ System * system,
+ int stdin_fd, int stdout_fd, int stderr_fd,
+ std::vector<std::string> &argv,
+ std::vector<std::string> &envp);
+
+ virtual SyscallDesc* getDesc(int callnum);
+
+ /// The target system's hostname.
+ static const char *hostname;
+
+ /// Array of syscall descriptors, indexed by call number.
+ static SyscallDesc syscallDescs[];
+
+ const int Num_Syscall_Descs;
+};
+
+
+} // namespace SparcISA
+#endif // __ALPHA_SOLARIS_PROCESS_HH__
diff --git a/src/arch/sparc/solaris/solaris.cc b/src/arch/sparc/solaris/solaris.cc
new file mode 100644
index 000000000..a56f10740
--- /dev/null
+++ b/src/arch/sparc/solaris/solaris.cc
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "arch/sparc/solaris/solaris.hh"
+
+// open(2) flags translation table
+OpenFlagTransTable SparcSolaris::openFlagTable[] = {
+#ifdef _MSC_VER
+ { SparcSolaris::TGT_O_RDONLY, _O_RDONLY },
+ { SparcSolaris::TGT_O_WRONLY, _O_WRONLY },
+ { SparcSolaris::TGT_O_RDWR, _O_RDWR },
+ { SparcSolaris::TGT_O_APPEND, _O_APPEND },
+ { SparcSolaris::TGT_O_CREAT, _O_CREAT },
+ { SparcSolaris::TGT_O_TRUNC, _O_TRUNC },
+ { SparcSolaris::TGT_O_EXCL, _O_EXCL },
+#ifdef _O_NONBLOCK
+ { SparcSolaris::TGT_O_NONBLOCK, _O_NONBLOCK },
+ { SparcSolaris::TGT_O_NDELAY , _O_NONBLOCK },
+#endif
+#ifdef _O_NOCTTY
+ { SparcSolaris::TGT_O_NOCTTY, _O_NOCTTY },
+#endif
+#ifdef _O_SYNC
+ { SparcSolaris::TGT_O_SYNC, _O_SYNC },
+ { SparcSolaris::TGT_O_DSYNC, _O_SYNC },
+ { SparcSolaris::TGT_O_RSYNC, _O_SYNC },
+#endif
+#else /* !_MSC_VER */
+ { SparcSolaris::TGT_O_RDONLY, O_RDONLY },
+ { SparcSolaris::TGT_O_WRONLY, O_WRONLY },
+ { SparcSolaris::TGT_O_RDWR, O_RDWR },
+ { SparcSolaris::TGT_O_APPEND, O_APPEND },
+ { SparcSolaris::TGT_O_CREAT, O_CREAT },
+ { SparcSolaris::TGT_O_TRUNC, O_TRUNC },
+ { SparcSolaris::TGT_O_EXCL, O_EXCL },
+ { SparcSolaris::TGT_O_NONBLOCK, O_NONBLOCK },
+ { SparcSolaris::TGT_O_NDELAY , O_NONBLOCK },
+ { SparcSolaris::TGT_O_NOCTTY, O_NOCTTY },
+#ifdef O_SYNC
+ { SparcSolaris::TGT_O_SYNC, O_SYNC },
+ { SparcSolaris::TGT_O_DSYNC, O_SYNC },
+ { SparcSolaris::TGT_O_RSYNC, O_SYNC },
+#endif
+#endif /* _MSC_VER */
+};
+
+const int SparcSolaris::NUM_OPEN_FLAGS =
+ (sizeof(SparcSolaris::openFlagTable)/sizeof(SparcSolaris::openFlagTable[0]));
+
diff --git a/src/arch/sparc/solaris/solaris.hh b/src/arch/sparc/solaris/solaris.hh
new file mode 100644
index 000000000..6833a2d6a
--- /dev/null
+++ b/src/arch/sparc/solaris/solaris.hh
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ARCH_SPARC_SOLARIS_SOLARIS_HH__
+#define __ARCH_SPARC_SOLARIS_SOLARIS_HH__
+
+#include "kern/solaris/solaris.hh"
+
+class SparcSolaris : public Solaris
+{
+ public:
+
+ static OpenFlagTransTable openFlagTable[];
+
+ static const int TGT_O_RDONLY = 0x00000000; //!< O_RDONLY
+ static const int TGT_O_WRONLY = 0x00000001; //!< O_WRONLY
+ static const int TGT_O_RDWR = 0x00000002; //!< O_RDWR
+ static const int TGT_O_NDELAY = 0x00000004; //!< O_NONBLOCK
+ static const int TGT_O_APPEND = 0x00000008; //!< O_APPEND
+ static const int TGT_O_SYNC = 0x00000010; //!< O_SYNC
+ static const int TGT_O_DSYNC = 0x00000040; //!< O_SYNC
+ static const int TGT_O_RSYNC = 0x00008000; //!< O_SYNC
+ static const int TGT_O_NONBLOCK = 0x00000080; //!< O_NONBLOCK
+ static const int TGT_O_PRIV = 0x00001000; //??
+ static const int TGT_O_LARGEFILE = 0x00002000; //??
+ static const int TGT_O_CREAT = 0x00000100; //!< O_CREAT
+ static const int TGT_O_TRUNC = 0x00000200; //!< O_TRUNC
+ static const int TGT_O_EXCL = 0x00000400; //!< O_EXCL
+ static const int TGT_O_NOCTTY = 0x00000800; //!< O_NOCTTY
+ static const int TGT_O_XATTR = 0x00004000; //??
+
+ static const int NUM_OPEN_FLAGS;
+
+ static const unsigned TGT_MAP_ANONYMOUS = 0x100;
+};
+
+#endif
diff --git a/src/arch/sparc/stacktrace.hh b/src/arch/sparc/stacktrace.hh
new file mode 100644
index 000000000..1d8d97a79
--- /dev/null
+++ b/src/arch/sparc/stacktrace.hh
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ARCH_ALPHA_STACKTRACE_HH__
+#define __ARCH_ALPHA_STACKTRACE_HH__
+
+#include "base/trace.hh"
+#include "cpu/static_inst.hh"
+
+class ExecContext;
+class StackTrace;
+
+class ProcessInfo
+{
+ private:
+ ExecContext *xc;
+
+ int thread_info_size;
+ int task_struct_size;
+ int task_off;
+ int pid_off;
+ int name_off;
+
+ public:
+ ProcessInfo(ExecContext *_xc);
+
+ Addr task(Addr ksp) const;
+ int pid(Addr ksp) const;
+ std::string name(Addr ksp) const;
+};
+
+class StackTrace
+{
+ protected:
+ typedef TheISA::MachInst MachInst;
+ private:
+ ExecContext *xc;
+ std::vector<Addr> stack;
+
+ private:
+ bool isEntry(Addr addr);
+ bool decodePrologue(Addr sp, Addr callpc, Addr func, int &size, Addr &ra);
+ bool decodeSave(MachInst inst, int &reg, int &disp);
+ bool decodeStack(MachInst inst, int &disp);
+
+ void trace(ExecContext *xc, bool is_call);
+
+ public:
+ StackTrace();
+ StackTrace(ExecContext *xc, StaticInstPtr inst);
+ ~StackTrace();
+
+ void clear()
+ {
+ xc = 0;
+ stack.clear();
+ }
+
+ bool valid() const { return xc != NULL; }
+ bool trace(ExecContext *xc, StaticInstPtr inst);
+
+ public:
+ const std::vector<Addr> &getstack() const { return stack; }
+
+ static const int user = 1;
+ static const int console = 2;
+ static const int unknown = 3;
+
+#if TRACING_ON
+ private:
+ void dump();
+
+ public:
+ void dprintf() { if (DTRACE(Stack)) dump(); }
+#else
+ public:
+ void dprintf() {}
+#endif
+};
+
+inline bool
+StackTrace::trace(ExecContext *xc, StaticInstPtr inst)
+{
+ if (!inst->isCall() && !inst->isReturn())
+ return false;
+
+ if (valid())
+ clear();
+
+ trace(xc, !inst->isReturn());
+ return true;
+}
+
+#endif // __ARCH_ALPHA_STACKTRACE_HH__
diff --git a/src/arch/sparc/system.cc b/src/arch/sparc/system.cc
new file mode 100644
index 000000000..1e2882607
--- /dev/null
+++ b/src/arch/sparc/system.cc
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2002-2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "arch/sparc/system.hh"
+#include "arch/vtophys.hh"
+#include "base/remote_gdb.hh"
+#include "base/loader/object_file.hh"
+#include "base/loader/symtab.hh"
+#include "base/trace.hh"
+#include "mem/physical.hh"
+#include "sim/byteswap.hh"
+#include "sim/builder.hh"
+
+
+using namespace BigEndianGuest;
+
+SparcSystem::SparcSystem(Params *p)
+ : System(p)
+{
+ resetSymtab = new SymbolTable;
+ hypervisorSymtab = new SymbolTable;
+ openbootSymtab = new SymbolTable;
+
+
+ /**
+ * Load the boot code, and hypervisor into memory.
+ */
+ // Read the reset binary
+ reset = createObjectFile(params()->reset_bin);
+ if (reset == NULL)
+ fatal("Could not load reset binary %s", params()->reset_bin);
+
+ // Read the openboot binary
+ openboot = createObjectFile(params()->openboot_bin);
+ if (openboot == NULL)
+ fatal("Could not load openboot bianry %s", params()->openboot_bin);
+
+ // Read the hypervisor binary
+ hypervisor = createObjectFile(params()->hypervisor_bin);
+ if (hypervisor == NULL)
+ fatal("Could not load hypervisor binary %s", params()->hypervisor_bin);
+
+
+ // Load reset binary into memory
+ reset->loadSections(&functionalPort, SparcISA::LoadAddrMask);
+ // Load the openboot binary
+ openboot->loadSections(&functionalPort, SparcISA::LoadAddrMask);
+ // Load the hypervisor binary
+ hypervisor->loadSections(&functionalPort, SparcISA::LoadAddrMask);
+
+ // load symbols
+ if (!reset->loadGlobalSymbols(reset))
+ panic("could not load reset symbols\n");
+
+ if (!openboot->loadGlobalSymbols(openbootSymtab))
+ panic("could not load openboot symbols\n");
+
+ if (!hypervisor->loadLocalSymbols(hypervisorSymtab))
+ panic("could not load hypervisor symbols\n");
+
+ // load symbols into debug table
+ if (!reset->loadGlobalSymbols(debugSymbolTable))
+ panic("could not load reset symbols\n");
+
+ if (!openboot->loadGlobalSymbols(debugSymbolTable))
+ panic("could not load openboot symbols\n");
+
+ if (!hypervisor->loadLocalSymbols(debugSymbolTable))
+ panic("could not load hypervisor symbols\n");
+
+
+ // @todo any fixup code over writing data in binaries on setting break
+ // events on functions should happen here.
+
+}
+
+SparcSystem::~SparcSystem()
+{
+ delete resetSymtab;
+ delete hypervisorSymtab;
+ delete openbootSymtab;
+ delete reset;
+ delete openboot;
+ delete hypervisor;
+}
+
+bool
+SparcSystem::breakpoint()
+{
+ panic("Need to implement");
+}
+
+void
+SparcSystem::serialize(std::ostream &os)
+{
+ System::serialize(os);
+ resetSymtab->serialize("reset_symtab", os);
+ hypervisorSymtab->serialize("hypervisor_symtab", os);
+ openbootSymtab->serialize("openboot_symtab", os);
+}
+
+
+void
+SparcSystem::unserialize(Checkpoint *cp, const std::string &section)
+{
+ System::unserialize(cp,section);
+ resetSymtab->unserialize("reset_symtab", cp, section);
+ hypervisorSymtab->unserialize("hypervisor_symtab", cp, section);
+ openbootSymtab->unserialize("openboot_symtab", cp, section);
+}
+
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(SparcSystem)
+
+ SimObjectParam<PhysicalMemory *> physmem;
+
+ Param<std::string> kernel;
+ Param<std::string> reset_bin;
+ Param<std::string> hypervisor_bin;
+ Param<std::string> openboot_bin;
+
+ Param<std::string> boot_osflags;
+ Param<std::string> readfile;
+ Param<unsigned int> init_param;
+
+ Param<bool> bin;
+ VectorParam<std::string> binned_fns;
+ Param<bool> bin_int;
+
+END_DECLARE_SIM_OBJECT_PARAMS(SparcSystem)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(SparcSystem)
+
+ INIT_PARAM(boot_cpu_frequency, "Frequency of the boot CPU"),
+ INIT_PARAM(physmem, "phsyical memory"),
+ INIT_PARAM(kernel, "file that contains the kernel code"),
+ INIT_PARAM(reset_bin, "file that contains the reset code"),
+ INIT_PARAM(hypervisor_bin, "file that contains the hypervisor code"),
+ INIT_PARAM(openboot_bin, "file that contains the openboot code"),
+ INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot",
+ "a"),
+ INIT_PARAM_DFLT(readfile, "file to read startup script from", ""),
+ INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0),
+ INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 34),
+ INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10),
+ INIT_PARAM_DFLT(bin, "is this system to be binned", false),
+ INIT_PARAM(binned_fns, "functions to be broken down and binned"),
+ INIT_PARAM_DFLT(bin_int, "is interrupt code binned seperately?", true)
+
+END_INIT_SIM_OBJECT_PARAMS(SparcSystem)
+
+CREATE_SIM_OBJECT(SparcSystem)
+{
+ SparcSystem::Params *p = new SparcSystem::Params;
+ p->name = getInstanceName();
+ p->boot_cpu_frequency = boot_cpu_frequency;
+ p->physmem = physmem;
+ p->kernel_path = kernel;
+ p->reset_bin = reset_bin;
+ p->hypervisor_bin = hypervisor_bin;
+ p->openboot_bin = openboot_bin;
+ p->boot_osflags = boot_osflags;
+ p->init_param = init_param;
+ p->readfile = readfile;
+ p->system_type = system_type;
+ p->system_rev = system_rev;
+ p->bin = bin;
+ p->binned_fns = binned_fns;
+ p->bin_int = bin_int;
+ return new SparcSystem(p);
+}
+
+REGISTER_SIM_OBJECT("SparcSystem", SparcSystem)
+
+
diff --git a/src/arch/sparc/system.hh b/src/arch/sparc/system.hh
new file mode 100644
index 000000000..27aa8768a
--- /dev/null
+++ b/src/arch/sparc/system.hh
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ARCH_SPARC_SYSTEM_HH__
+#define __ARCH_SPARC_SYSTEM_HH__
+
+#include <string>
+#include <vector>
+
+#include "base/loader/symtab.hh"
+#include "cpu/pc_event.hh"
+#include "kern/system_events.hh"
+#include "sim/sim_object.hh"
+#include "sim/system.hh"
+
+class SparcSystem : public System
+{
+ public:
+ struct Params : public System::Params
+ {
+ std::string reset_bin;
+ std::string hypervison_bin;
+ std::string openboot_bin;
+ std::string boot_osflags;
+ uint64_t system_type;
+ uint64_t system_rev;
+ };
+
+ SparcSystem(Params *p);
+
+ ~SparcaSystem();
+
+ virtual bool breakpoint();
+
+/**
+ * Serialization stuff
+ */
+ public:
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+
+ /** reset binary symbol table */
+ SymbolTable *resetSymtab;
+
+ /** hypervison binary symbol table */
+ SymbolTable *hypervisorSymtab;
+
+ /** openboot symbol table */
+ SymbolTable *openbootSymtab;
+
+ /** Object pointer for the reset binary */
+ ObjectFile *reset;
+
+ /** Object pointer for the hypervisor code */
+ ObjectFile *hypervisor;
+
+ /** Object pointer for the openboot code */
+ ObjectFile *openboot;
+
+ protected:
+ const Params *params() const { return (const Params *)_params; }
+
+ /** Add a function-based event to reset binary. */
+ template <class T>
+ T *SparcSystem::addResetFuncEvent(const char *lbl)
+ {
+ return addFuncEvent<T>(resetSymtab, lbl);
+ }
+
+ /** Add a function-based event to the hypervisor. */
+ template <class T>
+ T *SparcSystem::addHypervisorFuncEvent(const char *lbl)
+ {
+ return addFuncEvent<T>(hypervisorSymtab, lbl);
+ }
+
+ /** Add a function-based event to the openboot. */
+ template <class T>
+ T *SparcSystem::addOpenbootFuncEvent(const char *lbl)
+ {
+ return addFuncEvent<T>(openbootSymtab, lbl);
+ }
+
+ virtual Addr fixFuncEventAddr(Addr addr);
+
+};
+
+#endif
+
diff --git a/src/arch/sparc/utility.hh b/src/arch/sparc/utility.hh
new file mode 100644
index 000000000..1e67b3370
--- /dev/null
+++ b/src/arch/sparc/utility.hh
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ARCH_SPARC_UTILITY_HH__
+#define __ARCH_SPARC_UTILITY_HH__
+
+#include "arch/sparc/isa_traits.hh"
+#include "base/misc.hh"
+
+namespace SparcISA
+{
+ inline ExtMachInst
+ makeExtMI(MachInst inst, const Addr &pc) {
+ return ExtMachInst(inst);
+ }
+
+ inline bool isCallerSaveIntegerRegister(unsigned int reg) {
+ panic("register classification not implemented");
+ return false;
+ }
+
+ inline bool isCalleeSaveIntegerRegister(unsigned int reg) {
+ panic("register classification not implemented");
+ return false;
+ }
+
+ inline bool isCallerSaveFloatRegister(unsigned int reg) {
+ panic("register classification not implemented");
+ return false;
+ }
+
+ inline bool isCalleeSaveFloatRegister(unsigned int reg) {
+ panic("register classification not implemented");
+ return false;
+ }
+
+ // Instruction address compression hooks
+ inline Addr realPCToFetchPC(const Addr &addr)
+ {
+ return addr;
+ }
+
+ inline Addr fetchPCToRealPC(const Addr &addr)
+ {
+ return addr;
+ }
+
+ // the size of "fetched" instructions (not necessarily the size
+ // of real instructions for PISA)
+ inline size_t fetchInstSize()
+ {
+ return sizeof(MachInst);
+ }
+
+ /**
+ * Function to insure ISA semantics about 0 registers.
+ * @param xc The execution context.
+ */
+ template <class XC>
+ void zeroRegisters(XC *xc);
+
+} // namespace SparcISA
+
+#endif
diff --git a/src/base/bitfield.hh b/src/base/bitfield.hh
new file mode 100644
index 000000000..c59354c7d
--- /dev/null
+++ b/src/base/bitfield.hh
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_BITFIELD_HH__
+#define __BASE_BITFIELD_HH__
+
+#include "sim/host.hh"
+
+/**
+ * Generate a 64-bit mask of 'nbits' 1s, right justified.
+ */
+inline uint64_t
+mask(int nbits)
+{
+ return (nbits == 64) ? (uint64_t)-1LL : (1ULL << nbits) - 1;
+}
+
+
+/**
+ * Extract the bitfield from position 'first' to 'last' (inclusive)
+ * from 'val' and right justify it. MSB is numbered 63, LSB is 0.
+ */
+template <class T>
+inline
+T
+bits(T val, int first, int last)
+{
+ int nbits = first - last + 1;
+ return (val >> last) & mask(nbits);
+}
+
+/**
+ * Sign-extend an N-bit value to 64 bits.
+ */
+template <int N>
+inline
+int64_t
+sext(uint64_t val)
+{
+ int sign_bit = bits(val, N-1, N-1);
+ return sign_bit ? (val | ~mask(N)) : val;
+}
+
+#endif // __BASE_BITFIELD_HH__
diff --git a/src/base/callback.hh b/src/base/callback.hh
new file mode 100644
index 000000000..7b3023505
--- /dev/null
+++ b/src/base/callback.hh
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CALLBACK_HH__
+#define __CALLBACK_HH__
+
+#include <list>
+
+/**
+ * Generic callback class. This base class provides a virtual process
+ * function that gets called when the callback queue is processed.
+ */
+class Callback
+{
+ public:
+ /**
+ * virtualize the destructor to make sure that the correct one
+ * gets called.
+ */
+ virtual ~Callback() {}
+
+ /**
+ * virtual process function that is invoked when the callback
+ * queue is executed.
+ */
+ virtual void process() = 0;
+};
+
+class CallbackQueue
+{
+ protected:
+ /**
+ * Simple typedef for the data structure that stores all of the
+ * callbacks.
+ */
+ typedef std::list<Callback *> queue;
+
+ /**
+ * List of all callbacks. To be called in fifo order.
+ */
+ queue callbacks;
+
+ public:
+ /**
+ * Add a callback to the end of the queue
+ * @param callback the callback to be added to the queue
+ */
+ void add(Callback *callback)
+ {
+ callbacks.push_back(callback);
+ }
+
+ /**
+ * Find out if there are any callbacks in the queue
+ */
+ bool empty() const { return callbacks.empty(); }
+
+ /**
+ * process all callbacks
+ */
+ void process()
+ {
+ queue::iterator i = callbacks.begin();
+ queue::iterator end = callbacks.end();
+
+ while (i != end) {
+ (*i)->process();
+ ++i;
+ }
+ }
+
+ /**
+ * clear the callback queue
+ */
+ void clear()
+ {
+ callbacks.clear();
+ }
+};
+
+/// Helper template class to turn a simple class member function into
+/// a callback.
+template <class T, void (T::* F)()>
+class MakeCallback : public Callback
+{
+ private:
+ T *object;
+
+ public:
+ MakeCallback(T *o)
+ : object(o)
+ { }
+
+ void process() { (object->*F)(); }
+};
+
+#endif // __CALLBACK_HH__
diff --git a/src/base/chunk_generator.hh b/src/base/chunk_generator.hh
new file mode 100644
index 000000000..4f708bd4b
--- /dev/null
+++ b/src/base/chunk_generator.hh
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE__CHUNK_GENERATOR_HH__
+#define __BASE__CHUNK_GENERATOR_HH__
+
+/**
+ * @file
+ * Declaration and inline definition of ChunkGenerator object.
+ */
+
+#include <algorithm>
+#include "base/intmath.hh"
+#include "arch/isa_traits.hh" // for Addr
+
+/**
+ * This class takes an arbitrary memory region (address/length pair)
+ * and generates a series of appropriately (e.g. block- or page-)
+ * aligned chunks covering the same region.
+ *
+ * Example usage:
+
+\code
+ for (ChunkGenerator gen(addr, size, chunkSize); !gen.done(); gen.next()) {
+ doSomethingChunky(gen.addr(), gen.size());
+ }
+\endcode
+ */
+class ChunkGenerator
+{
+ private:
+ /** The starting address of the current chunk. */
+ Addr curAddr;
+ /** The starting address of the next chunk (after the current one). */
+ Addr nextAddr;
+ /** The size of the current chunk (in bytes). */
+ int curSize;
+ /** The number of bytes remaining in the region after the current chunk. */
+ int sizeLeft;
+ /** The start address so we can calculate offset in writing block. */
+ const Addr startAddr;
+ /** The maximum chunk size, e.g., the cache block size or page size. */
+ const int chunkSize;
+
+ public:
+ /**
+ * Constructor.
+ * @param startAddr The starting address of the region.
+ * @param totalSize The total size of the region.
+ * @param _chunkSize The size/alignment of chunks into which
+ * the region should be decomposed.
+ */
+ ChunkGenerator(Addr _startAddr, int totalSize, int _chunkSize)
+ : startAddr(_startAddr), chunkSize(_chunkSize)
+ {
+ // chunkSize must be a power of two
+ assert(chunkSize == 0 || isPowerOf2(chunkSize));
+
+ // set up initial chunk.
+ curAddr = startAddr;
+
+ if (chunkSize == 0) //Special Case, if we see 0, assume no chuncking
+ {
+ nextAddr = startAddr + totalSize;
+ }
+ else
+ {
+ // nextAddr should be *next* chunk start
+ nextAddr = roundUp(startAddr, chunkSize);
+ if (curAddr == nextAddr) {
+ // ... even if startAddr is already chunk-aligned
+ nextAddr += chunkSize;
+ }
+ }
+
+ // how many bytes are left between curAddr and the end of this chunk?
+ int left_in_chunk = nextAddr - curAddr;
+ curSize = std::min(totalSize, left_in_chunk);
+ sizeLeft = totalSize - curSize;
+ }
+
+ /** Return starting address of current chunk. */
+ Addr addr() { return curAddr; }
+ /** Return size in bytes of current chunk. */
+ int size() { return curSize; }
+
+ /** Number of bytes we have already chunked up. */
+ int complete() { return curAddr - startAddr; }
+ /**
+ * Are we done? That is, did the last call to next() advance
+ * past the end of the region?
+ * @return True if yes, false if more to go.
+ */
+ bool done() { return (curSize == 0); }
+
+ /**
+ * Advance generator to next chunk.
+ * @return True if successful, false if unsuccessful
+ * (because we were at the last chunk).
+ */
+ bool next()
+ {
+ if (sizeLeft == 0) {
+ curSize = 0;
+ return false;
+ }
+
+ curAddr = nextAddr;
+ curSize = std::min(sizeLeft, chunkSize);
+ sizeLeft -= curSize;
+ nextAddr += curSize;
+ return true;
+ }
+};
+
+#endif // __BASE__CHUNK_GENERATOR_HH__
diff --git a/src/base/circlebuf.cc b/src/base/circlebuf.cc
new file mode 100644
index 000000000..89bbfd822
--- /dev/null
+++ b/src/base/circlebuf.cc
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <algorithm>
+#include <string>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "base/circlebuf.hh"
+#include "base/cprintf.hh"
+#include "base/intmath.hh"
+
+using namespace std;
+
+CircleBuf::CircleBuf(int l)
+ : _rollover(false), _buflen(l), _size(0), _start(0), _stop(0)
+{
+ _buf = new char[_buflen];
+}
+
+CircleBuf::~CircleBuf()
+{
+ if (_buf)
+ delete [] _buf;
+}
+
+void
+CircleBuf::dump()
+{
+ cprintf("start = %10d, stop = %10d, buflen = %10d\n",
+ _start, _stop, _buflen);
+ fflush(stdout);
+ ::write(STDOUT_FILENO, _buf, _buflen);
+ ::write(STDOUT_FILENO, "<\n", 2);
+}
+
+void
+CircleBuf::flush()
+{
+ _start = 0;
+ _stop = 0;
+ _rollover = false;
+}
+
+void
+CircleBuf::read(char *b, int len)
+{
+ _size -= len;
+ if (_size < 0)
+ _size = 0;
+
+ if (_stop > _start) {
+ len = min(len, _stop - _start);
+ memcpy(b, _buf + _start, len);
+ _start += len;
+ }
+ else {
+ int endlen = _buflen - _start;
+ if (endlen > len) {
+ memcpy(b, _buf + _start, len);
+ _start += len;
+ }
+ else {
+ memcpy(b, _buf + _start, endlen);
+ _start = min(len - endlen, _stop);
+ memcpy(b + endlen, _buf, _start);
+ }
+ }
+}
+
+void
+CircleBuf::read(int fd, int len)
+{
+ _size -= len;
+ if (_size < 0)
+ _size = 0;
+
+ if (_stop > _start) {
+ len = min(len, _stop - _start);
+ ::write(fd, _buf + _start, len);
+ _start += len;
+ }
+ else {
+ int endlen = _buflen - _start;
+ if (endlen > len) {
+ ::write(fd, _buf + _start, len);
+ _start += len;
+ }
+ else {
+ ::write(fd, _buf + _start, endlen);
+ _start = min(len - endlen, _stop);
+ ::write(fd, _buf, _start);
+ }
+ }
+}
+
+void
+CircleBuf::read(int fd)
+{
+ _size = 0;
+
+ if (_stop > _start) {
+ ::write(fd, _buf + _start, _stop - _start);
+ }
+ else {
+ ::write(fd, _buf + _start, _buflen - _start);
+ ::write(fd, _buf, _stop);
+ }
+
+ _start = _stop;
+}
+
+void
+CircleBuf::read(ostream &out)
+{
+ _size = 0;
+
+ if (_stop > _start) {
+ out.write(_buf + _start, _stop - _start);
+ }
+ else {
+ out.write(_buf + _start, _buflen - _start);
+ out.write(_buf, _stop);
+ }
+
+ _start = _stop;
+}
+
+void
+CircleBuf::readall(int fd)
+{
+ if (_rollover)
+ ::write(fd, _buf + _stop, _buflen - _stop);
+
+ ::write(fd, _buf, _stop);
+ _start = _stop;
+}
+
+void
+CircleBuf::write(char b)
+{
+ write(&b, 1);
+}
+
+void
+CircleBuf::write(const char *b)
+{
+ write(b, strlen(b));
+}
+
+void
+CircleBuf::write(const char *b, int len)
+{
+ if (len <= 0)
+ return;
+
+ _size += len;
+ if (_size > _buflen)
+ _size = _buflen;
+
+ int old_start = _start;
+ int old_stop = _stop;
+
+ if (len >= _buflen) {
+ _start = 0;
+ _stop = _buflen;
+ _rollover = true;
+ memcpy(_buf, b + (len - _buflen), _buflen);
+ return;
+ }
+
+ if (_stop + len <= _buflen) {
+ memcpy(_buf + _stop, b, len);
+ _stop += len;
+ } else {
+ int end_len = _buflen - old_stop;
+ _stop = len - end_len;
+ memcpy(_buf + old_stop, b, end_len);
+ memcpy(_buf, b + end_len, _stop);
+ _rollover = true;
+ }
+
+ if (old_start > old_stop && old_start < _stop ||
+ old_start < old_stop && _stop < old_stop)
+ _start = _stop + 1;
+}
diff --git a/src/base/circlebuf.hh b/src/base/circlebuf.hh
new file mode 100644
index 000000000..8a64cb5f5
--- /dev/null
+++ b/src/base/circlebuf.hh
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CIRCLEBUF_HH__
+#define __CIRCLEBUF_HH__
+
+#include <iosfwd>
+
+class CircleBuf
+{
+ protected:
+ char *_buf;
+ bool _rollover;
+ int _buflen;
+ int _size;
+ int _start;
+ int _stop;
+
+ public:
+ explicit CircleBuf(int l);
+ ~CircleBuf();
+
+ bool empty() const { return _size == 0; }
+ int size() const { return _size; }
+ void dump();
+ void flush();
+ void read(char *b, int len);
+ void read(int fd, int len);
+ void read(int fd);
+ void read(std::ostream &out);
+ void readall(int fd);
+ void write(char b);
+ void write(const char *b);
+ void write(const char *b, int len);
+};
+
+#endif // __CIRCLEBUF_HH__
diff --git a/src/base/compression/lzss_compression.cc b/src/base/compression/lzss_compression.cc
new file mode 100644
index 000000000..3ffdf7e95
--- /dev/null
+++ b/src/base/compression/lzss_compression.cc
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * LZSSCompression definitions.
+ */
+
+#include <assert.h>
+
+#include "base/compression/lzss_compression.hh"
+
+#include "base/misc.hh" //for fatal
+
+void
+LZSSCompression::findSubString(uint8_t *src, int back, int size, uint16_t &L,
+ uint16_t &P)
+{
+ int front = 0;
+ int max_length = size - back;
+ L = 0;
+ P = back - 1;
+ while (front < back) {
+ while (src[front] != src[back] && front < back) ++front;
+ if (front >= back) {
+ return;
+ }
+ int i = 1;
+ while (src[front+i] == src[back+i] && i < max_length) ++i;
+ if (i >= L) {
+ L = i;
+ P = front;
+ }
+ if (src[front+i] != src[back+i-1]) {
+ // can't find a longer substring until past this point.
+ front += i;
+ } else {
+ ++front;
+ }
+ }
+}
+
+int
+LZSSCompression::emitByte(uint8_t *dest, uint8_t byte)
+{
+ if ((byte >> 5 & 0x7) == 0 || (byte >> 5 & 0x7) == 7) {
+ // If the top 3 bits are the same, emit 00<6bits>
+ dest[0] = byte & 0x3f;
+ return 1;
+ } else {
+ // emit 01XXXXXX <8 bits>
+ dest[0] = 0x40;
+ dest[1] = byte;
+ return 2;
+ }
+}
+
+void
+LZSSCompression::emitString(uint8_t *dest, uint16_t P, uint16_t L)
+{
+ // Emit 1<7P> <5P><3L> <8L>
+ dest[0] = 1<<7 | (P >> 5 & 0x7f);
+ dest[1] = ((P & 0x1f) << 3) | (L>>8 & 0x3);
+ dest[2] = L & 0xFF;
+}
+
+int
+LZSSCompression::compress(uint8_t *dest, uint8_t *src, int size)
+{
+ if (size > 4096) {
+ fatal("Compression can only handle block sizes of 4096 bytes or less");
+ }
+
+ // Encode the first byte.
+ int dest_index = emitByte(dest, src[0]);
+ int i = 1;
+ // A 11 bit field
+ uint16_t L;
+ // A 12 bit field
+ uint16_t P = 0;
+
+ while (i < size && dest_index < size) {
+ L = 0;
+
+ if (dest_index+3 >= size) {
+ dest_index = size;
+ continue;
+ }
+
+ if (i == size - 1) {
+ // Output the character
+ dest_index += emitByte(&dest[dest_index], src[i]);
+ ++i;
+ continue;
+ }
+ findSubString(src, i, size, L, P);
+ if (L > 1) {
+ // Output the string reference
+ emitString(&dest[dest_index], P, L);
+ dest_index += 3;
+ i = i+L;
+ } else {
+ // Output the character
+ dest_index += emitByte(&dest[dest_index], src[i]);
+ ++i;
+ }
+ }
+
+ if (dest_index >= size) {
+ // Have expansion instead of compression, just copy.
+ memcpy(dest,src,size);
+ return size;
+ }
+ return dest_index;
+}
+
+int
+LZSSCompression::uncompress(uint8_t *dest, uint8_t *src, int size)
+{
+ int index = 0;
+ int i = 0;
+ while (i < size) {
+ if (src[i] & 1<<7 ) {
+ // We have a string
+ // Extract P
+ int start = (src[i] & 0x3f)<<5 | ((src[i+1] >> 3) & 0x1f);
+ // Extract L
+ int len = (src[i+1] & 0x07)<<8 | src[i+2];
+ i += 3;
+ for (int j = start; j < start+len; ++j) {
+ dest[index++] = dest[j];
+ }
+ } else {
+ // We have a character
+ if (src[i] & 1<<6) {
+ // Value is in the next byte
+ dest[index++] = src[i+1];
+ i += 2;
+ } else {
+ // just extend the lower 6 bits
+ dest[index++] = (src[i] & 0x3f) | ((src[i] & 1<<5) ? 0xC0 : 0);
+ ++i;
+ }
+ }
+ }
+ return index;
+}
diff --git a/src/base/compression/lzss_compression.hh b/src/base/compression/lzss_compression.hh
new file mode 100644
index 000000000..c136c6d60
--- /dev/null
+++ b/src/base/compression/lzss_compression.hh
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __LZSS_COMPRESSION_HH__
+#define __LZSS_COMPRESSION_HH__
+
+/** @file
+ * LZSSCompression declarations.
+ */
+
+#include "sim/host.hh" // for uint8_t
+
+/**
+ * Simple LZSS compression scheme.
+ */
+class LZSSCompression
+{
+ /**
+ * Finds the longest substring for the given offset.
+ * @param src The source block that we search for substrings.
+ * @param back The larger offset.
+ * @param size The size of the source block.
+ * @param L The length of the largest substring.
+ * @param P The starting offset of the largest substring.
+ */
+ void findSubString(uint8_t *src, int back, int size, uint16_t &L,
+ uint16_t &P);
+
+ /**
+ * Emit an encoded byte to the compressed data array. If the 2 high
+ * order bits can be signed extended, use 1 byte encoding, if not use 2
+ * bytes.
+ * @param dest The compressed data.
+ * @param byte The byte to emit.
+ * @return The number of bytes used to encode.
+ */
+ int emitByte(uint8_t *dest, uint8_t byte);
+
+ /**
+ * Emit a string reference to the compressed data array. A string reference
+ * always uses 3 bytes. 1 flag bit, 12 bits for the starting position, and
+ * 11 bits for the length of the string. This allows compression of 4096
+ * byte blocks with string lengths of up to 2048 bytes.
+ * @param dest The compressed data.
+ * @param P The starting position in the uncompressed data.
+ * @param L The length in bytes of the string.
+ */
+ void emitString(uint8_t *dest, uint16_t P, uint16_t L);
+
+ public:
+ /**
+ * Compresses the source block and stores it in the destination block. If
+ * the compressed block grows to larger than the source block, it aborts
+ * and just performs a copy.
+ * @param dest The destination block.
+ * @param src The block to be compressed.
+ * @param size The size of the source block.
+ * @return The size of the compressed block.
+ *
+ * @pre Destination has enough storage to hold the compressed block.
+ */
+ int compress(uint8_t *dest, uint8_t *src, int size);
+
+ /**
+ * Unompresses the source block and stores it in the destination block.
+ * @param dest The destination block.
+ * @param src The block to be uncompressed.
+ * @param size The size of the source block.
+ * @return The size of the uncompressed block.
+ *
+ * @pre Destination has enough storage to hold the uncompressed block.
+ */
+ int uncompress(uint8_t *dest, uint8_t *src, int size);
+};
+
+#endif //__LZSS_COMPRESSION_HH__
diff --git a/src/base/compression/null_compression.hh b/src/base/compression/null_compression.hh
new file mode 100644
index 000000000..5fbcf562b
--- /dev/null
+++ b/src/base/compression/null_compression.hh
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_COMPRESSION_NULL_COMPRESSION_HH__
+#define __BASE_COMPRESSION_NULL_COMPRESSION_HH__
+
+/**
+ * @file
+ * This file defines a doNothing compression algorithm.
+ */
+
+#include "base/misc.hh" // for fatal()
+#include "sim/host.hh"
+
+
+/**
+ * A dummy compression class to use when no data compression is desired.
+ */
+class NullCompression
+{
+ public:
+ /**
+ * Uncompress the data, causes a fatal since no data should be compressed.
+ * @param dest The output buffer.
+ * @param src The compressed data.
+ * @param size The number of bytes in src.
+ *
+ * @retval The size of the uncompressed data.
+ */
+ static int uncompress(uint8_t * dest, uint8_t *src, int size)
+ {
+ fatal("Can't uncompress data");
+ }
+
+ /**
+ * Compress the data, just returns the source data.
+ * @param dest The output buffer.
+ * @param src The data to be compressed.
+ * @param size The number of bytes in src.
+ *
+ * @retval The size of the compressed data.
+ */
+
+ static int compress(uint8_t *dest, uint8_t *src, int size)
+ {
+ memcpy(dest,src,size);
+ return size;
+ }
+};
+
+#endif //__BASE_COMPRESSION_NULL_COMPRESSION_HH__
diff --git a/src/base/cprintf.cc b/src/base/cprintf.cc
new file mode 100644
index 000000000..cf332ebf2
--- /dev/null
+++ b/src/base/cprintf.cc
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <cassert>
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+
+#include "base/cprintf.hh"
+
+using namespace std;
+
+namespace cp {
+
+ArgList::~ArgList()
+{
+ while (!objects.empty()) {
+ delete objects.front();
+ objects.pop_front();
+ }
+}
+
+void
+ArgList::dump(const string &format)
+{
+ list_t::iterator iter = objects.begin();
+ list_t::iterator end = objects.end();
+
+ const char *p = format.c_str();
+
+ stream->fill(' ');
+ stream->flags((ios::fmtflags)0);
+
+ while (*p) {
+ switch (*p) {
+ case '%': {
+ if (p[1] == '%') {
+ *stream << '%';
+ p += 2;
+ continue;
+ }
+
+ Format fmt;
+ bool done = false;
+ bool end_number = false;
+ bool have_precision = false;
+ int number = 0;
+
+ while (!done) {
+ ++p;
+ if (*p >= '0' && *p <= '9') {
+ if (end_number)
+ continue;
+ } else if (number > 0)
+ end_number = true;
+
+ switch (*p) {
+ case 's':
+ fmt.format = Format::string;
+ done = true;
+ break;
+
+ case 'c':
+ fmt.format = Format::character;
+ done = true;
+ break;
+
+ case 'l':
+ continue;
+
+ case 'p':
+ fmt.format = Format::integer;
+ fmt.base = Format::hex;
+ fmt.alternate_form = true;
+ done = true;
+ break;
+
+ case 'X':
+ fmt.uppercase = true;
+ case 'x':
+ fmt.base = Format::hex;
+ fmt.format = Format::integer;
+ done = true;
+ break;
+
+ case 'o':
+ fmt.base = Format::oct;
+ fmt.format = Format::integer;
+ done = true;
+ break;
+
+ case 'd':
+ case 'i':
+ case 'u':
+ fmt.format = Format::integer;
+ done = true;
+ break;
+
+ case 'G':
+ fmt.uppercase = true;
+ case 'g':
+ fmt.format = Format::floating;
+ fmt.float_format = Format::best;
+ done = true;
+ break;
+
+ case 'E':
+ fmt.uppercase = true;
+ case 'e':
+ fmt.format = Format::floating;
+ fmt.float_format = Format::scientific;
+ done = true;
+ break;
+
+ case 'f':
+ fmt.format = Format::floating;
+ fmt.float_format = Format::fixed;
+ done = true;
+ break;
+
+ case 'n':
+ *stream << "we don't do %n!!!\n";
+ done = true;
+ break;
+
+ case '#':
+ fmt.alternate_form = true;
+ break;
+
+ case '-':
+ fmt.flush_left = true;
+ break;
+
+ case '+':
+ fmt.print_sign = true;
+ break;
+
+ case ' ':
+ fmt.blank_space = true;
+ break;
+
+ case '.':
+ fmt.width = number;
+ fmt.precision = 0;
+ have_precision = true;
+ number = 0;
+ end_number = false;
+ break;
+
+ case '0':
+ if (number == 0) {
+ fmt.fill_zero = true;
+ break;
+ }
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ number = number * 10 + (*p - '0');
+ break;
+
+ case '%':
+ assert("we shouldn't get here");
+ break;
+
+ default:
+ done = true;
+ break;
+ }
+
+ if (end_number) {
+ if (have_precision)
+ fmt.precision = number;
+ else
+ fmt.width = number;
+
+ end_number = false;
+ number = 0;
+ }
+ }
+
+ if (iter != end)
+ {
+ ios::fmtflags saved_flags = stream->flags();
+ char old_fill = stream->fill();
+ int old_precision = stream->precision();
+
+ (*iter)->process(*stream, fmt);
+
+ stream->flags(saved_flags);
+ stream->fill(old_fill);
+ stream->precision(old_precision);
+
+ ++iter;
+ } else {
+ *stream << "<missing arg for format>";
+ }
+
+ ++p;
+ }
+ break;
+
+ case '\n':
+ *stream << endl;
+ ++p;
+ break;
+ case '\r':
+ ++p;
+ if (*p != '\n')
+ *stream << endl;
+ break;
+
+ default: {
+ size_t len = strcspn(p, "%\n\r\0");
+ stream->write(p, len);
+ p += len;
+ }
+ break;
+ }
+ }
+
+ while (iter != end) {
+ *stream << "<extra arg>";
+ ++iter;
+ }
+}
+
+string
+ArgList::dumpToString(const string &format)
+{
+ stringstream ss;
+
+ dump(ss, format);
+
+ return ss.str();
+}
+
+}
diff --git a/src/base/cprintf.hh b/src/base/cprintf.hh
new file mode 100644
index 000000000..c468c375f
--- /dev/null
+++ b/src/base/cprintf.hh
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPRINTF_HH__
+#define __CPRINTF_HH__
+
+#include <iostream>
+#include <list>
+#include <string>
+
+#include "base/cprintf_formats.hh"
+
+namespace cp {
+
+class ArgList
+{
+ private:
+ class Base
+ {
+ public:
+ virtual ~Base() {}
+ virtual void process(std::ostream &out, Format &fmt) = 0;
+ };
+
+ template <typename T>
+ class Node : public Base
+ {
+ public:
+ const T &data;
+
+ public:
+ Node(const T &d) : data(d) {}
+ virtual void process(std::ostream &out, Format &fmt) {
+ switch (fmt.format) {
+ case Format::character:
+ format_char(out, data, fmt);
+ break;
+
+ case Format::integer:
+ format_integer(out, data, fmt);
+ break;
+
+ case Format::floating:
+ format_float(out, data, fmt);
+ break;
+
+ case Format::string:
+ format_string(out, data, fmt);
+ break;
+
+ default:
+ out << "<bad format>";
+ break;
+ }
+ }
+ };
+
+ typedef std::list<Base *> list_t;
+
+ protected:
+ list_t objects;
+ std::ostream *stream;
+
+ public:
+ ArgList() : stream(&std::cout) {}
+ ~ArgList();
+
+ template<class T>
+ void append(const T &data) {
+ Base *obj = new ArgList::Node<T>(data);
+ objects.push_back(obj);
+ }
+
+ template<class T>
+ void prepend(const T &data) {
+ Base *obj = new ArgList::Node<T>(data);
+ objects.push_front(obj);
+ }
+
+ void dump(const std::string &format);
+ void dump(std::ostream &strm, const std::string &fmt)
+ { stream = &strm; dump(fmt); }
+
+ std::string dumpToString(const std::string &format);
+
+ friend ArgList &operator<<(std::ostream &str, ArgList &list);
+};
+
+template<class T>
+inline ArgList &
+operator,(ArgList &alist, const T &data)
+{
+ alist.append(data);
+ return alist;
+}
+
+class ArgListNull {
+};
+
+inline ArgList &
+operator,(ArgList &alist, ArgListNull)
+{ return alist; }
+
+//
+// cprintf(format, args, ...) prints to cout
+// (analogous to printf())
+//
+inline void
+__cprintf(const std::string &format, ArgList &args)
+{ args.dump(format); delete &args; }
+#define __cprintf__(format, args...) \
+ cp::__cprintf(format, (*(new cp::ArgList), args))
+#define cprintf(args...) \
+ __cprintf__(args, cp::ArgListNull())
+
+//
+// ccprintf(stream, format, args, ...) prints to the specified stream
+// (analogous to fprintf())
+//
+inline void
+__ccprintf(std::ostream &stream, const std::string &format, ArgList &args)
+{ args.dump(stream, format); delete &args; }
+#define __ccprintf__(stream, format, args...) \
+ cp::__ccprintf(stream, format, (*(new cp::ArgList), args))
+#define ccprintf(stream, args...) \
+ __ccprintf__(stream, args, cp::ArgListNull())
+
+//
+// csprintf(format, args, ...) returns a string
+// (roughly analogous to sprintf())
+//
+inline std::string
+__csprintf(const std::string &format, ArgList &args)
+{ std::string s = args.dumpToString(format); delete &args; return s; }
+#define __csprintf__(format, args...) \
+ cp::__csprintf(format, (*(new cp::ArgList), args))
+#define csprintf(args...) \
+ __csprintf__(args, cp::ArgListNull())
+
+template<class T>
+inline ArgList &
+operator<<(ArgList &list, const T &data)
+{
+ list.append(data);
+ return list;
+}
+
+inline ArgList &
+operator<<(std::ostream &str, ArgList &list)
+{
+ list.stream = &str;
+ return list;
+}
+
+class ArgListTemp
+{
+ private:
+ std::string format;
+ ArgList *args;
+
+ public:
+ ArgListTemp(const std::string &f) : format(f) { args = new ArgList; }
+ ~ArgListTemp() { args->dump(format); delete args; }
+
+ operator ArgList *() { return args; }
+};
+
+#define cformat(format) \
+ (*((cp::ArgList *)cp::ArgListTemp(format)))
+}
+
+#endif // __CPRINTF_HH__
diff --git a/src/base/cprintf_formats.hh b/src/base/cprintf_formats.hh
new file mode 100644
index 000000000..05a8723a4
--- /dev/null
+++ b/src/base/cprintf_formats.hh
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPRINTF_FORMATS_HH__
+#define __CPRINTF_FORMATS_HH__
+
+#include <sstream>
+#include <ostream>
+
+namespace cp {
+
+struct Format
+{
+ bool alternate_form;
+ bool flush_left;
+ bool print_sign;
+ bool blank_space;
+ bool fill_zero;
+ bool uppercase;
+ enum { dec, hex, oct } base;
+ enum { none, string, integer, character, floating } format;
+ enum { best, fixed, scientific } float_format;
+ int precision;
+ int width;
+
+ Format() { clear(); }
+
+ void clear()
+ {
+ alternate_form = false;
+ flush_left = false;
+ print_sign = false;
+ blank_space = false;
+ fill_zero = false;
+ uppercase = false;
+ base = dec;
+ format = none;
+ precision = -1;
+ width = 0;
+ }
+};
+
+template <typename T>
+inline void
+_format_char(std::ostream &out, const T &data, Format &fmt)
+{
+ using namespace std;
+
+ out << data;
+}
+
+template <typename T>
+inline void
+_format_integer(std::ostream &out, const T &data, Format &fmt)
+{
+ using namespace std;
+
+ switch (fmt.base) {
+ case Format::hex:
+ out.setf(ios::hex, ios::basefield);
+ break;
+
+ case Format::oct:
+ out.setf(ios::oct, ios::basefield);
+ break;
+
+ case Format::dec:
+ out.setf(ios::dec, ios::basefield);
+ break;
+ }
+
+ if (fmt.alternate_form) {
+ if (!fmt.fill_zero)
+ out.setf(ios::showbase);
+ else {
+ switch (fmt.base) {
+ case Format::hex:
+ out << "0x";
+ fmt.width -= 2;
+ break;
+ case Format::oct:
+ out << "0";
+ fmt.width -= 1;
+ break;
+ case Format::dec:
+ break;
+ }
+ }
+ }
+
+ if (fmt.fill_zero)
+ out.fill('0');
+
+ if (fmt.width > 0)
+ out.width(fmt.width);
+
+ if (fmt.flush_left && !fmt.fill_zero)
+ out.setf(ios::left);
+
+ if (fmt.print_sign)
+ out.setf(ios::showpos);
+
+ if (fmt.uppercase)
+ out.setf(ios::uppercase);
+
+ out << data;
+}
+
+template <typename T>
+inline void
+_format_float(std::ostream &out, const T &data, Format &fmt)
+{
+ using namespace std;
+
+ switch (fmt.float_format) {
+ case Format::scientific:
+ if (fmt.precision != -1) {
+ if (fmt.width > 0)
+ out.width(fmt.width);
+
+ if (fmt.precision == 0)
+ fmt.precision = 1;
+ else
+ out.setf(ios::scientific);
+
+ out.precision(fmt.precision);
+ } else
+ if (fmt.width > 0)
+ out.width(fmt.width);
+
+ if (fmt.uppercase)
+ out.setf(ios::uppercase);
+ break;
+
+ case Format::fixed:
+ if (fmt.precision != -1) {
+ if (fmt.width > 0)
+ out.width(fmt.width);
+
+ out.setf(ios::fixed);
+ out.precision(fmt.precision);
+ } else
+ if (fmt.width > 0)
+ out.width(fmt.width);
+
+ break;
+
+ default:
+ if (fmt.precision != -1)
+ out.precision(fmt.precision);
+
+ if (fmt.width > 0)
+ out.width(fmt.width);
+
+ break;
+ }
+
+ out << data;
+}
+
+template <typename T>
+inline void
+_format_string(std::ostream &out, const T &data, Format &fmt)
+{
+ using namespace std;
+
+#if defined(__GNUC__) && (__GNUC__ < 3) || 1
+ if (fmt.width > 0) {
+ std::stringstream foo;
+ foo << data;
+ int flen = foo.str().size();
+
+ if (fmt.width > flen) {
+ char *spaces = new char[fmt.width - flen + 1];
+ memset(spaces, ' ', fmt.width - flen);
+ spaces[fmt.width - flen] = 0;
+
+ if (fmt.flush_left)
+ out << foo.str() << spaces;
+ else
+ out << spaces << foo.str();
+
+ delete [] spaces;
+ } else
+ out << data;
+ } else
+ out << data;
+#else
+ if (fmt.width > 0)
+ out.width(fmt.width);
+ if (fmt.flush_left)
+ out.setf(ios::left);
+
+ out << data;
+#endif
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// The code below controls the actual usage of formats for various types
+//
+
+//
+// character formats
+//
+template <typename T>
+inline void
+format_char(std::ostream &out, const T &data, Format &fmt)
+{ out << "<bad arg type for char format>"; }
+
+inline void
+format_char(std::ostream &out, char data, Format &fmt)
+{ _format_char(out, data, fmt); }
+
+inline void
+format_char(std::ostream &out, unsigned char data, Format &fmt)
+{ _format_char(out, data, fmt); }
+
+inline void
+format_char(std::ostream &out, signed char data, Format &fmt)
+{ _format_char(out, data, fmt); }
+
+inline void
+format_char(std::ostream &out, short data, Format &fmt)
+{ _format_char(out, (char)data, fmt); }
+
+inline void
+format_char(std::ostream &out, unsigned short data, Format &fmt)
+{ _format_char(out, (char)data, fmt); }
+
+inline void
+format_char(std::ostream &out, int data, Format &fmt)
+{ _format_char(out, (char)data, fmt); }
+
+inline void
+format_char(std::ostream &out, unsigned int data, Format &fmt)
+{ _format_char(out, (char)data, fmt); }
+
+inline void
+format_char(std::ostream &out, long data, Format &fmt)
+{ _format_char(out, (char)data, fmt); }
+
+inline void
+format_char(std::ostream &out, unsigned long data, Format &fmt)
+{ _format_char(out, (char)data, fmt); }
+
+inline void
+format_char(std::ostream &out, long long data, Format &fmt)
+{ _format_char(out, (char)data, fmt); }
+
+inline void
+format_char(std::ostream &out, unsigned long long data, Format &fmt)
+{ _format_char(out, (char)data, fmt); }
+
+//
+// integer formats
+//
+template <typename T>
+inline void
+format_integer(std::ostream &out, const T &data, Format &fmt)
+{ _format_integer(out, data, fmt); }
+inline void
+format_integer(std::ostream &out, char data, Format &fmt)
+{ _format_integer(out, data, fmt); }
+inline void
+format_integer(std::ostream &out, unsigned char data, Format &fmt)
+{ _format_integer(out, data, fmt); }
+inline void
+format_integer(std::ostream &out, signed char data, Format &fmt)
+{ _format_integer(out, data, fmt); }
+#if 0
+inline void
+format_integer(std::ostream &out, short data, Format &fmt)
+{ _format_integer(out, data, fmt); }
+inline void
+format_integer(std::ostream &out, unsigned short data, Format &fmt)
+{ _format_integer(out, data, fmt); }
+inline void
+format_integer(std::ostream &out, int data, Format &fmt)
+{ _format_integer(out, data, fmt); }
+inline void
+format_integer(std::ostream &out, unsigned int data, Format &fmt)
+{ _format_integer(out, data, fmt); }
+inline void
+format_integer(std::ostream &out, long data, Format &fmt)
+{ _format_integer(out, data, fmt); }
+inline void
+format_integer(std::ostream &out, unsigned long data, Format &fmt)
+{ _format_integer(out, data, fmt); }
+inline void
+format_integer(std::ostream &out, long long data, Format &fmt)
+{ _format_integer(out, data, fmt); }
+inline void
+format_integer(std::ostream &out, unsigned long long data, Format &fmt)
+{ _format_integer(out, data, fmt); }
+#endif
+
+//
+// floating point formats
+//
+template <typename T>
+inline void
+format_float(std::ostream &out, const T &data, Format &fmt)
+{ out << "<bad arg type for float format>"; }
+
+inline void
+format_float(std::ostream &out, float data, Format &fmt)
+{ _format_float(out, data, fmt); }
+
+inline void
+format_float(std::ostream &out, double data, Format &fmt)
+{ _format_float(out, data, fmt); }
+
+//
+// string formats
+//
+template <typename T>
+inline void
+format_string(std::ostream &out, const T &data, Format &fmt)
+{ _format_string(out, data, fmt); }
+
+inline void
+format_string(std::ostream &out, const std::stringstream &data, Format &fmt)
+{ _format_string(out, data.str(), fmt); }
+
+} // namespace cp
+
+#endif // __CPRINTF_FORMATS_HH__
diff --git a/src/base/crc.cc b/src/base/crc.cc
new file mode 100644
index 000000000..08f039577
--- /dev/null
+++ b/src/base/crc.cc
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 1988, 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <string>
+
+#include "sim/host.hh"
+#include "base/crc.hh"
+
+#define ETHER_CRC_POLY_LE 0xedb88320
+#define ETHER_CRC_POLY_BE 0x04c11db6
+
+#if 0
+/*
+ * This is for reference. We have a table-driven version
+ * of the little-endian crc32 generator, which is faster
+ * than the double-loop.
+ */
+uint32_t
+crc32le(const uint8_t *buf, size_t len)
+{
+ uint32_t c, crc, carry;
+ size_t i, j;
+
+ crc = 0xffffffffU; /* initial value */
+
+ for (i = 0; i < len; i++) {
+ c = buf[i];
+ for (j = 0; j < 8; j++) {
+ carry = ((crc & 0x01) ? 1 : 0) ^ (c & 0x01);
+ crc >>= 1;
+ c >>= 1;
+ if (carry)
+ crc = (crc ^ ETHER_CRC_POLY_LE);
+ }
+ }
+
+ return (crc);
+}
+#else
+uint32_t
+crc32le(const uint8_t *buf, size_t len)
+{
+ static const uint32_t crctab[] = {
+ 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
+ 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
+ 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
+ 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
+ };
+ uint32_t crc;
+ int i;
+
+ crc = 0xffffffffU; /* initial value */
+
+ for (i = 0; i < len; i++) {
+ crc ^= buf[i];
+ crc = (crc >> 4) ^ crctab[crc & 0xf];
+ crc = (crc >> 4) ^ crctab[crc & 0xf];
+ }
+
+ return (crc);
+}
+#endif
+
+uint32_t
+crc32be(const uint8_t *buf, size_t len)
+{
+ uint32_t c, crc, carry;
+ size_t i, j;
+
+ crc = 0xffffffffU; /* initial value */
+
+ for (i = 0; i < len; i++) {
+ c = buf[i];
+ for (j = 0; j < 8; j++) {
+ carry = ((crc & 0x80000000U) ? 1 : 0) ^ (c & 0x01);
+ crc <<= 1;
+ c >>= 1;
+ if (carry)
+ crc = (crc ^ ETHER_CRC_POLY_BE) | carry;
+ }
+ }
+
+ return (crc);
+}
diff --git a/src/base/crc.hh b/src/base/crc.hh
new file mode 100644
index 000000000..6ede07748
--- /dev/null
+++ b/src/base/crc.hh
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_CRC_HH__
+#define __BASE_CRC_HH__
+
+#include "sim/host.hh"
+
+uint32_t crc32be(const uint8_t *buf, size_t len);
+uint32_t crc32le(const uint8_t *buf, size_t len);
+
+#endif // __BASE_CRC_HH__
diff --git a/src/base/date.cc b/src/base/date.cc
new file mode 100644
index 000000000..ba7698c29
--- /dev/null
+++ b/src/base/date.cc
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+const char *compileDate = __DATE__ " " __TIME__;
diff --git a/src/base/dbl_list.hh b/src/base/dbl_list.hh
new file mode 100644
index 000000000..1d06ff576
--- /dev/null
+++ b/src/base/dbl_list.hh
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2000-2001, 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __DBL_LIST_HH__
+#define __DBL_LIST_HH__
+
+class DblListEl {
+ DblListEl *next;
+ DblListEl *prev;
+
+ // remove this from list
+ void remove() {
+ prev->next = next;
+ next->prev = prev;
+ }
+
+ // insert this before old_el
+ void insertBefore(DblListEl *old_el) {
+ prev = old_el->prev;
+ next = old_el;
+ prev->next = this;
+ next->prev = this;
+ }
+
+ // insert this after old_el
+ void insertAfter(DblListEl *old_el) {
+ next = old_el->next;
+ prev = old_el;
+ next->prev = this;
+ prev->next = this;
+ }
+
+ friend class DblListBase;
+};
+
+
+//
+// doubly-linked list of DblListEl objects
+//
+class DblListBase {
+ // dummy list head element: dummy.next is head, dummy.prev is tail
+ DblListEl dummy;
+
+ // length counter
+ unsigned length;
+
+ DblListEl *valid_or_null(DblListEl *el) {
+ // make sure users never see the dummy element
+ return (el == &dummy) ? NULL : el;
+ }
+
+ public:
+
+ DblListEl *head() {
+ return valid_or_null(dummy.next);
+ }
+
+ DblListEl *tail() {
+ return valid_or_null(dummy.prev);
+ }
+
+ DblListEl *next(DblListEl *el) {
+ return valid_or_null(el->next);
+ }
+
+ DblListEl *prev(DblListEl *el) {
+ return valid_or_null(el->prev);
+ }
+
+ bool is_empty() {
+ return (dummy.next == &dummy);
+ }
+
+ void remove(DblListEl *el) {
+ el->remove();
+ --length;
+ }
+
+ void insertBefore(DblListEl *new_el, DblListEl *old_el) {
+ new_el->insertBefore(old_el);
+ ++length;
+ }
+
+ void insertAfter(DblListEl *new_el, DblListEl *old_el) {
+ new_el->insertAfter(old_el);
+ ++length;
+ }
+
+ // append to end of list, i.e. as dummy.prev
+ void append(DblListEl *el) {
+ insertBefore(el, &dummy);
+ }
+
+ // prepend to front of list (push), i.e. as dummy.next
+ void prepend(DblListEl *el) {
+ insertAfter(el, &dummy);
+ }
+
+ DblListEl *pop() {
+ DblListEl *hd = head();
+ if (hd != NULL)
+ remove(hd);
+ return hd;
+ }
+
+ // constructor
+ DblListBase() {
+ dummy.next = dummy.prev = &dummy;
+ length = 0;
+ }
+};
+
+
+//
+// Template class serves solely to cast args & return values
+// to appropriate type (T *)
+//
+template<class T> class DblList : private DblListBase {
+
+ public:
+
+ T *head() { return (T *)DblListBase::head(); }
+ T *tail() { return (T *)DblListBase::tail(); }
+
+ T *next(T *el) { return (T *)DblListBase::next(el); }
+ T *prev(T *el) { return (T *)DblListBase::prev(el); }
+
+ bool is_empty() { return DblListBase::is_empty(); }
+
+ void remove(T *el) { DblListBase::remove(el); }
+
+ void append(T *el) { DblListBase::append(el); }
+ void prepend(T *el) { DblListBase::prepend(el); }
+
+ T *pop() { return (T *)DblListBase::pop(); }
+
+ DblList<T>() { }
+};
+
+#endif // __DBL_LIST_HH__
diff --git a/src/base/endian.hh b/src/base/endian.hh
new file mode 100644
index 000000000..499eb50c5
--- /dev/null
+++ b/src/base/endian.hh
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ENDIAN_HH__
+#define __ENDIAN_HH__
+
+#include <arpa/inet.h>
+
+inline bool
+HostBigEndian()
+{
+ int x = 0x11223344;
+ return x == htonl(x);
+}
+
+#endif // __ENDIAN_HH__
diff --git a/src/base/fast_alloc.cc b/src/base/fast_alloc.cc
new file mode 100644
index 000000000..6504e07c2
--- /dev/null
+++ b/src/base/fast_alloc.cc
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2000-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was originally written by Steve Reinhardt as part of
+ * the Wisconsin Wind Tunnel simulator. Relicensed as part of M5
+ * by permission.
+ */
+
+#ifndef NO_FAST_ALLOC
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include <assert.h>
+#include "base/fast_alloc.hh"
+
+void *FastAlloc::freeLists[Num_Buckets];
+
+#ifdef FAST_ALLOC_STATS
+unsigned FastAlloc::newCount[Num_Buckets];
+unsigned FastAlloc::deleteCount[Num_Buckets];
+unsigned FastAlloc::allocCount[Num_Buckets];
+#endif
+
+void *FastAlloc::moreStructs(int bucket)
+{
+ assert(bucket > 0 && bucket < Num_Buckets);
+
+ int sz = bucket * Alloc_Quantum;
+ const int nstructs = Num_Structs_Per_New; // how many to allocate?
+ char *p = ::new char[nstructs * sz];
+
+#ifdef FAST_ALLOC_STATS
+ ++allocCount[bucket];
+#endif
+
+ freeLists[bucket] = p;
+ for (int i = 0; i < (nstructs-2); ++i, p += sz)
+ *(void **)p = p + sz;
+ *(void **)p = 0;
+
+ return (p + sz);
+}
+
+
+#ifdef FAST_ALLOC_DEBUG
+
+#include <typeinfo>
+#include <iostream>
+#include <iomanip>
+#include <map>
+#include <string>
+
+using namespace std;
+
+// count of in-use FastAlloc objects
+int FastAlloc::numInUse;
+
+// dummy head & tail object for doubly linked list of in-use FastAlloc
+// objects
+FastAlloc FastAlloc::inUseHead(&FastAlloc::inUseHead, &FastAlloc::inUseHead);
+
+// special constructor for dummy head: make inUsePrev & inUseNext
+// point to self
+FastAlloc::FastAlloc(FastAlloc *prev, FastAlloc *next)
+{
+ inUsePrev = prev;
+ inUseNext = next;
+}
+
+
+// constructor: marks as in use, add to in-use list
+FastAlloc::FastAlloc()
+{
+ // mark this object in use
+ inUse = true;
+
+ // update count
+ ++numInUse;
+
+ // add to tail of list of in-use objects ("before" dummy head)
+ FastAlloc *myNext = &inUseHead;
+ FastAlloc *myPrev = inUseHead.inUsePrev;
+
+ inUsePrev = myPrev;
+ inUseNext = myNext;
+ myPrev->inUseNext = this;
+ myNext->inUsePrev = this;
+}
+
+// destructor: mark not in use, remove from in-use list
+FastAlloc::~FastAlloc()
+{
+ assert(inUse);
+ inUse = false;
+
+ --numInUse;
+ assert(numInUse >= 0);
+
+ // remove me from in-use list
+ inUsePrev->inUseNext = inUseNext;
+ inUseNext->inUsePrev = inUsePrev;
+}
+
+
+// summarize in-use list
+void
+FastAlloc::dump_summary()
+{
+ map<string, int> typemap;
+
+ for (FastAlloc *p = inUseHead.inUseNext; p != &inUseHead; p = p->inUseNext)
+ {
+ ++typemap[typeid(*p).name()];
+ }
+
+ map<string, int>::const_iterator mapiter;
+
+ cout << " count type\n"
+ << " ----- ----\n";
+ for (mapiter = typemap.begin(); mapiter != typemap.end(); ++mapiter)
+ {
+ cout << setw(6) << mapiter->second << " " << mapiter->first << endl;
+ }
+}
+
+
+// show oldest n items on in-use list
+void
+FastAlloc::dump_oldest(int n)
+{
+ // sanity check: don't want to crash the debugger if you forget to
+ // pass in a parameter
+ if (n < 0 || n > numInUse)
+ {
+ cout << "FastAlloc::dump_oldest: bad arg " << n
+ << " (" << numInUse << " objects in use" << endl;
+ return;
+ }
+
+ for (FastAlloc *p = inUseHead.inUsePrev;
+ p != &inUseHead && n > 0;
+ p = p->inUsePrev, --n)
+ {
+ cout << p << " " << typeid(*p).name() << endl;
+ }
+}
+
+
+//
+// C interfaces to FastAlloc::dump_summary() and FastAlloc::dump_oldest().
+// gdb seems to have trouble with calling C++ functions directly.
+//
+extern "C" void
+fast_alloc_summary()
+{
+ FastAlloc::dump_summary();
+}
+
+extern "C" void
+fast_alloc_oldest(int n)
+{
+ FastAlloc::dump_oldest(n);
+}
+
+#endif
+
+#endif // NO_FAST_ALLOC
diff --git a/src/base/fast_alloc.hh b/src/base/fast_alloc.hh
new file mode 100644
index 000000000..54e35f8e0
--- /dev/null
+++ b/src/base/fast_alloc.hh
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2000-2001, 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was originally written by Steve Reinhardt as part of
+ * the Wisconsin Wind Tunnel simulator. Relicensed as part of M5
+ * by permission.
+ */
+
+#ifndef __FAST_ALLOC_H__
+#define __FAST_ALLOC_H__
+
+#include <stddef.h>
+
+// Fast structure allocator. Designed for small objects that are
+// frequently allocated and deallocated. This code is derived from the
+// 'alloc_struct' package used in WWT and Blizzard. C++ provides a
+// much nicer framework for the same optimization. The package is
+// implemented as a class, FastAlloc. Allocation and deletion are
+// performed using FastAlloc's new and delete operators. Any object
+// that derives from the FastAlloc class will transparently use this
+// allocation package.
+
+// The static allocate() and deallocate() methods can also be called
+// directly if desired.
+
+// In order for derived classes to call delete with the correct
+// structure size even when they are deallocated via a base-type
+// pointer, they must have a virtual destructor. It is sufficient for
+// FastAlloc to declare a virtual destructor (as it does); it is not
+// required for derived classes to declare their own destructor. The
+// compiler will automatically generate a virtual destructor for each
+// derived class. However, it is more efficient if each derived class
+// defines an inline destructor, so that the compiler can statically
+// collapse the destructor call chain back up the inheritance
+// hierarchy.
+
+// Uncomment this #define to track in-use objects
+// (for debugging memory leaks).
+//#define FAST_ALLOC_DEBUG
+
+// Uncomment this #define to count news, deletes, and chunk allocations
+// (by bucket).
+// #define FAST_ALLOC_STATS
+
+#include "config/no_fast_alloc.hh"
+
+#if NO_FAST_ALLOC
+
+class FastAlloc {
+};
+
+#else
+
+class FastAlloc {
+ public:
+
+ static void *allocate(size_t);
+ static void deallocate(void *, size_t);
+
+ void *operator new(size_t);
+ void operator delete(void *, size_t);
+
+#ifdef FAST_ALLOC_DEBUG
+ FastAlloc();
+ FastAlloc(FastAlloc*,FastAlloc*); // for inUseHead, see below
+ virtual ~FastAlloc();
+#else
+ virtual ~FastAlloc() {}
+#endif
+
+ private:
+
+ // Max_Alloc_Size is the largest object that can be allocated with
+ // this class. There's no fundamental limit, but this limits the
+ // size of the freeLists array. Let's not make this really huge
+ // like in Blizzard.
+ static const int Max_Alloc_Size = 512;
+
+ // Alloc_Quantum is the difference in size between adjacent
+ // buckets in the free list array.
+ static const int Log2_Alloc_Quantum = 3;
+ static const int Alloc_Quantum = (1 << Log2_Alloc_Quantum);
+
+ // Num_Buckets = bucketFor(Max_Alloc_Size) + 1
+ static const int Num_Buckets =
+ ((Max_Alloc_Size + Alloc_Quantum - 1) >> Log2_Alloc_Quantum) + 1;
+
+ // when we call new() for more structures, how many should we get?
+ static const int Num_Structs_Per_New = 20;
+
+ static int bucketFor(size_t);
+ static void *moreStructs(int bucket);
+
+ static void *freeLists[Num_Buckets];
+
+#ifdef FAST_ALLOC_STATS
+ static unsigned newCount[Num_Buckets];
+ static unsigned deleteCount[Num_Buckets];
+ static unsigned allocCount[Num_Buckets];
+#endif
+
+#ifdef FAST_ALLOC_DEBUG
+ // per-object debugging fields
+ bool inUse; // in-use flag
+ FastAlloc *inUsePrev; // ptrs to build list of in-use objects
+ FastAlloc *inUseNext;
+
+ // static (global) debugging vars
+ static int numInUse; // count in-use objects
+ static FastAlloc inUseHead; // dummy head for list of in-use objects
+
+ public:
+ // functions to dump debugging info (see fast_alloc.cc for C
+ // versions that might be more agreeable to call from gdb)
+ static void dump_summary();
+ static void dump_oldest(int n);
+#endif
+};
+
+
+inline
+int FastAlloc::bucketFor(size_t sz)
+{
+ return (sz + Alloc_Quantum - 1) >> Log2_Alloc_Quantum;
+}
+
+
+inline
+void *FastAlloc::allocate(size_t sz)
+{
+ int b;
+ void *p;
+
+ if (sz > Max_Alloc_Size)
+ return (void *)::new char[sz];
+
+ b = bucketFor(sz);
+ p = freeLists[b];
+
+ if (p)
+ freeLists[b] = *(void **)p;
+ else
+ p = moreStructs(b);
+
+#ifdef FAST_ALLOC_STATS
+ ++newCount[b];
+#endif
+
+ return p;
+}
+
+
+inline
+void FastAlloc::deallocate(void *p, size_t sz)
+{
+ int b;
+
+ if (sz > Max_Alloc_Size)
+ {
+ ::delete [] (char *)p;
+ return;
+ }
+
+ b = bucketFor(sz);
+ *(void **)p = freeLists[b];
+ freeLists[b] = p;
+#ifdef FAST_ALLOC_STATS
+ ++deleteCount[b];
+#endif
+}
+
+
+inline
+void *FastAlloc::operator new(size_t sz)
+{
+ return allocate(sz);
+}
+
+
+inline
+void FastAlloc::operator delete(void *p, size_t sz)
+{
+ deallocate(p, sz);
+}
+
+#endif // NO_FAST_ALLOC
+
+#endif // __FAST_ALLOC_H__
diff --git a/src/base/fenv.hh b/src/base/fenv.hh
new file mode 100644
index 000000000..3234f5dd3
--- /dev/null
+++ b/src/base/fenv.hh
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_FENV_HH__
+#define __BASE_FENV_HH__
+
+#include "config/use_fenv.hh"
+
+#if USE_FENV
+
+#include <fenv.h>
+
+#else
+
+// Dummy definitions to allow code to compile w/o a real <fenv.h>.
+
+#define FE_TONEAREST 0
+#define FE_DOWNWARD 0
+#define FE_UPWARD 0
+#define FE_TOWARDZERO 0
+
+inline int fesetround(int rounding_mode) { return 0; }
+
+#endif // USE_FENV
+
+
+#endif // __BASE_FENV_HH__
diff --git a/src/base/fifo_buffer.cc b/src/base/fifo_buffer.cc
new file mode 100644
index 000000000..85b306c25
--- /dev/null
+++ b/src/base/fifo_buffer.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "base/fifo_buffer.hh"
+
+template<class T>
+void
+FifoBuffer<T>::dump()
+{
+ if (buffer->count() > 0)
+ for (iterator i=buffer->tail(); i.notnull(); i=i.prev())
+ i->dump();
+}
+
+
diff --git a/src/base/fifo_buffer.hh b/src/base/fifo_buffer.hh
new file mode 100644
index 000000000..03ce057c7
--- /dev/null
+++ b/src/base/fifo_buffer.hh
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __FIFO_BUFFER_HH__
+#define __FIFO_BUFFER_HH__
+
+#include "base/res_list.hh"
+
+
+//
+// The FifoBuffer requires only that the objects to be used have a default
+// constructor and a dump() method
+//
+template<class T>
+class FifoBuffer
+{
+ public:
+ typedef typename res_list<T>::iterator iterator;
+
+ private:
+ res_list<T> *buffer;
+
+ unsigned size;
+
+ public:
+ FifoBuffer(unsigned sz)
+ {
+ buffer = new res_list<T>(sz, true, 0);
+ size = sz;
+ }
+
+ void add(T &item)
+ {
+ assert(buffer->num_free() > 0);
+ buffer->add_head(item);
+ }
+
+ iterator head() { return buffer->head(); }
+ iterator tail() { return buffer->tail(); }
+
+ unsigned count() {return buffer->count();}
+ unsigned free_slots() {return buffer->num_free();}
+
+ T *peek() { return (count() > 0) ? tail().data_ptr() : 0; }
+
+ T remove()
+ {
+ assert(buffer->count() > 0);
+ T rval = *buffer->tail();
+ buffer->remove_tail();
+ return rval;
+ }
+
+ void dump();
+
+ ~FifoBuffer() { delete buffer; }
+};
+
+
+#endif
+
diff --git a/src/base/hashmap.hh b/src/base/hashmap.hh
new file mode 100644
index 000000000..712366829
--- /dev/null
+++ b/src/base/hashmap.hh
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __HASHMAP_HH__
+#define __HASHMAP_HH__
+
+#if defined(__GNUC__) && __GNUC__ >= 3
+#include <ext/hash_map>
+#else
+#include <hash_map>
+#endif
+
+#include <string>
+
+#include "sim/host.hh"
+
+#if defined(__GNUC__) && __GNUC__ >= 3
+ #define __hash_namespace __gnu_cxx
+#else
+ #define __hash_namespace std
+#endif
+
+namespace m5 {
+ using ::__hash_namespace::hash_multimap;
+ using ::__hash_namespace::hash_map;
+ using ::__hash_namespace::hash;
+}
+
+
+///////////////////////////////////
+// Some default Hashing Functions
+//
+
+namespace __hash_namespace {
+#if !defined(__LP64__) && !defined(__alpha__)
+ template<>
+ struct hash<uint64_t> {
+ size_t operator()(uint64_t r) const {
+ return r;
+ }
+ };
+
+ template<>
+ struct hash<int64_t> {
+ size_t operator()(int64_t r) const {
+ return r;
+ };
+ };
+#endif
+
+ template<>
+ struct hash<std::string> {
+ size_t operator()(const std::string &s) const {
+ return(__stl_hash_string(s.c_str()));
+ }
+ };
+}
+
+
+#endif // __HASHMAP_HH__
diff --git a/src/base/hostinfo.cc b/src/base/hostinfo.cc
new file mode 100644
index 000000000..d42c96732
--- /dev/null
+++ b/src/base/hostinfo.cc
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <math.h>
+#include <unistd.h>
+
+#include <cstdlib>
+#include <cstring>
+#include <string>
+
+#include "base/misc.hh"
+#include "sim/host.hh"
+
+using namespace std;
+
+string
+__get_hostname()
+{
+ char host[256];
+ if (gethostname(host, sizeof host) == -1)
+ warn("could not get host name!");
+ return host;
+}
+
+string &
+hostname()
+{
+ static string hostname = __get_hostname();
+ return hostname;
+}
+
+uint64_t
+procInfo(char *filename, char *target)
+{
+ int done = 0;
+ char line[80];
+ char format[80];
+ long usage;
+
+ FILE *fp = fopen(filename, "r");
+
+ while (fp && !feof(fp) && !done) {
+ if (fgets(line, 80, fp)) {
+ if (strncmp(line, target, strlen(target)) == 0) {
+ snprintf(format, sizeof(format), "%s %%ld", target);
+ sscanf(line, format, &usage);
+
+ fclose(fp);
+ return usage ;
+ }
+ }
+ }
+
+ if (fp)
+ fclose(fp);
+
+ return 0;
+}
diff --git a/src/base/hostinfo.hh b/src/base/hostinfo.hh
new file mode 100644
index 000000000..21a6e5475
--- /dev/null
+++ b/src/base/hostinfo.hh
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __HOSTINFO_HH__
+#define __HOSTINFO_HH__
+
+#include <string>
+
+#include "sim/host.hh"
+
+std::string &hostname();
+
+uint64_t procInfo(char *filename, char *target);
+
+inline uint64_t memUsage()
+{ return procInfo("/proc/self/status", "VmSize:"); }
+
+#endif // __HOSTINFO_HH__
diff --git a/src/base/hybrid_pred.cc b/src/base/hybrid_pred.cc
new file mode 100644
index 000000000..21cbdb0fd
--- /dev/null
+++ b/src/base/hybrid_pred.cc
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string>
+#include <sstream>
+
+#include "base/hybrid_pred.hh"
+#include "base/statistics.hh"
+#include "sim/stats.hh"
+
+using namespace std;
+
+HybridPredictor::HybridPredictor(const char *_p_name, const char *_z_name,
+ const char *_o_name,
+ unsigned _index_bits, unsigned _counter_bits,
+ unsigned _zero_change, unsigned _one_change,
+ unsigned _thresh,
+ unsigned _global_bits,
+ unsigned _global_thresh,
+ bool _reg_individual_stats)
+{
+ stringstream local_name, global_name;
+
+ pred_name = _p_name;
+ one_name = _o_name;
+ zero_name = _z_name;
+ reg_individual_stats = _reg_individual_stats;
+
+ local_name << pred_name.c_str() << ":L";
+ local = new SaturatingCounterPred(local_name.str(), zero_name, one_name,
+ _index_bits, _counter_bits,
+ _zero_change, _one_change, _thresh);
+
+ global_name << pred_name.c_str() << ":G";
+ global = new SaturatingCounterPred(global_name.str(), zero_name, one_name,
+ 0, _global_bits, 1, 1, _global_thresh);
+}
+
+void HybridPredictor::regStats()
+{
+ using namespace Stats;
+
+ string p_name;
+ stringstream description;
+
+ if (reg_individual_stats)
+ p_name = pred_name + ":A";
+ else
+ p_name = pred_name;
+
+
+ //
+ // Number of predictions
+ //
+ stringstream num_zero_preds;
+ num_zero_preds << p_name << ":" << zero_name << ":preds";
+ description << "number of predictions of " << zero_name;
+ pred_zero
+ .name(num_zero_preds.str())
+ .desc(description.str());
+ description.str("");
+
+ stringstream num_one_preds;
+ num_one_preds << p_name << ":" << one_name << ":preds";
+ description << "number of predictions of " << one_name;
+ pred_one
+ .name(num_one_preds.str())
+ .desc(description.str())
+ ;
+ description.str("");
+
+ //
+ // Count the number of correct predictions
+ //
+ stringstream num_zero_correct;
+ num_zero_correct << p_name << ":" << zero_name << ":corr_preds";
+ description << "number of correct " << zero_name << " preds" ;
+ correct_pred_zero
+ .name(num_zero_correct.str())
+ .desc(description.str())
+ ;
+ description.str("");
+
+ stringstream num_one_correct;
+ num_one_correct << p_name << ":" << one_name << ":corr_preds";
+ description << "number of correct " << one_name << " preds" ;
+ correct_pred_one
+ .name(num_one_correct.str())
+ .desc(description.str())
+ ;
+ description.str("");
+
+
+ //
+ // Number of predictor updates
+ //
+ stringstream num_zero_updates;
+ num_zero_updates << p_name << ":" << zero_name << ":updates" ;
+ description << "number of actual " << zero_name << "s" ;
+ record_zero
+ .name(num_zero_updates.str())
+ .desc(description.str())
+ ;
+ description.str("");
+
+ stringstream num_one_updates;
+ num_one_updates << p_name << ":" << one_name << ":updates" ;
+ description << "number of actual " << one_name << "s" ;
+ record_one
+ .name(num_one_updates.str())
+ .desc(description.str())
+ ;
+ description.str("");
+
+ //
+ // Local & Global predictor stats
+ //
+ if (reg_individual_stats) {
+ local->regStats();
+ global->regStats();
+ }
+}
+
+void HybridPredictor::regFormulas()
+{
+ using namespace Stats;
+
+ string p_name;
+ stringstream description;
+ stringstream name;
+
+ if (reg_individual_stats)
+ p_name = pred_name + ":A";
+ else
+ p_name = pred_name;
+
+ //
+ // Number of predictions
+ //
+ name << p_name << ":predictions" ;
+ total_preds
+ .name(name.str())
+ .desc("total number of predictions made")
+ ;
+ total_preds = pred_one + pred_zero;
+ name.str("");
+
+ //
+ // Fraction of all predictions that are one or zero
+ //
+ name << p_name << ":" << zero_name << ":pred_frac";
+ description << "fraction of all preds that were " << zero_name ;
+ frac_preds_zero
+ .name(name.str())
+ .desc(description.str())
+ ;
+ frac_preds_zero = 100 * record_zero / total_preds;
+ description.str("");
+ name.str("");
+
+ name << p_name << ":" << one_name << ":pred_frac";
+ description << "fraction of all preds that were " << one_name ;
+ frac_preds_one
+ .name(name.str())
+ .desc(description.str())
+ ;
+ frac_preds_one = 100 * record_one / total_preds;
+ description.str("");
+ name.str("");
+
+ //
+ // Count the number of correct predictions
+ //
+ name << p_name << ":correct_preds" ;
+ total_correct
+ .name(name.str())
+ .desc("total number of correct predictions made")
+ ;
+ total_correct = correct_pred_one + correct_pred_zero;
+ name.str("");
+
+
+ //
+ // Prediction accuracy rates
+ //
+ name << p_name << ":pred_rate";
+ total_accuracy
+ .name(name.str())
+ .desc("fraction of all preds that were correct")
+ ;
+ total_accuracy = 100 * total_correct / total_preds;
+ name.str("");
+
+ name << p_name << ":" << zero_name << ":pred_rate" ;
+ description << "fraction of "<< zero_name <<" preds that were correct";
+ zero_accuracy
+ .name(name.str())
+ .desc(description.str())
+ ;
+ zero_accuracy = 100 * correct_pred_zero / pred_zero;
+ description.str("");
+ name.str("");
+
+ name << p_name << ":" << one_name << ":pred_rate" ;
+ description << "fraction of "<< one_name <<" preds that were correct";
+ one_accuracy
+ .name(name.str())
+ .desc(description.str())
+ ;
+ one_accuracy = 100 * correct_pred_one / pred_one;
+ description.str("");
+ name.str("");
+
+ //
+ // Coverage
+ //
+ name << p_name << ":" << zero_name << ":coverage";
+ description << "fraction of " << zero_name
+ << "s that were predicted correctly";
+ zero_coverage
+ .name(name.str())
+ .desc(description.str())
+ ;
+ zero_coverage = 100 * correct_pred_zero / record_zero;
+ description.str("");
+ name.str("");
+
+ name << p_name << ":" << one_name << ":coverage";
+ description << "fraction of " << one_name
+ << "s that were predicted correctly";
+ one_coverage
+ .name(name.str())
+ .desc(description.str())
+ ;
+ one_coverage = 100 * correct_pred_one / record_one;
+ description.str("");
+ name.str("");
+
+ //
+ // Local & Global predictor stats
+ //
+ if (reg_individual_stats) {
+ local->regFormulas();
+ global->regFormulas();
+ }
+
+}
+
diff --git a/src/base/hybrid_pred.hh b/src/base/hybrid_pred.hh
new file mode 100644
index 000000000..ea4a9d04c
--- /dev/null
+++ b/src/base/hybrid_pred.hh
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//==========================================================================
+//
+// This predictor takes the AND of a "local" and a "global" predictor
+// in order to determine its prediction.
+//
+//
+//
+//
+
+#ifndef __HYBRID_PRED_HH__
+#define __HYBRID_PRED_HH__
+
+#include <string>
+
+#include "base/sat_counter.hh"
+#include "base/statistics.hh"
+
+class HybridPredictor : public GenericPredictor
+{
+ private:
+ std::string pred_name;
+ std::string one_name;
+ std::string zero_name;
+ bool reg_individual_stats;
+
+ SaturatingCounterPred *local;
+ SaturatingCounterPred *global;
+
+ unsigned long max_index;
+
+ //
+ // Stats
+ //
+ Stats::Scalar<> pred_one; //num_one_preds
+ Stats::Scalar<> pred_zero; //num_zero_preds
+ Stats::Scalar<> correct_pred_one; //num_one_correct
+ Stats::Scalar<> correct_pred_zero; //num_zero_correct
+ Stats::Scalar<> record_one; //num_one_updates
+ Stats::Scalar<> record_zero; //num_zero_updates
+
+ Stats::Formula total_preds;
+ Stats::Formula frac_preds_zero;
+ Stats::Formula frac_preds_one;
+ Stats::Formula total_correct;
+ Stats::Formula total_accuracy;
+ Stats::Formula zero_accuracy;
+ Stats::Formula one_accuracy;
+ Stats::Formula zero_coverage;
+ Stats::Formula one_coverage;
+
+ public:
+ HybridPredictor(const char *_p_name, const char *_z_name,
+ const char *_o_name,
+ unsigned _index_bits, unsigned _counter_bits,
+ unsigned _zero_change, unsigned _one_change,
+ unsigned _thresh,
+ unsigned _global_bits, unsigned _global_thresh,
+ bool _reg_individual_stats = false);
+
+ void clear() {
+ global->clear();
+ local->clear();
+ }
+
+ unsigned peek(unsigned long _index) {
+ unsigned l = local->peek(_index);
+ unsigned g = global->peek(_index);
+
+ if (l && g)
+ return 1;
+
+ return 0;
+ }
+
+ unsigned value(unsigned long _index) {
+ unsigned l = local->peek(_index);
+ unsigned g = global->peek(_index);
+
+ l = l & 0xFFFF;
+ g = g & 0xFFFF;
+
+ return (l << 16) | g;
+
+ }
+
+ unsigned predict(unsigned long _index) {
+ unsigned l = local->predict(_index);
+ unsigned g = global->predict(_index);
+
+ if (l && g) {
+ ++pred_one;
+ return 1;
+ }
+
+ ++pred_zero;
+ return 0;
+ }
+
+
+ //
+ // This version need only be used if local/global statistics
+ // will be maintained
+ //
+ unsigned predict(unsigned long _index, unsigned &_pdata) {
+ unsigned l = local->predict(_index);
+ unsigned g = global->predict(_index);
+
+ //
+ // bit 0 => local predictor result
+ // bit 1 => global predictor result
+ //
+ _pdata = 0;
+ if (l)
+ _pdata |= 1;
+ if (g)
+ _pdata |= 2;
+ if (l && g) {
+ ++pred_one;
+ return 1;
+ }
+
+ ++pred_zero;
+ return 0;
+ }
+
+ void record(unsigned long _index, unsigned _val, unsigned _predicted) {
+
+ if (_val) {
+ local->record(_index, _val, 0);
+ global->record(_index, _val, 0);
+ ++record_one;
+
+ if (_val == _predicted) {
+ ++correct_pred_one;
+ }
+ } else {
+ local->record(_index, _val, 0);
+ global->record(_index, _val, 0);
+ ++record_zero;
+
+ if (_val == _predicted)
+ ++correct_pred_zero;
+ }
+ }
+
+ void record(unsigned long _index, unsigned _val, unsigned _predicted,
+ unsigned _pdata)
+ {
+
+ local->record(_index, _val, (_pdata & 1));
+ global->record(_index, _val, ((_pdata & 2) ? 1 : 0));
+
+
+ if (_val) {
+ ++record_one;
+
+ if (_val == _predicted)
+ ++correct_pred_one;
+ } else {
+ ++record_zero;
+
+ if (_val == _predicted)
+ ++correct_pred_zero;
+ }
+ }
+
+ void regStats();
+ void regFormulas();
+};
+
+
+#endif // _HYBRID_PRED_HH__
+
diff --git a/src/base/inet.cc b/src/base/inet.cc
new file mode 100644
index 000000000..f2665bd2b
--- /dev/null
+++ b/src/base/inet.cc
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sstream>
+#include <string>
+
+#include "base/cprintf.hh"
+#include "sim/host.hh"
+#include "base/inet.hh"
+
+using namespace std;
+namespace Net {
+
+EthAddr::EthAddr()
+{
+ memset(data, 0, ETH_ADDR_LEN);
+}
+
+EthAddr::EthAddr(const uint8_t ea[ETH_ADDR_LEN])
+{
+ *data = *ea;
+}
+
+EthAddr::EthAddr(const eth_addr &ea)
+{
+ *data = *ea.data;
+}
+
+EthAddr::EthAddr(const std::string &addr)
+{
+ parse(addr);
+}
+
+const EthAddr &
+EthAddr::operator=(const eth_addr &ea)
+{
+ *data = *ea.data;
+ return *this;
+}
+
+const EthAddr &
+EthAddr::operator=(const std::string &addr)
+{
+ parse(addr);
+ return *this;
+}
+
+void
+EthAddr::parse(const std::string &addr)
+{
+ // the hack below is to make sure that ETH_ADDR_LEN is 6 otherwise
+ // the sscanf function won't work.
+ int bytes[ETH_ADDR_LEN == 6 ? ETH_ADDR_LEN : -1];
+ if (sscanf(addr.c_str(), "%x:%x:%x:%x:%x:%x", &bytes[0], &bytes[1],
+ &bytes[2], &bytes[3], &bytes[4], &bytes[5]) != ETH_ADDR_LEN) {
+ memset(data, 0xff, ETH_ADDR_LEN);
+ return;
+ }
+
+ for (int i = 0; i < ETH_ADDR_LEN; ++i) {
+ if (bytes[i] & ~0xff) {
+ memset(data, 0xff, ETH_ADDR_LEN);
+ return;
+ }
+
+ data[i] = bytes[i];
+ }
+}
+
+string
+EthAddr::string() const
+{
+ stringstream stream;
+ stream << *this;
+ return stream.str();
+}
+
+bool
+operator==(const EthAddr &left, const EthAddr &right)
+{
+ return memcmp(left.bytes(), right.bytes(), ETH_ADDR_LEN);
+}
+
+ostream &
+operator<<(ostream &stream, const EthAddr &ea)
+{
+ const uint8_t *a = ea.addr();
+ ccprintf(stream, "%x:%x:%x:%x:%x:%x", a[0], a[1], a[2], a[3], a[4], a[5]);
+ return stream;
+}
+
+uint16_t
+cksum(const IpPtr &ptr)
+{
+ int sum = ip_cksum_add(ptr->bytes(), ptr->hlen(), 0);
+ return ip_cksum_carry(sum);
+}
+
+uint16_t
+__tu_cksum(const IpPtr &ip)
+{
+ int tcplen = ip->len() - ip->hlen();
+ int sum = ip_cksum_add(ip->payload(), tcplen, 0);
+ sum = ip_cksum_add(&ip->ip_src, 8, sum); // source and destination
+ sum += htons(ip->ip_p + tcplen);
+ return ip_cksum_carry(sum);
+}
+
+uint16_t
+cksum(const TcpPtr &tcp)
+{ return __tu_cksum(IpPtr(tcp.packet())); }
+
+uint16_t
+cksum(const UdpPtr &udp)
+{ return __tu_cksum(IpPtr(udp.packet())); }
+
+bool
+IpHdr::options(vector<const IpOpt *> &vec) const
+{
+ vec.clear();
+
+ const uint8_t *data = bytes() + sizeof(struct ip_hdr);
+ int all = hlen() - sizeof(struct ip_hdr);
+ while (all > 0) {
+ const IpOpt *opt = (const IpOpt *)data;
+ int len = opt->len();
+ if (all < len)
+ return false;
+
+ vec.push_back(opt);
+ all -= len;
+ data += len;
+ }
+
+ return true;
+}
+
+bool
+TcpHdr::options(vector<const TcpOpt *> &vec) const
+{
+ vec.clear();
+
+ const uint8_t *data = bytes() + sizeof(struct tcp_hdr);
+ int all = off() - sizeof(struct tcp_hdr);
+ while (all > 0) {
+ const TcpOpt *opt = (const TcpOpt *)data;
+ int len = opt->len();
+ if (all < len)
+ return false;
+
+ vec.push_back(opt);
+ all -= len;
+ data += len;
+ }
+
+ return true;
+}
+
+bool
+TcpOpt::sack(vector<SackRange> &vec) const
+{
+ vec.clear();
+
+ const uint8_t *data = bytes() + sizeof(struct tcp_hdr);
+ int all = len() - offsetof(tcp_opt, opt_data.sack);
+ while (all > 0) {
+ const uint16_t *sack = (const uint16_t *)data;
+ int len = sizeof(uint16_t) * 2;
+ if (all < len) {
+ vec.clear();
+ return false;
+ }
+
+ vec.push_back(RangeIn(ntohs(sack[0]), ntohs(sack[1])));
+ all -= len;
+ data += len;
+ }
+
+ return false;
+}
+
+/* namespace Net */ }
diff --git a/src/base/inet.hh b/src/base/inet.hh
new file mode 100644
index 000000000..e5d0473f9
--- /dev/null
+++ b/src/base/inet.hh
@@ -0,0 +1,407 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_INET_HH__
+#define __BASE_INET_HH__
+
+#include <iosfwd>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/range.hh"
+#include "dev/etherpkt.hh"
+#include "sim/host.hh"
+
+#include "dnet/os.h"
+#include "dnet/eth.h"
+#include "dnet/ip.h"
+#include "dnet/ip6.h"
+#include "dnet/addr.h"
+#include "dnet/arp.h"
+#include "dnet/icmp.h"
+#include "dnet/tcp.h"
+#include "dnet/udp.h"
+#include "dnet/intf.h"
+#include "dnet/route.h"
+#include "dnet/fw.h"
+#include "dnet/blob.h"
+#include "dnet/rand.h"
+
+namespace Net {
+
+/*
+ * Ethernet Stuff
+ */
+struct EthAddr : protected eth_addr
+{
+ protected:
+ void parse(const std::string &addr);
+
+ public:
+ EthAddr();
+ EthAddr(const uint8_t ea[ETH_ADDR_LEN]);
+ EthAddr(const eth_addr &ea);
+ EthAddr(const std::string &addr);
+ const EthAddr &operator=(const eth_addr &ea);
+ const EthAddr &operator=(const std::string &addr);
+
+ int size() const { return sizeof(eth_addr); }
+
+ const uint8_t *bytes() const { return &data[0]; }
+ uint8_t *bytes() { return &data[0]; }
+
+ const uint8_t *addr() const { return &data[0]; }
+ bool unicast() const { return data[0] == 0x00; }
+ bool multicast() const { return data[0] == 0x01; }
+ bool broadcast() const { return data[0] == 0xff; }
+ std::string string() const;
+
+ operator uint64_t() const
+ {
+ uint64_t reg = 0;
+ reg |= ((uint64_t)data[0]) << 40;
+ reg |= ((uint64_t)data[1]) << 32;
+ reg |= ((uint64_t)data[2]) << 24;
+ reg |= ((uint64_t)data[3]) << 16;
+ reg |= ((uint64_t)data[4]) << 8;
+ reg |= ((uint64_t)data[5]) << 0;
+ return reg;
+ }
+
+};
+
+std::ostream &operator<<(std::ostream &stream, const EthAddr &ea);
+bool operator==(const EthAddr &left, const EthAddr &right);
+
+struct EthHdr : public eth_hdr
+{
+ uint16_t type() const { return ntohs(eth_type); }
+ const EthAddr &src() const { return *(EthAddr *)&eth_src; }
+ const EthAddr &dst() const { return *(EthAddr *)&eth_dst; }
+
+ int size() const { return sizeof(eth_hdr); }
+
+ const uint8_t *bytes() const { return (const uint8_t *)this; }
+ const uint8_t *payload() const { return bytes() + size(); }
+ uint8_t *bytes() { return (uint8_t *)this; }
+ uint8_t *payload() { return bytes() + size(); }
+};
+
+class EthPtr
+{
+ protected:
+ friend class IpPtr;
+ EthPacketPtr p;
+
+ public:
+ EthPtr() {}
+ EthPtr(const EthPacketPtr &ptr) : p(ptr) { }
+
+ EthHdr *operator->() { return (EthHdr *)p->data; }
+ EthHdr &operator*() { return *(EthHdr *)p->data; }
+ operator EthHdr *() { return (EthHdr *)p->data; }
+
+ const EthHdr *operator->() const { return (const EthHdr *)p->data; }
+ const EthHdr &operator*() const { return *(const EthHdr *)p->data; }
+ operator const EthHdr *() const { return (const EthHdr *)p->data; }
+
+ const EthPtr &operator=(const EthPacketPtr &ptr) { p = ptr; return *this; }
+
+ const EthPacketPtr packet() const { return p; }
+ EthPacketPtr packet() { return p; }
+ bool operator!() const { return !p; }
+ operator bool() const { return p; }
+};
+
+/*
+ * IP Stuff
+ */
+struct IpOpt;
+struct IpHdr : public ip_hdr
+{
+ uint8_t version() const { return ip_v; }
+ uint8_t hlen() const { return ip_hl * 4; }
+ uint8_t tos() const { return ip_tos; }
+ uint16_t len() const { return ntohs(ip_len); }
+ uint16_t id() const { return ntohs(ip_id); }
+ uint16_t frag_flags() const { return ntohs(ip_off) >> 13; }
+ uint16_t frag_off() const { return ntohs(ip_off) & 0x1fff; }
+ uint8_t ttl() const { return ip_ttl; }
+ uint8_t proto() const { return ip_p; }
+ uint16_t sum() const { return ip_sum; }
+ uint32_t src() const { return ntohl(ip_src); }
+ uint32_t dst() const { return ntohl(ip_dst); }
+
+ void sum(uint16_t sum) { ip_sum = sum; }
+
+ bool options(std::vector<const IpOpt *> &vec) const;
+
+ int size() const { return hlen(); }
+ const uint8_t *bytes() const { return (const uint8_t *)this; }
+ const uint8_t *payload() const { return bytes() + size(); }
+ uint8_t *bytes() { return (uint8_t *)this; }
+ uint8_t *payload() { return bytes() + size(); }
+};
+
+class IpPtr
+{
+ protected:
+ friend class TcpPtr;
+ friend class UdpPtr;
+ EthPacketPtr p;
+
+ const IpHdr *h() const
+ { return (const IpHdr *)(p->data + sizeof(eth_hdr)); }
+ IpHdr *h() { return (IpHdr *)(p->data + sizeof(eth_hdr)); }
+
+ void set(const EthPacketPtr &ptr)
+ {
+ EthHdr *eth = (EthHdr *)ptr->data;
+ if (eth->type() == ETH_TYPE_IP)
+ p = ptr;
+ else
+ p = 0;
+ }
+
+ public:
+ IpPtr() {}
+ IpPtr(const EthPacketPtr &ptr) { set(ptr); }
+ IpPtr(const EthPtr &ptr) { set(ptr.p); }
+ IpPtr(const IpPtr &ptr) : p(ptr.p) { }
+
+ IpHdr *operator->() { return h(); }
+ IpHdr &operator*() { return *h(); }
+ operator IpHdr *() { return h(); }
+
+ const IpHdr *operator->() const { return h(); }
+ const IpHdr &operator*() const { return *h(); }
+ operator const IpHdr *() const { return h(); }
+
+ const IpPtr &operator=(const EthPacketPtr &ptr) { set(ptr); return *this; }
+ const IpPtr &operator=(const EthPtr &ptr) { set(ptr.p); return *this; }
+ const IpPtr &operator=(const IpPtr &ptr) { p = ptr.p; return *this; }
+
+ const EthPacketPtr packet() const { return p; }
+ EthPacketPtr packet() { return p; }
+ bool operator!() const { return !p; }
+ operator bool() const { return p; }
+ operator bool() { return p; }
+};
+
+uint16_t cksum(const IpPtr &ptr);
+
+struct IpOpt : public ip_opt
+{
+ uint8_t type() const { return opt_type; }
+ uint8_t typeNumber() const { return IP_OPT_NUMBER(opt_type); }
+ uint8_t typeClass() const { return IP_OPT_CLASS(opt_type); }
+ uint8_t typeCopied() const { return IP_OPT_COPIED(opt_type); }
+ uint8_t len() const { return IP_OPT_TYPEONLY(type()) ? 1 : opt_len; }
+
+ bool isNumber(int num) const { return typeNumber() == IP_OPT_NUMBER(num); }
+ bool isClass(int cls) const { return typeClass() == IP_OPT_CLASS(cls); }
+ bool isCopied(int cpy) const { return typeCopied() == IP_OPT_COPIED(cpy); }
+
+ const uint8_t *data() const { return opt_data.data8; }
+ void sec(ip_opt_data_sec &sec) const;
+ void lsrr(ip_opt_data_rr &rr) const;
+ void ssrr(ip_opt_data_rr &rr) const;
+ void ts(ip_opt_data_ts &ts) const;
+ uint16_t satid() const { return ntohs(opt_data.satid); }
+ uint16_t mtup() const { return ntohs(opt_data.mtu); }
+ uint16_t mtur() const { return ntohs(opt_data.mtu); }
+ void tr(ip_opt_data_tr &tr) const;
+ const uint32_t *addext() const { return &opt_data.addext[0]; }
+ uint16_t rtralt() const { return ntohs(opt_data.rtralt); }
+ void sdb(std::vector<uint32_t> &vec) const;
+};
+
+/*
+ * TCP Stuff
+ */
+struct TcpOpt;
+struct TcpHdr : public tcp_hdr
+{
+ uint16_t sport() const { return ntohs(th_sport); }
+ uint16_t dport() const { return ntohs(th_dport); }
+ uint32_t seq() const { return ntohl(th_seq); }
+ uint32_t ack() const { return ntohl(th_ack); }
+ uint8_t off() const { return th_off; }
+ uint8_t flags() const { return th_flags & 0x3f; }
+ uint16_t win() const { return ntohs(th_win); }
+ uint16_t sum() const { return th_sum; }
+ uint16_t urp() const { return ntohs(th_urp); }
+
+ void sum(uint16_t sum) { th_sum = sum; }
+
+ bool options(std::vector<const TcpOpt *> &vec) const;
+
+ int size() const { return off(); }
+ const uint8_t *bytes() const { return (const uint8_t *)this; }
+ const uint8_t *payload() const { return bytes() + size(); }
+ uint8_t *bytes() { return (uint8_t *)this; }
+ uint8_t *payload() { return bytes() + size(); }
+};
+
+class TcpPtr
+{
+ protected:
+ EthPacketPtr p;
+ int off;
+
+ const TcpHdr *h() const { return (const TcpHdr *)(p->data + off); }
+ TcpHdr *h() { return (TcpHdr *)(p->data + off); }
+
+ void set(const EthPacketPtr &ptr, int offset) { p = ptr; off = offset; }
+ void set(const IpPtr &ptr)
+ {
+ if (ptr->proto() == IP_PROTO_TCP)
+ set(ptr.p, sizeof(eth_hdr) + ptr->hlen());
+ else
+ set(0, 0);
+ }
+
+ public:
+ TcpPtr() {}
+ TcpPtr(const IpPtr &ptr) { set(ptr); }
+ TcpPtr(const TcpPtr &ptr) : p(ptr.p), off(ptr.off) {}
+
+ TcpHdr *operator->() { return h(); }
+ TcpHdr &operator*() { return *h(); }
+ operator TcpHdr *() { return h(); }
+
+ const TcpHdr *operator->() const { return h(); }
+ const TcpHdr &operator*() const { return *h(); }
+ operator const TcpHdr *() const { return h(); }
+
+ const TcpPtr &operator=(const IpPtr &i) { set(i); return *this; }
+ const TcpPtr &operator=(const TcpPtr &t) { set(t.p, t.off); return *this; }
+
+ const EthPacketPtr packet() const { return p; }
+ EthPacketPtr packet() { return p; }
+ bool operator!() const { return !p; }
+ operator bool() const { return p; }
+ operator bool() { return p; }
+};
+
+uint16_t cksum(const TcpPtr &ptr);
+
+typedef Range<uint16_t> SackRange;
+
+struct TcpOpt : public tcp_opt
+{
+ uint8_t type() const { return opt_type; }
+ uint8_t len() const { return TCP_OPT_TYPEONLY(type()) ? 1 : opt_len; }
+
+ bool isopt(int opt) const { return type() == opt; }
+
+ const uint8_t *data() const { return opt_data.data8; }
+
+ uint16_t mss() const { return ntohs(opt_data.mss); }
+ uint8_t wscale() const { return opt_data.wscale; }
+ bool sack(std::vector<SackRange> &vec) const;
+ uint32_t echo() const { return ntohl(opt_data.echo); }
+ uint32_t tsval() const { return ntohl(opt_data.timestamp[0]); }
+ uint32_t tsecr() const { return ntohl(opt_data.timestamp[1]); }
+ uint32_t cc() const { return ntohl(opt_data.cc); }
+ uint8_t cksum() const{ return opt_data.cksum; }
+ const uint8_t *md5() const { return opt_data.md5; }
+
+ int size() const { return len(); }
+ const uint8_t *bytes() const { return (const uint8_t *)this; }
+ const uint8_t *payload() const { return bytes() + size(); }
+ uint8_t *bytes() { return (uint8_t *)this; }
+ uint8_t *payload() { return bytes() + size(); }
+};
+
+/*
+ * UDP Stuff
+ */
+struct UdpHdr : public udp_hdr
+{
+ uint16_t sport() const { return ntohs(uh_sport); }
+ uint16_t dport() const { return ntohs(uh_dport); }
+ uint16_t len() const { return ntohs(uh_ulen); }
+ uint16_t sum() const { return uh_sum; }
+
+ void sum(uint16_t sum) { uh_sum = sum; }
+
+ int size() const { return sizeof(udp_hdr); }
+ const uint8_t *bytes() const { return (const uint8_t *)this; }
+ const uint8_t *payload() const { return bytes() + size(); }
+ uint8_t *bytes() { return (uint8_t *)this; }
+ uint8_t *payload() { return bytes() + size(); }
+};
+
+class UdpPtr
+{
+ protected:
+ EthPacketPtr p;
+ int off;
+
+ const UdpHdr *h() const { return (const UdpHdr *)(p->data + off); }
+ UdpHdr *h() { return (UdpHdr *)(p->data + off); }
+
+ void set(const EthPacketPtr &ptr, int offset) { p = ptr; off = offset; }
+ void set(const IpPtr &ptr)
+ {
+ if (ptr->proto() == IP_PROTO_UDP)
+ set(ptr.p, sizeof(eth_hdr) + ptr->hlen());
+ else
+ set(0, 0);
+ }
+
+ public:
+ UdpPtr() {}
+ UdpPtr(const IpPtr &ptr) { set(ptr); }
+ UdpPtr(const UdpPtr &ptr) : p(ptr.p), off(ptr.off) {}
+
+ UdpHdr *operator->() { return h(); }
+ UdpHdr &operator*() { return *h(); }
+ operator UdpHdr *() { return h(); }
+
+ const UdpHdr *operator->() const { return h(); }
+ const UdpHdr &operator*() const { return *h(); }
+ operator const UdpHdr *() const { return h(); }
+
+ const UdpPtr &operator=(const IpPtr &i) { set(i); return *this; }
+ const UdpPtr &operator=(const UdpPtr &t) { set(t.p, t.off); return *this; }
+
+ const EthPacketPtr packet() const { return p; }
+ EthPacketPtr packet() { return p; }
+ bool operator!() const { return !p; }
+ operator bool() const { return p; }
+ operator bool() { return p; }
+};
+
+uint16_t cksum(const UdpPtr &ptr);
+
+/* namespace Net */ }
+
+#endif // __BASE_INET_HH__
diff --git a/src/base/inifile.cc b/src/base/inifile.cc
new file mode 100644
index 000000000..eb5a1335f
--- /dev/null
+++ b/src/base/inifile.cc
@@ -0,0 +1,433 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define USE_CPP
+
+#ifdef USE_CPP
+#include <sys/signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#endif
+
+#include <fstream>
+#include <iostream>
+
+#include <vector>
+#include <string>
+
+#include "base/inifile.hh"
+#include "base/str.hh"
+
+using namespace std;
+
+IniFile::IniFile()
+{}
+
+IniFile::~IniFile()
+{
+ SectionTable::iterator i = table.begin();
+ SectionTable::iterator end = table.end();
+
+ while (i != end) {
+ delete (*i).second;
+ ++i;
+ }
+}
+
+
+#ifdef USE_CPP
+bool
+IniFile::loadCPP(const string &file, vector<char *> &cppArgs)
+{
+ // Open the file just to verify that we can. Otherwise if the
+ // file doesn't exist or has bad permissions the user will get
+ // confusing errors from cpp/g++.
+ ifstream tmpf(file.c_str());
+
+ if (!tmpf.is_open())
+ return false;
+
+ tmpf.close();
+
+ char *cfile = strncpy(new char[file.size() + 1], file.c_str(),
+ file.size());
+ char *dir = dirname(cfile);
+ char *dir_arg = NULL;
+ if (*dir != '.') {
+ string arg = "-I";
+ arg += dir;
+
+ dir_arg = new char[arg.size() + 1];
+ strncpy(dir_arg, arg.c_str(), arg.size());
+ }
+
+ delete [] cfile;
+
+ char tempfile[] = "/tmp/configXXXXXX";
+ int tmp_fd = mkstemp(tempfile);
+
+ int pid = fork();
+
+ if (pid == -1)
+ return false;
+
+ if (pid == 0) {
+ char filename[FILENAME_MAX];
+ string::size_type i = file.copy(filename, sizeof(filename) - 1);
+ filename[i] = '\0';
+
+ int arg_count = cppArgs.size();
+
+ char **args = new char *[arg_count + 20];
+
+ int nextArg = 0;
+ args[nextArg++] = "g++";
+ args[nextArg++] = "-E";
+ args[nextArg++] = "-P";
+ args[nextArg++] = "-nostdinc";
+ args[nextArg++] = "-nostdinc++";
+ args[nextArg++] = "-x";
+ args[nextArg++] = "c++";
+ args[nextArg++] = "-undef";
+
+ for (int i = 0; i < arg_count; i++)
+ args[nextArg++] = cppArgs[i];
+
+ if (dir_arg)
+ args[nextArg++] = dir_arg;
+
+ args[nextArg++] = filename;
+ args[nextArg++] = NULL;
+
+ close(STDOUT_FILENO);
+ if (dup2(tmp_fd, STDOUT_FILENO) == -1)
+ exit(1);
+
+ execvp("g++", args);
+
+ exit(0);
+ }
+
+ int retval;
+ waitpid(pid, &retval, 0);
+
+ delete [] dir_arg;
+
+ // check for normal completion of CPP
+ if (!WIFEXITED(retval) || WEXITSTATUS(retval) != 0)
+ return false;
+
+ close(tmp_fd);
+
+ bool status = false;
+
+ status = load(tempfile);
+
+ unlink(tempfile);
+
+ return status;
+}
+#endif
+
+bool
+IniFile::load(const string &file)
+{
+ ifstream f(file.c_str());
+
+ if (!f.is_open())
+ return false;
+
+ return load(f);
+}
+
+
+const string &
+IniFile::Entry::getValue() const
+{
+ referenced = true;
+ return value;
+}
+
+
+void
+IniFile::Section::addEntry(const std::string &entryName,
+ const std::string &value,
+ bool append)
+{
+ EntryTable::iterator ei = table.find(entryName);
+
+ if (ei == table.end()) {
+ // new entry
+ table[entryName] = new Entry(value);
+ }
+ else if (append) {
+ // append new reult to old entry
+ ei->second->appendValue(value);
+ }
+ else {
+ // override old entry
+ ei->second->setValue(value);
+ }
+}
+
+
+bool
+IniFile::Section::add(const std::string &assignment)
+{
+ string::size_type offset = assignment.find('=');
+ if (offset == string::npos) {
+ // no '=' found
+ cerr << "Can't parse .ini line " << assignment << endl;
+ return false;
+ }
+
+ // if "+=" rather than just "=" then append value
+ bool append = (assignment[offset-1] == '+');
+
+ string entryName = assignment.substr(0, append ? offset-1 : offset);
+ string value = assignment.substr(offset + 1);
+
+ eat_white(entryName);
+ eat_white(value);
+
+ addEntry(entryName, value, append);
+ return true;
+}
+
+
+IniFile::Entry *
+IniFile::Section::findEntry(const std::string &entryName) const
+{
+ referenced = true;
+
+ EntryTable::const_iterator ei = table.find(entryName);
+
+ return (ei == table.end()) ? NULL : ei->second;
+}
+
+
+IniFile::Section *
+IniFile::addSection(const string &sectionName)
+{
+ SectionTable::iterator i = table.find(sectionName);
+
+ if (i != table.end()) {
+ return i->second;
+ }
+ else {
+ // new entry
+ Section *sec = new Section();
+ table[sectionName] = sec;
+ return sec;
+ }
+}
+
+
+IniFile::Section *
+IniFile::findSection(const string &sectionName) const
+{
+ SectionTable::const_iterator i = table.find(sectionName);
+
+ return (i == table.end()) ? NULL : i->second;
+}
+
+
+// Take string of the form "<section>:<parameter>=<value>" and add to
+// database. Return true if successful, false if parse error.
+bool
+IniFile::add(const string &str)
+{
+ // find ':'
+ string::size_type offset = str.find(':');
+ if (offset == string::npos) // no ':' found
+ return false;
+
+ string sectionName = str.substr(0, offset);
+ string rest = str.substr(offset + 1);
+
+ eat_white(sectionName);
+ Section *s = addSection(sectionName);
+
+ return s->add(rest);
+}
+
+bool
+IniFile::load(istream &f)
+{
+ Section *section = NULL;
+
+ while (!f.eof()) {
+ f >> ws; // Eat whitespace
+ if (f.eof()) {
+ break;
+ }
+
+ string line;
+ getline(f, line);
+ if (line.size() == 0)
+ continue;
+
+ eat_end_white(line);
+ int last = line.size() - 1;
+
+ if (line[0] == '[' && line[last] == ']') {
+ string sectionName = line.substr(1, last - 1);
+ eat_white(sectionName);
+ section = addSection(sectionName);
+ continue;
+ }
+
+ if (section == NULL)
+ continue;
+
+ if (!section->add(line))
+ return false;
+ }
+
+ return true;
+}
+
+bool
+IniFile::find(const string &sectionName, const string &entryName,
+ string &value) const
+{
+ Section *section = findSection(sectionName);
+ if (section == NULL)
+ return false;
+
+ Entry *entry = section->findEntry(entryName);
+ if (entry == NULL)
+ return false;
+
+ value = entry->getValue();
+
+ return true;
+}
+
+bool
+IniFile::sectionExists(const string &sectionName) const
+{
+ return findSection(sectionName) != NULL;
+}
+
+
+bool
+IniFile::Section::printUnreferenced(const string &sectionName)
+{
+ bool unref = false;
+ bool search_unref_entries = false;
+ vector<string> unref_ok_entries;
+
+ Entry *entry = findEntry("unref_entries_ok");
+ if (entry != NULL) {
+ tokenize(unref_ok_entries, entry->getValue(), ' ');
+ if (unref_ok_entries.size()) {
+ search_unref_entries = true;
+ }
+ }
+
+ for (EntryTable::iterator ei = table.begin();
+ ei != table.end(); ++ei) {
+ const string &entryName = ei->first;
+ Entry *entry = ei->second;
+
+ if (entryName == "unref_section_ok" ||
+ entryName == "unref_entries_ok")
+ {
+ continue;
+ }
+
+ if (!entry->isReferenced()) {
+ if (search_unref_entries &&
+ (std::find(unref_ok_entries.begin(), unref_ok_entries.end(),
+ entryName) != unref_ok_entries.end()))
+ {
+ continue;
+ }
+
+ cerr << "Parameter " << sectionName << ":" << entryName
+ << " not referenced." << endl;
+ unref = true;
+ }
+ }
+
+ return unref;
+}
+
+
+bool
+IniFile::printUnreferenced()
+{
+ bool unref = false;
+
+ for (SectionTable::iterator i = table.begin();
+ i != table.end(); ++i) {
+ const string &sectionName = i->first;
+ Section *section = i->second;
+
+ if (!section->isReferenced()) {
+ if (section->findEntry("unref_section_ok") == NULL) {
+ cerr << "Section " << sectionName << " not referenced."
+ << endl;
+ unref = true;
+ }
+ }
+ else {
+ if (section->printUnreferenced(sectionName)) {
+ unref = true;
+ }
+ }
+ }
+
+ return unref;
+}
+
+
+void
+IniFile::Section::dump(const string &sectionName)
+{
+ for (EntryTable::iterator ei = table.begin();
+ ei != table.end(); ++ei) {
+ cout << sectionName << ": " << (*ei).first << " => "
+ << (*ei).second->getValue() << "\n";
+ }
+}
+
+void
+IniFile::dump()
+{
+ for (SectionTable::iterator i = table.begin();
+ i != table.end(); ++i) {
+ i->second->dump(i->first);
+ }
+}
diff --git a/src/base/inifile.hh b/src/base/inifile.hh
new file mode 100644
index 000000000..3c6894978
--- /dev/null
+++ b/src/base/inifile.hh
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __INIFILE_HH__
+#define __INIFILE_HH__
+
+#include <fstream>
+#include <list>
+#include <string>
+#include <vector>
+
+#include "base/hashmap.hh"
+
+/**
+ * @file
+ * Declaration of IniFile object.
+ * @todo Change comments to match documentation style.
+ */
+
+///
+/// This class represents the contents of a ".ini" file.
+///
+/// It's basically a two level lookup table: a set of named sections,
+/// where each section is a set of key/value pairs. Section names,
+/// keys, and values are all uninterpreted strings.
+///
+class IniFile
+{
+ protected:
+
+ ///
+ /// A single key/value pair.
+ ///
+ class Entry
+ {
+ std::string value; ///< The entry value.
+ mutable bool referenced; ///< Has this entry been used?
+
+ public:
+ /// Constructor.
+ Entry(const std::string &v)
+ : value(v), referenced(false)
+ {
+ }
+
+ /// Has this entry been used?
+ bool isReferenced() { return referenced; }
+
+ /// Fetch the value.
+ const std::string &getValue() const;
+
+ /// Set the value.
+ void setValue(const std::string &v) { value = v; }
+
+ /// Append the given string to the value. A space is inserted
+ /// between the existing value and the new value. Since this
+ /// operation is typically used with values that are
+ /// space-separated lists of tokens, this keeps the tokens
+ /// separate.
+ void appendValue(const std::string &v) { value += " "; value += v; }
+ };
+
+ ///
+ /// A section.
+ ///
+ class Section
+ {
+ /// EntryTable type. Map of strings to Entry object pointers.
+ typedef m5::hash_map<std::string, Entry *> EntryTable;
+
+ EntryTable table; ///< Table of entries.
+ mutable bool referenced; ///< Has this section been used?
+
+ public:
+ /// Constructor.
+ Section()
+ : table(), referenced(false)
+ {
+ }
+
+ /// Has this section been used?
+ bool isReferenced() { return referenced; }
+
+ /// Add an entry to the table. If an entry with the same name
+ /// already exists, the 'append' parameter is checked If true,
+ /// the new value will be appended to the existing entry. If
+ /// false, the new value will replace the existing entry.
+ void addEntry(const std::string &entryName, const std::string &value,
+ bool append);
+
+ /// Add an entry to the table given a string assigment.
+ /// Assignment should be of the form "param=value" or
+ /// "param+=value" (for append). This funciton parses the
+ /// assignment statment and calls addEntry().
+ /// @retval True for success, false if parse error.
+ bool add(const std::string &assignment);
+
+ /// Find the entry with the given name.
+ /// @retval Pointer to the entry object, or NULL if none.
+ Entry *findEntry(const std::string &entryName) const;
+
+ /// Print the unreferenced entries in this section to cerr.
+ /// Messages can be suppressed using "unref_section_ok" and
+ /// "unref_entries_ok".
+ /// @param sectionName Name of this section, for use in output message.
+ /// @retval True if any entries were printed.
+ bool printUnreferenced(const std::string &sectionName);
+
+ /// Print the contents of this section to cout (for debugging).
+ void dump(const std::string &sectionName);
+ };
+
+ /// SectionTable type. Map of strings to Section object pointers.
+ typedef m5::hash_map<std::string, Section *> SectionTable;
+
+ protected:
+ /// Hash of section names to Section object pointers.
+ SectionTable table;
+
+ /// Look up section with the given name, creating a new section if
+ /// not found.
+ /// @retval Pointer to section object.
+ Section *addSection(const std::string &sectionName);
+
+ /// Look up section with the given name.
+ /// @retval Pointer to section object, or NULL if not found.
+ Section *findSection(const std::string &sectionName) const;
+
+ public:
+ /// Constructor.
+ IniFile();
+
+ /// Destructor.
+ ~IniFile();
+
+ /// Load parameter settings from given istream. This is a helper
+ /// function for load(string) and loadCPP(), which open a file
+ /// and then pass it here.
+ /// @retval True if successful, false if errors were encountered.
+ bool load(std::istream &f);
+
+ /// Load the specified file, passing it through the C preprocessor.
+ /// Parameter settings found in the file will be merged with any
+ /// already defined in this object.
+ /// @param file The path of the file to load.
+ /// @param cppFlags Vector of extra flags to pass to cpp.
+ /// @retval True if successful, false if errors were encountered.
+ bool loadCPP(const std::string &file, std::vector<char *> &cppFlags);
+
+ /// Load the specified file.
+ /// Parameter settings found in the file will be merged with any
+ /// already defined in this object.
+ /// @param file The path of the file to load.
+ /// @retval True if successful, false if errors were encountered.
+ bool load(const std::string &file);
+
+ /// Take string of the form "<section>:<parameter>=<value>" or
+ /// "<section>:<parameter>+=<value>" and add to database.
+ /// @retval True if successful, false if parse error.
+ bool add(const std::string &s);
+
+ /// Find value corresponding to given section and entry names.
+ /// Value is returned by reference in 'value' param.
+ /// @retval True if found, false if not.
+ bool find(const std::string &section, const std::string &entry,
+ std::string &value) const;
+
+ /// Determine whether the named section exists in the .ini file.
+ /// Note that the 'Section' class is (intentionally) not public,
+ /// so all clients can do is get a bool that says whether there
+ /// are any values in that section or not.
+ /// @return True if the section exists.
+ bool sectionExists(const std::string &section) const;
+
+ /// Print unreferenced entries in object. Iteratively calls
+ /// printUnreferend() on all the constituent sections.
+ bool printUnreferenced();
+
+ /// Dump contents to cout. For debugging.
+ void dump();
+};
+
+#endif // __INIFILE_HH__
diff --git a/src/base/intmath.cc b/src/base/intmath.cc
new file mode 100644
index 000000000..f1c1651ba
--- /dev/null
+++ b/src/base/intmath.cc
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2001, 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "base/intmath.hh"
+
+int
+prevPrime(int n)
+{
+ int decr;
+
+ // If the number is even, let's start with the previous odd number.
+ if (!(n & 1))
+ --n;
+
+ // Lets test for divisibility by 3. Then we will be able to easily
+ // avoid numbers that are divisible by 3 in the future.
+ decr = n % 3;
+ if (decr == 0) {
+ n -= 2;
+ decr = 2;
+ }
+ else if (decr == 1)
+ decr = 4;
+
+ for (;;) {
+ if (isPrime(n))
+ return n;
+ n -= decr;
+ // Toggle between 2 and 4 to prevent trying numbers that are known
+ // to be divisible by 3.
+ decr = 6 - decr;
+ }
+}
diff --git a/src/base/intmath.hh b/src/base/intmath.hh
new file mode 100644
index 000000000..51baddb91
--- /dev/null
+++ b/src/base/intmath.hh
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2001, 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __INTMATH_HH__
+#define __INTMATH_HH__
+
+#include <assert.h>
+
+#include "sim/host.hh"
+
+// Returns the prime number one less than n.
+int prevPrime(int n);
+
+// Determine if a number is prime
+template <class T>
+inline bool
+isPrime(T n)
+{
+ T i;
+
+ if (n == 2 || n == 3)
+ return true;
+
+ // Don't try every odd number to prove if it is a prime.
+ // Toggle between every 2nd and 4th number.
+ // (This is because every 6th odd number is divisible by 3.)
+ for (i = 5; i*i <= n; i += 6) {
+ if (((n % i) == 0 ) || ((n % (i + 2)) == 0) ) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+template <class T>
+inline T
+leastSigBit(T n)
+{
+ return n & ~(n - 1);
+}
+
+template <class T>
+inline bool
+isPowerOf2(T n)
+{
+ return n != 0 && leastSigBit(n) == n;
+}
+
+inline int
+floorLog2(unsigned x)
+{
+ assert(x > 0);
+
+ int y = 0;
+
+ if (x & 0xffff0000) { y += 16; x >>= 16; }
+ if (x & 0x0000ff00) { y += 8; x >>= 8; }
+ if (x & 0x000000f0) { y += 4; x >>= 4; }
+ if (x & 0x0000000c) { y += 2; x >>= 2; }
+ if (x & 0x00000002) { y += 1; }
+
+ return y;
+}
+
+inline int
+floorLog2(unsigned long x)
+{
+ assert(x > 0);
+
+ int y = 0;
+
+#if defined(__LP64__)
+ if (x & ULL(0xffffffff00000000)) { y += 32; x >>= 32; }
+#endif
+ if (x & 0xffff0000) { y += 16; x >>= 16; }
+ if (x & 0x0000ff00) { y += 8; x >>= 8; }
+ if (x & 0x000000f0) { y += 4; x >>= 4; }
+ if (x & 0x0000000c) { y += 2; x >>= 2; }
+ if (x & 0x00000002) { y += 1; }
+
+ return y;
+}
+
+inline int
+floorLog2(unsigned long long x)
+{
+ assert(x > 0);
+
+ int y = 0;
+
+ if (x & ULL(0xffffffff00000000)) { y += 32; x >>= 32; }
+ if (x & ULL(0x00000000ffff0000)) { y += 16; x >>= 16; }
+ if (x & ULL(0x000000000000ff00)) { y += 8; x >>= 8; }
+ if (x & ULL(0x00000000000000f0)) { y += 4; x >>= 4; }
+ if (x & ULL(0x000000000000000c)) { y += 2; x >>= 2; }
+ if (x & ULL(0x0000000000000002)) { y += 1; }
+
+ return y;
+}
+
+inline int
+floorLog2(int x)
+{
+ assert(x > 0);
+ return floorLog2((unsigned)x);
+}
+
+inline int
+floorLog2(long x)
+{
+ assert(x > 0);
+ return floorLog2((unsigned long)x);
+}
+
+inline int
+floorLog2(long long x)
+{
+ assert(x > 0);
+ return floorLog2((unsigned long long)x);
+}
+
+template <class T>
+inline int
+ceilLog2(T n)
+{
+ if (n == 1)
+ return 0;
+
+ return floorLog2(n - (T)1) + 1;
+}
+
+template <class T>
+inline T
+floorPow2(T n)
+{
+ return (T)1 << floorLog2(n);
+}
+
+template <class T>
+inline T
+ceilPow2(T n)
+{
+ return (T)1 << ceilLog2(n);
+}
+
+template <class T>
+inline T
+divCeil(T a, T b)
+{
+ return (a + b - 1) / b;
+}
+
+template <class T>
+inline T
+roundUp(T val, int align)
+{
+ T mask = (T)align - 1;
+ return (val + mask) & ~mask;
+}
+
+template <class T>
+inline T
+roundDown(T val, int align)
+{
+ T mask = (T)align - 1;
+ return val & ~mask;
+}
+
+inline bool
+isHex(char c)
+{
+ return c >= '0' && c <= '9' ||
+ c >= 'A' && c <= 'F' ||
+ c >= 'a' && c <= 'f';
+}
+
+inline bool
+isOct(char c)
+{
+ return c >= '0' && c <= '7';
+}
+
+inline bool
+isDec(char c)
+{
+ return c >= '0' && c <= '9';
+}
+
+inline int
+hex2Int(char c)
+{
+ if (c >= '0' && c <= '9')
+ return (c - '0');
+
+ if (c >= 'A' && c <= 'F')
+ return (c - 'A') + 10;
+
+ if (c >= 'a' && c <= 'f')
+ return (c - 'a') + 10;
+
+ return 0;
+}
+
+#endif // __INTMATH_HH__
diff --git a/src/base/kgdb.h b/src/base/kgdb.h
new file mode 100644
index 000000000..104244d0b
--- /dev/null
+++ b/src/base/kgdb.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratories.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)remote-sl.h 8.1 (Berkeley) 6/11/93
+ */
+
+/* $NetBSD: kgdb.h,v 1.4 1998/08/13 02:10:59 eeh Exp $ */
+
+#ifndef __KGDB_H__
+#define __KGDB_H__
+
+/*
+ * Message types.
+ */
+#define KGDB_SIGNAL '?' // last sigal
+#define KGDB_SET_BAUD 'b' // set baud (deprecated)
+#define KGDB_SET_BREAK 'B' // set breakpoint (deprecated)
+#define KGDB_CONT 'c' // resume
+#define KGDB_ASYNC_CONT 'C' // continue with signal
+#define KGDB_DEBUG 'd' // toggle debug flags (deprecated)
+#define KGDB_DETACH 'D' // detach remote gdb
+#define KGDB_REG_R 'g' // read general registers
+#define KGDB_REG_W 'G' // write general registers
+#define KGDB_SET_THREAD 'H' // set thread
+#define KGDB_CYCLE_STEP 'i' // step a single cycle
+#define KGDB_SIG_CYCLE_STEP 'I' // signal then single cycle step
+#define KGDB_KILL 'k' // kill program
+#define KGDB_MEM_R 'm' // read memory
+#define KGDB_MEM_W 'M' // write memory
+#define KGDB_READ_REG 'p' // read register
+#define KGDB_SET_REG 'P' // write register
+#define KGDB_QUERY_VAR 'q' // query variable
+#define KGDB_SET_VAR 'Q' // set variable
+#define KGDB_RESET 'r' // reset system. (Deprecated)
+#define KGDB_STEP 's' // step
+#define KGDB_ASYNC_STEP 'S' // signal and step
+#define KGDB_THREAD_ALIVE 'T' // find out if the thread is alive.
+#define KGDB_TARGET_EXIT 'W' // target exited
+#define KGDB_BINARY_DLOAD 'X' // write memory
+#define KGDB_CLR_HW_BKPT 'z' // remove breakpoint or watchpoint
+#define KGDB_SET_HW_BKPT 'Z' // insert breakpoint or watchpoint
+
+/*
+ * start of frame/end of frame
+ */
+#define KGDB_START '$'
+#define KGDB_END '#'
+#define KGDB_GOODP '+'
+#define KGDB_BADP '-'
+
+/*
+ * Stuff for KGDB.
+ */
+#define KGDB_NUMREGS 66 /* from tm-alpha.h, NUM_REGS */
+#define KGDB_REG_V0 0
+#define KGDB_REG_T0 1
+#define KGDB_REG_T1 2
+#define KGDB_REG_T2 3
+#define KGDB_REG_T3 4
+#define KGDB_REG_T4 5
+#define KGDB_REG_T5 6
+#define KGDB_REG_T6 7
+#define KGDB_REG_T7 8
+#define KGDB_REG_S0 9
+#define KGDB_REG_S1 10
+#define KGDB_REG_S2 11
+#define KGDB_REG_S3 12
+#define KGDB_REG_S4 13
+#define KGDB_REG_S5 14
+#define KGDB_REG_S6 15 /* FP */
+#define KGDB_REG_A0 16
+#define KGDB_REG_A1 17
+#define KGDB_REG_A2 18
+#define KGDB_REG_A3 19
+#define KGDB_REG_A4 20
+#define KGDB_REG_A5 21
+#define KGDB_REG_T8 22
+#define KGDB_REG_T9 23
+#define KGDB_REG_T10 24
+#define KGDB_REG_T11 25
+#define KGDB_REG_RA 26
+#define KGDB_REG_T12 27
+#define KGDB_REG_AT 28
+#define KGDB_REG_GP 29
+#define KGDB_REG_SP 30
+#define KGDB_REG_ZERO 31
+#define KGDB_REG_F0 32
+#define KGDB_REG_F1 33
+#define KGDB_REG_F2 34
+#define KGDB_REG_F3 35
+#define KGDB_REG_F4 36
+#define KGDB_REG_F5 37
+#define KGDB_REG_F6 38
+#define KGDB_REG_F7 39
+#define KGDB_REG_F8 40
+#define KGDB_REG_F9 41
+#define KGDB_REG_F10 42
+#define KGDB_REG_F11 43
+#define KGDB_REG_F12 44
+#define KGDB_REG_F13 45
+#define KGDB_REG_F14 46
+#define KGDB_REG_F15 47
+#define KGDB_REG_F16 48
+#define KGDB_REG_F17 49
+#define KGDB_REG_F18 50
+#define KGDB_REG_F19 51
+#define KGDB_REG_F20 52
+#define KGDB_REG_F21 53
+#define KGDB_REG_F22 54
+#define KGDB_REG_F23 55
+#define KGDB_REG_F24 56
+#define KGDB_REG_F25 57
+#define KGDB_REG_F26 58
+#define KGDB_REG_F27 59
+#define KGDB_REG_F28 60
+#define KGDB_REG_F29 61
+#define KGDB_REG_F30 62
+#define KGDB_REG_F31 63
+#define KGDB_REG_PC 64
+#define KGDB_REG_VFP 65
+
+/* Too much? Must be large enough for register transfer. */
+#define KGDB_BUFLEN 1024
+
+/*
+ * Kernel Entry Vectors. [OSF/1 PALcode Specific]
+ */
+
+#define ALPHA_KENTRY_INT 0
+#define ALPHA_KENTRY_ARITH 1
+#define ALPHA_KENTRY_MM 2
+#define ALPHA_KENTRY_IF 3
+#define ALPHA_KENTRY_UNA 4
+#define ALPHA_KENTRY_SYS 5
+
+#endif /* __KGDB_H__ */
diff --git a/src/base/loader/aout_object.cc b/src/base/loader/aout_object.cc
new file mode 100644
index 000000000..564898ca3
--- /dev/null
+++ b/src/base/loader/aout_object.cc
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string>
+
+#include "base/loader/aout_object.hh"
+
+#include "base/loader/symtab.hh"
+
+#include "base/trace.hh" // for DPRINTF
+
+#include "base/loader/exec_aout.h"
+
+using namespace std;
+
+ObjectFile *
+AoutObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data)
+{
+ if (!N_BADMAG(*(aout_exechdr *)data)) {
+ // right now this is only used for Alpha PAL code
+ return new AoutObject(fname, fd, len, data,
+ ObjectFile::Alpha, ObjectFile::UnknownOpSys);
+ }
+ else {
+ return NULL;
+ }
+}
+
+
+AoutObject::AoutObject(const string &_filename, int _fd,
+ size_t _len, uint8_t *_data,
+ Arch _arch, OpSys _opSys)
+ : ObjectFile(_filename, _fd, _len, _data, _arch, _opSys)
+{
+ execHdr = (aout_exechdr *)fileData;
+
+ entry = execHdr->entry;
+
+ text.baseAddr = N_TXTADDR(*execHdr);
+ text.size = execHdr->tsize;
+ text.fileImage = fileData + N_TXTOFF(*execHdr);
+
+ data.baseAddr = N_DATADDR(*execHdr);
+ data.size = execHdr->dsize;
+ data.fileImage = fileData + N_DATOFF(*execHdr);
+
+ bss.baseAddr = N_BSSADDR(*execHdr);
+ bss.size = execHdr->bsize;
+ bss.fileImage = NULL;
+
+ DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n",
+ text.baseAddr, text.size, data.baseAddr, data.size,
+ bss.baseAddr, bss.size);
+}
+
+
+bool
+AoutObject::loadGlobalSymbols(SymbolTable *symtab)
+{
+ // a.out symbols not supported yet
+ return false;
+}
+
+bool
+AoutObject::loadLocalSymbols(SymbolTable *symtab)
+{
+ // a.out symbols not supported yet
+ return false;
+}
diff --git a/src/base/loader/aout_object.hh b/src/base/loader/aout_object.hh
new file mode 100644
index 000000000..aeb710427
--- /dev/null
+++ b/src/base/loader/aout_object.hh
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __AOUT_OBJECT_HH__
+#define __AOUT_OBJECT_HH__
+
+#include "base/loader/object_file.hh"
+
+// forward decls: avoid including exec_aout.h here
+struct aout_exechdr;
+
+class AoutObject : public ObjectFile
+{
+ protected:
+ aout_exechdr *execHdr;
+
+ AoutObject(const std::string &_filename, int _fd,
+ size_t _len, uint8_t *_data,
+ Arch _arch, OpSys _opSys);
+
+ public:
+ virtual ~AoutObject() {}
+
+ virtual bool loadGlobalSymbols(SymbolTable *symtab);
+ virtual bool loadLocalSymbols(SymbolTable *symtab);
+
+ static ObjectFile *tryFile(const std::string &fname, int fd,
+ size_t len, uint8_t *data);
+};
+
+#endif // __AOUT_OBJECT_HH__
diff --git a/src/base/loader/coff_sym.h b/src/base/loader/coff_sym.h
new file mode 100644
index 000000000..4c6540395
--- /dev/null
+++ b/src/base/loader/coff_sym.h
@@ -0,0 +1,519 @@
+/*
+ * Copyright (c) 2003, 2005-2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Steve Reinhardt
+ */
+
+/*
+ * Taken from binutils-2.14.90.0.5 include/coff/sym.h
+ */
+
+/* Declarations of internal format of MIPS ECOFF symbols.
+ Originally contributed by MIPS Computer Systems and Third Eye Software.
+ Changes contributed by Cygnus Support are in the public domain.
+
+ This file is just aggregated with the files that make up the GNU
+ release; it is not considered part of GAS, GDB, or other GNU
+ programs. */
+
+/*
+ * |-----------------------------------------------------------|
+ * | Copyright (c) 1992, 1991, 1990 MIPS Computer Systems, Inc.|
+ * | MIPS Computer Systems, Inc. grants reproduction and use |
+ * | rights to all parties, PROVIDED that this comment is |
+ * | maintained in the copy. |
+ * |-----------------------------------------------------------|
+ */
+#ifndef _SYM_H
+#define _SYM_H
+
+/* (C) Copyright 1984 by Third Eye Software, Inc.
+ *
+ * Third Eye Software, Inc. grants reproduction and use rights to
+ * all parties, PROVIDED that this comment is maintained in the copy.
+ *
+ * Third Eye makes no claims about the applicability of this
+ * symbol table to a particular use.
+ */
+
+/*
+ * This file contains the definition of the Third Eye Symbol Table.
+ *
+ * Symbols are assumed to be in 'encounter order' - i.e. the order that
+ * the things they represent were encountered by the compiler/assembler/loader.
+ * EXCEPT for globals! These are assumed to be bunched together,
+ * probably right after the last 'normal' symbol. Globals ARE sorted
+ * in ascending order.
+ *
+ * -----------------------------------------------------------------------
+ * A brief word about Third Eye naming/use conventions:
+ *
+ * All arrays and index's are 0 based.
+ * All "ifooMax" values are the highest legal value PLUS ONE. This makes
+ * them good for allocating arrays, etc. All checks are "ifoo < ifooMax".
+ *
+ * "isym" Index into the SYMbol table.
+ * "ipd" Index into the Procedure Descriptor array.
+ * "ifd" Index into the File Descriptor array.
+ * "iss" Index into String Space.
+ * "cb" Count of Bytes.
+ * "rgPd" array whose domain is "0..ipdMax-1" and RanGe is PDR.
+ * "rgFd" array whose domain is "0..ifdMax-1" and RanGe is FDR.
+ */
+
+
+/*
+ * Symbolic Header (HDR) structure.
+ * As long as all the pointers are set correctly,
+ * we don't care WHAT order the various sections come out in!
+ *
+ * A file produced solely for the use of CDB will probably NOT have
+ * any instructions or data areas in it, as these are available
+ * in the original.
+ */
+
+typedef struct ecoff_symhdr {
+ coff_short magic; /* to verify validity of the table */
+ coff_short vstamp; /* version stamp */
+ coff_int ilineMax; /* number of line number entries */
+ coff_int idnMax; /* max index into dense number table */
+ coff_int ipdMax; /* number of procedures */
+ coff_int isymMax; /* number of local symbols */
+ coff_int ioptMax; /* max index into optimization symbol entries */
+ coff_int iauxMax; /* number of auxillary symbol entries */
+ coff_int issMax; /* max index into local strings */
+ coff_int issExtMax; /* max index into external strings */
+ coff_int ifdMax; /* number of file descriptor entries */
+ coff_int crfd; /* number of relative file descriptor entries */
+ coff_int iextMax; /* max index into external symbols */
+ coff_addr cbLine; /* number of bytes for line number entries */
+ coff_addr cbLineOffset; /* offset to start of line number entries*/
+ coff_addr cbDnOffset; /* offset to start dense number table */
+ coff_addr cbPdOffset; /* offset to procedure descriptor table */
+ coff_addr cbSymOffset; /* offset to start of local symbols*/
+ coff_addr cbOptOffset; /* offset to optimization symbol entries */
+ coff_addr cbAuxOffset; /* offset to start of auxillary symbol entries*/
+ coff_addr cbSsOffset; /* offset to start of local strings */
+ coff_addr cbSsExtOffset; /* offset to start of external strings */
+ coff_addr cbFdOffset; /* offset to file descriptor table */
+ coff_addr cbRfdOffset; /* offset to relative file descriptor table */
+ coff_addr cbExtOffset; /* offset to start of external symbol entries*/
+ /* If you add machine dependent fields, add them here */
+} HDRR, *pHDRR;
+#define cbHDRR sizeof(HDRR)
+#define hdrNil ((pHDRR)0)
+
+/*
+ * The FDR and PDR structures speed mapping of address <-> name.
+ * They are sorted in ascending memory order and are kept in
+ * memory by CDB at runtime.
+ */
+
+/*
+ * File Descriptor
+ *
+ * There is one of these for EVERY FILE, whether compiled with
+ * full debugging symbols or not. The name of a file should be
+ * the path name given to the compiler. This allows the user
+ * to simply specify the names of the directories where the COMPILES
+ * were done, and we will be able to find their files.
+ * A field whose comment starts with "R - " indicates that it will be
+ * setup at runtime.
+ */
+typedef struct ecoff_fdr {
+ coff_addr adr; /* memory address of beginning of file */
+ coff_addr cbLineOffset; /* byte offset from header for this file ln's */
+ coff_addr cbLine; /* size of lines for this file */
+ coff_addr cbSs; /* number of bytes in the ss */
+ coff_int rss; /* file name (of source, if known) */
+ coff_int issBase; /* file's string space */
+ coff_int isymBase; /* beginning of symbols */
+ coff_int csym; /* count file's of symbols */
+ coff_int ilineBase; /* file's line symbols */
+ coff_int cline; /* count of file's line symbols */
+ coff_int ioptBase; /* file's optimization entries */
+ coff_int copt; /* count of file's optimization entries */
+ coff_int ipdFirst; /* start of procedures for this file */
+ coff_int cpd; /* count of procedures for this file */
+ coff_int iauxBase; /* file's auxiliary entries */
+ coff_int caux; /* count of file's auxiliary entries */
+ coff_int rfdBase; /* index into the file indirect table */
+ coff_int crfd; /* count file indirect entries */
+ unsigned lang: 5; /* language for this file */
+ unsigned fMerge : 1; /* whether this file can be merged */
+ unsigned fReadin : 1; /* true if it was read in (not just created) */
+ unsigned fBigendian : 1;/* if set, was compiled on big endian machine */
+ /* aux's will be in compile host's sex */
+ unsigned glevel : 2; /* level this file was compiled with */
+ unsigned reserved : 22; /* reserved for future use */
+ coff_uint reserved2;
+} FDR, *pFDR;
+#define cbFDR sizeof(FDR)
+#define fdNil ((pFDR)0)
+#define ifdNil -1
+#define ifdTemp 0
+#define ilnNil -1
+
+
+/*
+ * Procedure Descriptor
+ *
+ * There is one of these for EVERY TEXT LABEL.
+ * If a procedure is in a file with full symbols, then isym
+ * will point to the PROC symbols, else it will point to the
+ * global symbol for the label.
+ */
+
+typedef struct pdr {
+ coff_addr adr; /* memory address of start of procedure */
+ coff_addr cbLineOffset; /* byte offset for this procedure from the fd base */
+ coff_int isym; /* start of local symbol entries */
+ coff_int iline; /* start of line number entries*/
+ coff_uint regmask; /* save register mask */
+ coff_int regoffset; /* save register offset */
+ coff_int iopt; /* start of optimization symbol entries*/
+ coff_uint fregmask; /* save floating point register mask */
+ coff_int fregoffset; /* save floating point register offset */
+ coff_int frameoffset; /* frame size */
+ coff_int lnLow; /* lowest line in the procedure */
+ coff_int lnHigh; /* highest line in the procedure */
+ /* These fields are new for 64 bit ECOFF. */
+ unsigned gp_prologue : 8; /* byte size of GP prologue */
+ unsigned gp_used : 1; /* true if the procedure uses GP */
+ unsigned reg_frame : 1; /* true if register frame procedure */
+ unsigned prof : 1; /* true if compiled with -pg */
+ unsigned reserved : 13; /* reserved: must be zero */
+ unsigned localoff : 8; /* offset of local variables from vfp */
+ coff_short framereg; /* frame pointer register */
+ coff_short pcreg; /* offset or reg of return pc */
+} PDR, *pPDR;
+#define cbPDR sizeof(PDR)
+#define pdNil ((pPDR) 0)
+#define ipdNil -1
+
+/*
+ * The structure of the runtime procedure descriptor created by the loader
+ * for use by the static exception system.
+ */
+/*
+ * If 0'd out because exception_info chokes Visual C++ and because there
+ * don't seem to be any references to this structure elsewhere in gdb.
+ */
+#if 0
+typedef struct runtime_pdr {
+ coff_addr adr; /* memory address of start of procedure */
+ coff_uint regmask; /* save register mask */
+ coff_int regoffset; /* save register offset */
+ coff_uint fregmask; /* save floating point register mask */
+ coff_int fregoffset; /* save floating point register offset */
+ coff_int frameoffset; /* frame size */
+ coff_ushort framereg; /* frame pointer register */
+ coff_ushort pcreg; /* offset or reg of return pc */
+ coff_int irpss; /* index into the runtime string table */
+ coff_uint reserved;
+ struct exception_info *exception_info;/* pointer to exception array */
+} RPDR, *pRPDR;
+#define cbRPDR sizeof(RPDR)
+#define rpdNil ((pRPDR) 0)
+#endif
+
+/*
+ * Line Numbers
+ *
+ * Line Numbers are segregated from the normal symbols because they
+ * are [1] smaller , [2] are of no interest to your
+ * average loader, and [3] are never needed in the middle of normal
+ * scanning and therefore slow things down.
+ *
+ * By definition, the first LINER for any given procedure will have
+ * the first line of a procedure and represent the first address.
+ */
+
+typedef coff_int LINER, *pLINER;
+#define lineNil ((pLINER)0)
+#define cbLINER sizeof(LINER)
+#define ilineNil -1
+
+
+
+/*
+ * The Symbol Structure (GFW, to those who Know!)
+ */
+
+typedef struct ecoff_sym {
+ coff_long value; /* value of symbol */
+ coff_int iss; /* index into String Space of name */
+ unsigned st : 6; /* symbol type */
+ unsigned sc : 5; /* storage class - text, data, etc */
+ unsigned reserved : 1; /* reserved */
+ unsigned index : 20; /* index into sym/aux table */
+} SYMR, *pSYMR;
+#define symNil ((pSYMR)0)
+#define cbSYMR sizeof(SYMR)
+#define isymNil -1
+#define indexNil 0xfffff
+#define issNil -1
+#define issNull 0
+
+
+/* The following converts a memory resident string to an iss.
+ * This hack is recognized in SbFIss, in sym.c of the debugger.
+ */
+#define IssFSb(sb) (0x80000000 | ((coff_ulong)(sb)))
+
+/* E X T E R N A L S Y M B O L R E C O R D
+ *
+ * Same as the SYMR except it contains file context to determine where
+ * the index is.
+ */
+typedef struct ecoff_extsym {
+ SYMR asym; /* symbol for the external */
+ unsigned jmptbl:1; /* symbol is a jump table entry for shlibs */
+ unsigned cobol_main:1; /* symbol is a cobol main procedure */
+ unsigned weakext:1; /* symbol is weak external */
+ unsigned reserved:29; /* reserved for future use */
+ coff_int ifd; /* where the iss and index fields point into */
+} EXTR, *pEXTR;
+#define extNil ((pEXTR)0)
+#define cbEXTR sizeof(EXTR)
+
+
+/* A U X I L L A R Y T Y P E I N F O R M A T I O N */
+
+/*
+ * Type Information Record
+ */
+typedef struct {
+ unsigned fBitfield : 1; /* set if bit width is specified */
+ unsigned continued : 1; /* indicates additional TQ info in next AUX */
+ unsigned bt : 6; /* basic type */
+ unsigned tq4 : 4;
+ unsigned tq5 : 4;
+ /* ---- 16 bit boundary ---- */
+ unsigned tq0 : 4;
+ unsigned tq1 : 4; /* 6 type qualifiers - tqPtr, etc. */
+ unsigned tq2 : 4;
+ unsigned tq3 : 4;
+} TIR, *pTIR;
+#define cbTIR sizeof(TIR)
+#define tiNil ((pTIR)0)
+#define itqMax 6
+
+/*
+ * Relative symbol record
+ *
+ * If the rfd field is 4095, the index field indexes into the global symbol
+ * table.
+ */
+
+typedef struct {
+ unsigned rfd : 12; /* index into the file indirect table */
+ unsigned index : 20; /* index int sym/aux/iss tables */
+} RNDXR, *pRNDXR;
+#define cbRNDXR sizeof(RNDXR)
+#define rndxNil ((pRNDXR)0)
+
+/* dense numbers or sometimes called block numbers are stored in this type,
+ * a rfd of 0xffffffff is an index into the global table.
+ */
+typedef struct {
+ coff_uint rfd; /* index into the file table */
+ coff_uint index; /* index int sym/aux/iss tables */
+} DNR, *pDNR;
+#define cbDNR sizeof(DNR)
+#define dnNil ((pDNR)0)
+
+
+
+/*
+ * Auxillary information occurs only if needed.
+ * It ALWAYS occurs in this order when present.
+
+ isymMac used by stProc only
+ TIR type info
+ TIR additional TQ info (if first TIR was not enough)
+ rndx if (bt == btStruct,btUnion,btEnum,btSet,btRange,
+ btTypedef):
+ rsym.index == iaux for btSet or btRange
+ else rsym.index == isym
+ dimLow btRange, btSet
+ dimMac btRange, btSet
+ rndx0 As many as there are tq arrays
+ dimLow0
+ dimHigh0
+ ...
+ rndxMax-1
+ dimLowMax-1
+ dimHighMax-1
+ width in bits if (bit field), width in bits.
+ */
+#define cAuxMax (6 + (idimMax*3))
+
+/* a union of all possible info in the AUX universe */
+typedef union {
+ TIR ti; /* type information record */
+ RNDXR rndx; /* relative index into symbol table */
+ coff_int dnLow; /* low dimension */
+ coff_int dnHigh; /* high dimension */
+ coff_int isym; /* symbol table index (end of proc) */
+ coff_int iss; /* index into string space (not used) */
+ coff_int width; /* width for non-default sized struc fields */
+ coff_int count; /* count of ranges for variant arm */
+} AUXU, *pAUXU;
+#define cbAUXU sizeof(AUXU)
+#define auxNil ((pAUXU)0)
+#define iauxNil -1
+
+
+/*
+ * Optimization symbols
+ *
+ * Optimization symbols contain some overlap information with the normal
+ * symbol table. In particular, the proc information
+ * is somewhat redundant but necessary to easily find the other information
+ * present.
+ *
+ * All of the offsets are relative to the beginning of the last otProc
+ */
+
+typedef struct {
+ unsigned ot: 8; /* optimization type */
+ unsigned value: 24; /* address where we are moving it to */
+ RNDXR rndx; /* points to a symbol or opt entry */
+ coff_ulong offset; /* relative offset this occured */
+} OPTR, *pOPTR;
+#define optNil ((pOPTR) 0)
+#define cbOPTR sizeof(OPTR)
+#define ioptNil -1
+
+/*
+ * File Indirect
+ *
+ * When a symbol is referenced across files the following procedure is used:
+ * 1) use the file index to get the File indirect entry.
+ * 2) use the file indirect entry to get the File descriptor.
+ * 3) add the sym index to the base of that file's sym table
+ *
+ */
+
+typedef coff_long RFDT, *pRFDT;
+#define cbRFDT sizeof(RFDT)
+#define rfdNil -1
+
+/*
+ * The file indirect table in the mips loader is known as an array of FITs.
+ * This is done to keep the code in the loader readable in the area where
+ * these tables are merged. Note this is only a name change.
+ */
+typedef coff_int FIT, *pFIT;
+#define cbFIT sizeof(FIT)
+#define ifiNil -1
+#define fiNil ((pFIT) 0)
+
+#ifdef _LANGUAGE_PASCAL
+#define ifdNil -1
+#define ilnNil -1
+#define ipdNil -1
+#define ilineNil -1
+#define isymNil -1
+#define indexNil 16#fffff
+#define issNil -1
+#define issNull 0
+#define itqMax 6
+#define iauxNil -1
+#define ioptNil -1
+#define rfdNil -1
+#define ifiNil -1
+#endif /* _LANGUAGE_PASCAL */
+
+
+/* Dense numbers
+ *
+ * Rather than use file index, symbol index pairs to represent symbols
+ * and globals, we use dense number so that they can be easily embeded
+ * in intermediate code and the programs that process them can
+ * use direct access tabls instead of hash table (which would be
+ * necesary otherwise because of the sparse name space caused by
+ * file index, symbol index pairs. Dense number are represented
+ * by RNDXRs.
+ */
+
+/*
+ * The following table defines the meaning of each SYM field as
+ * a function of the "st". (scD/B == scData OR scBss)
+ *
+ * Note: the value "isymMac" is used by symbols that have the concept
+ * of enclosing a block of related information. This value is the
+ * isym of the first symbol AFTER the end associated with the primary
+ * symbol. For example if a procedure was at isym==90 and had an
+ * isymMac==155, the associated end would be at isym==154, and the
+ * symbol at 155 would probably (although not necessarily) be the
+ * symbol for the next procedure. This allows rapid skipping over
+ * internal information of various sorts. "stEnd"s ALWAYS have the
+ * isym of the primary symbol that started the block.
+ *
+
+ST SC VALUE INDEX
+-------- ------ -------- ------
+stFile scText address isymMac
+stLabel scText address ---
+stGlobal scD/B address iaux
+stStatic scD/B address iaux
+stParam scAbs offset iaux
+stLocal scAbs offset iaux
+stProc scText address iaux (isymMac is first AUX)
+stStaticProc scText address iaux (isymMac is first AUX)
+
+stMember scNil ordinal --- (if member of enum)
+ (mipsread thinks the case below has a bit, not byte, offset.)
+stMember scNil byte offset iaux (if member of struct/union)
+stMember scBits bit offset iaux (bit field spec)
+
+stBlock scText address isymMac (text block)
+ (the code seems to think that rather than scNil, we see scInfo for
+ the two cases below.)
+stBlock scNil cb isymMac (struct/union member define)
+stBlock scNil cMembers isymMac (enum member define)
+
+ (New types added by SGI to simplify things:)
+stStruct scInfo cb isymMac (struct type define)
+stUnion scInfo cb isymMac (union type define)
+stEnum scInfo cMembers isymMac (enum type define)
+
+stEnd scText address isymStart
+stEnd scNil ------- isymStart (struct/union/enum)
+
+stTypedef scNil ------- iaux
+stRegReloc sc??? value old register number
+stForward sc??? new address isym to original symbol
+
+stConstant scInfo value --- (scalar)
+stConstant scInfo iss --- (complex, e.g. string)
+
+ *
+ */
+#endif
diff --git a/src/base/loader/coff_symconst.h b/src/base/loader/coff_symconst.h
new file mode 100644
index 000000000..f383c19e6
--- /dev/null
+++ b/src/base/loader/coff_symconst.h
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2003, 2005-2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Steve Reinhardt
+ */
+
+/*
+ * Taken from binutils-2.14.90.0.5 include/coff/symconst.h
+ */
+
+/* Declarations of constants for internal format of MIPS ECOFF symbols.
+ Originally contributed by MIPS Computer Systems and Third Eye Software.
+ Changes contributed by Cygnus Support are in the public domain.
+
+ This file is just aggregated with the files that make up the GNU
+ release; it is not considered part of GAS, GDB, or other GNU
+ programs. */
+
+/*
+ * |-----------------------------------------------------------|
+ * | Copyright (c) 1992, 1991, 1990 MIPS Computer Systems, Inc.|
+ * | MIPS Computer Systems, Inc. grants reproduction and use |
+ * | rights to all parties, PROVIDED that this comment is |
+ * | maintained in the copy. |
+ * |-----------------------------------------------------------|
+ */
+
+/* (C) Copyright 1984 by Third Eye Software, Inc.
+ *
+ * Third Eye Software, Inc. grants reproduction and use rights to
+ * all parties, PROVIDED that this comment is maintained in the copy.
+ *
+ * Third Eye makes no claims about the applicability of this
+ * symbol table to a particular use.
+ */
+
+/* glevels for field in FDR */
+#define GLEVEL_0 2
+#define GLEVEL_1 1
+#define GLEVEL_2 0 /* for upward compat reasons. */
+#define GLEVEL_3 3
+
+/* magic number fo symheader */
+#define magicSym 0x7009
+/* The Alpha uses this value instead, for some reason. */
+#define magicSym2 0x1992
+
+/* Language codes */
+#define langC 0
+#define langPascal 1
+#define langFortran 2
+#define langAssembler 3 /* one Assembley inst might map to many mach */
+#define langMachine 4
+#define langNil 5
+#define langAda 6
+#define langPl1 7
+#define langCobol 8
+#define langStdc 9 /* FIXME: Collides with SGI langCplusplus */
+#define langCplusplus 9 /* FIXME: Collides with langStdc */
+#define langCplusplusV2 10 /* SGI addition */
+#define langMax 11 /* maximun allowed 32 -- 5 bits */
+
+/* The following are value definitions for the fields in the SYMR */
+
+/*
+ * Storage Classes
+ */
+
+#define scNil 0
+#define scText 1 /* text symbol */
+#define scData 2 /* initialized data symbol */
+#define scBss 3 /* un-initialized data symbol */
+#define scRegister 4 /* value of symbol is register number */
+#define scAbs 5 /* value of symbol is absolute */
+#define scUndefined 6 /* who knows? */
+#define scCdbLocal 7 /* variable's value is IN se->va.?? */
+#define scBits 8 /* this is a bit field */
+#define scCdbSystem 9 /* variable's value is IN CDB's address space */
+#define scDbx 9 /* overlap dbx internal use */
+#define scRegImage 10 /* register value saved on stack */
+#define scInfo 11 /* symbol contains debugger information */
+#define scUserStruct 12 /* address in struct user for current process */
+#define scSData 13 /* load time only small data */
+#define scSBss 14 /* load time only small common */
+#define scRData 15 /* load time only read only data */
+#define scVar 16 /* Var parameter (fortran,pascal) */
+#define scCommon 17 /* common variable */
+#define scSCommon 18 /* small common */
+#define scVarRegister 19 /* Var parameter in a register */
+#define scVariant 20 /* Variant record */
+#define scSUndefined 21 /* small undefined(external) data */
+#define scInit 22 /* .init section symbol */
+#define scBasedVar 23 /* Fortran or PL/1 ptr based var */
+#define scXData 24 /* exception handling data */
+#define scPData 25 /* Procedure section */
+#define scFini 26 /* .fini section */
+#define scRConst 27 /* .rconst section */
+#define scMax 32
+
+
+/*
+ * Symbol Types
+ */
+
+#define stNil 0 /* Nuthin' special */
+#define stGlobal 1 /* external symbol */
+#define stStatic 2 /* static */
+#define stParam 3 /* procedure argument */
+#define stLocal 4 /* local variable */
+#define stLabel 5 /* label */
+#define stProc 6 /* " " Procedure */
+#define stBlock 7 /* beginnning of block */
+#define stEnd 8 /* end (of anything) */
+#define stMember 9 /* member (of anything - struct/union/enum */
+#define stTypedef 10 /* type definition */
+#define stFile 11 /* file name */
+#define stRegReloc 12 /* register relocation */
+#define stForward 13 /* forwarding address */
+#define stStaticProc 14 /* load time only static procs */
+#define stConstant 15 /* const */
+#define stStaParam 16 /* Fortran static parameters */
+ /* These new symbol types have been recently added to SGI machines. */
+#define stStruct 26 /* Beginning of block defining a struct type */
+#define stUnion 27 /* Beginning of block defining a union type */
+#define stEnum 28 /* Beginning of block defining an enum type */
+#define stIndirect 34 /* Indirect type specification */
+ /* Pseudo-symbols - internal to debugger */
+#define stStr 60 /* string */
+#define stNumber 61 /* pure number (ie. 4 NOR 2+2) */
+#define stExpr 62 /* 2+2 vs. 4 */
+#define stType 63 /* post-coersion SER */
+#define stMax 64
+
+/* definitions for fields in TIR */
+
+/* type qualifiers for ti.tq0 -> ti.(itqMax-1) */
+#define tqNil 0 /* bt is what you see */
+#define tqPtr 1 /* pointer */
+#define tqProc 2 /* procedure */
+#define tqArray 3 /* duh */
+#define tqFar 4 /* longer addressing - 8086/8 land */
+#define tqVol 5 /* volatile */
+#define tqConst 6 /* const */
+#define tqMax 8
+
+/* basic types as seen in ti.bt */
+#define btNil 0 /* undefined (also, enum members) */
+#define btAdr 1 /* address - integer same size as pointer */
+#define btChar 2 /* character */
+#define btUChar 3 /* unsigned character */
+#define btShort 4 /* short */
+#define btUShort 5 /* unsigned short */
+#define btInt 6 /* int */
+#define btUInt 7 /* unsigned int */
+#define btLong 8 /* long */
+#define btULong 9 /* unsigned long */
+#define btFloat 10 /* float (real) */
+#define btDouble 11 /* Double (real) */
+#define btStruct 12 /* Structure (Record) */
+#define btUnion 13 /* Union (variant) */
+#define btEnum 14 /* Enumerated */
+#define btTypedef 15 /* defined via a typedef, isymRef points */
+#define btRange 16 /* subrange of int */
+#define btSet 17 /* pascal sets */
+#define btComplex 18 /* fortran complex */
+#define btDComplex 19 /* fortran double complex */
+#define btIndirect 20 /* forward or unnamed typedef */
+#define btFixedDec 21 /* Fixed Decimal */
+#define btFloatDec 22 /* Float Decimal */
+#define btString 23 /* Varying Length Character String */
+#define btBit 24 /* Aligned Bit String */
+#define btPicture 25 /* Picture */
+#define btVoid 26 /* void */
+#define btLongLong 27 /* long long */
+#define btULongLong 28 /* unsigned long long */
+#define btMax 64
diff --git a/src/base/loader/ecoff_object.cc b/src/base/loader/ecoff_object.cc
new file mode 100644
index 000000000..80917ee9c
--- /dev/null
+++ b/src/base/loader/ecoff_object.cc
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string>
+
+#include "base/loader/ecoff_object.hh"
+#include "base/misc.hh"
+#include "base/loader/symtab.hh"
+
+#include "base/trace.hh" // for DPRINTF
+
+#include "base/loader/exec_ecoff.h"
+#include "base/loader/coff_sym.h"
+#include "base/loader/coff_symconst.h"
+
+using namespace std;
+
+ObjectFile *
+EcoffObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data)
+{
+ if (((ecoff_filehdr *)data)->f_magic == ECOFF_MAGIC_ALPHA) {
+ // it's Alpha ECOFF
+ return new EcoffObject(fname, fd, len, data,
+ ObjectFile::Alpha, ObjectFile::Tru64);
+ }
+ else {
+ return NULL;
+ }
+}
+
+
+EcoffObject::EcoffObject(const string &_filename, int _fd,
+ size_t _len, uint8_t *_data,
+ Arch _arch, OpSys _opSys)
+ : ObjectFile(_filename, _fd, _len, _data, _arch, _opSys)
+{
+ execHdr = (ecoff_exechdr *)fileData;
+ fileHdr = &(execHdr->f);
+ aoutHdr = &(execHdr->a);
+
+ entry = aoutHdr->entry;
+
+ text.baseAddr = aoutHdr->text_start;
+ text.size = aoutHdr->tsize;
+ text.fileImage = fileData + ECOFF_TXTOFF(execHdr);
+
+ data.baseAddr = aoutHdr->data_start;
+ data.size = aoutHdr->dsize;
+ data.fileImage = fileData + ECOFF_DATOFF(execHdr);
+
+ bss.baseAddr = aoutHdr->bss_start;
+ bss.size = aoutHdr->bsize;
+ bss.fileImage = NULL;
+
+ DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n",
+ text.baseAddr, text.size, data.baseAddr, data.size,
+ bss.baseAddr, bss.size);
+}
+
+
+bool
+EcoffObject::loadGlobalSymbols(SymbolTable *symtab)
+{
+ if (!symtab)
+ return false;
+
+ if (fileHdr->f_magic != ECOFF_MAGIC_ALPHA) {
+ warn("loadGlobalSymbols: wrong magic on %s\n", filename);
+ return false;
+ }
+
+ ecoff_symhdr *syms = (ecoff_symhdr *)(fileData + fileHdr->f_symptr);
+ if (syms->magic != magicSym2) {
+ warn("loadGlobalSymbols: bad symbol header magic on %s\n", filename);
+ return false;
+ }
+
+ ecoff_extsym *ext_syms = (ecoff_extsym *)(fileData + syms->cbExtOffset);
+
+ char *ext_strings = (char *)(fileData + syms->cbSsExtOffset);
+ for (int i = 0; i < syms->iextMax; i++) {
+ ecoff_sym *entry = &(ext_syms[i].asym);
+ if (entry->iss != -1)
+ symtab->insert(entry->value, ext_strings + entry->iss);
+ }
+
+ return true;
+}
+
+bool
+EcoffObject::loadLocalSymbols(SymbolTable *symtab)
+{
+ if (!symtab)
+ return false;
+
+ if (fileHdr->f_magic != ECOFF_MAGIC_ALPHA) {
+ warn("loadGlobalSymbols: wrong magic on %s\n", filename);
+ return false;
+ }
+
+ ecoff_symhdr *syms = (ecoff_symhdr *)(fileData + fileHdr->f_symptr);
+ if (syms->magic != magicSym2) {
+ warn("loadGlobalSymbols: bad symbol header magic on %s\n", filename);
+ return false;
+ }
+
+ ecoff_sym *local_syms = (ecoff_sym *)(fileData + syms->cbSymOffset);
+ char *local_strings = (char *)(fileData + syms->cbSsOffset);
+ ecoff_fdr *fdesc = (ecoff_fdr *)(fileData + syms->cbFdOffset);
+
+ for (int i = 0; i < syms->ifdMax; i++) {
+ ecoff_sym *entry = (ecoff_sym *)(local_syms + fdesc[i].isymBase);
+ char *strings = (char *)(local_strings + fdesc[i].issBase);
+ for (int j = 0; j < fdesc[i].csym; j++) {
+ if (entry[j].st == stGlobal || entry[j].st == stProc)
+ if (entry[j].iss != -1)
+ symtab->insert(entry[j].value, strings + entry[j].iss);
+ }
+ }
+
+ for (int i = 0; i < syms->isymMax; i++) {
+ ecoff_sym *entry = &(local_syms[i]);
+ if (entry->st == stProc)
+ symtab->insert(entry->value, local_strings + entry->iss);
+ }
+
+ return true;
+}
diff --git a/src/base/loader/ecoff_object.hh b/src/base/loader/ecoff_object.hh
new file mode 100644
index 000000000..603c70bec
--- /dev/null
+++ b/src/base/loader/ecoff_object.hh
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ECOFF_OBJECT_HH__
+#define __ECOFF_OBJECT_HH__
+
+#include "base/loader/object_file.hh"
+
+// forward decls: avoid including exec_ecoff.h here
+struct ecoff_exechdr;
+struct ecoff_filehdr;
+struct ecoff_aouthdr;
+
+class EcoffObject : public ObjectFile
+{
+ protected:
+ ecoff_exechdr *execHdr;
+ ecoff_filehdr *fileHdr;
+ ecoff_aouthdr *aoutHdr;
+
+ EcoffObject(const std::string &_filename, int _fd,
+ size_t _len, uint8_t *_data,
+ Arch _arch, OpSys _opSys);
+
+ public:
+ virtual ~EcoffObject() {}
+
+ virtual bool loadGlobalSymbols(SymbolTable *symtab);
+ virtual bool loadLocalSymbols(SymbolTable *symtab);
+
+ static ObjectFile *tryFile(const std::string &fname, int fd,
+ size_t len, uint8_t *data);
+};
+
+#endif // __ECOFF_OBJECT_HH__
diff --git a/src/base/loader/elf_object.cc b/src/base/loader/elf_object.cc
new file mode 100644
index 000000000..165501e1c
--- /dev/null
+++ b/src/base/loader/elf_object.cc
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string>
+
+// Because of the -Wundef flag we have to do this
+#define __LIBELF_INTERNAL__ 0
+// counterintuitive, but the flag below causes libelf to define
+// 64-bit elf types that apparently didn't exist in some older
+// versions of Linux. They seem to be there in 2.4.x, so don't
+// set this now (it causes things to break on 64-bit platforms).
+#define __LIBELF64_LINUX 0
+#define __LIBELF_NEED_LINK_H 0
+#define __LIBELF_SYMBOL_VERSIONS 0
+
+#include "libelf/libelf.h"
+#include "libelf/gelf.h"
+
+#include "base/loader/elf_object.hh"
+#include "base/misc.hh"
+
+#include "base/loader/symtab.hh"
+
+#include "base/trace.hh" // for DPRINTF
+
+#include "sim/byteswap.hh"
+
+
+using namespace std;
+
+ObjectFile *
+ElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data)
+{
+ Elf *elf;
+ GElf_Ehdr ehdr;
+ Arch arch = UnknownArch;
+ OpSys opSys = UnknownOpSys;
+
+ // check that header matches library version
+ if (elf_version(EV_CURRENT) == EV_NONE)
+ panic("wrong elf version number!");
+
+ // get a pointer to elf structure
+ elf = elf_memory((char*)data,len);
+ // will only fail if fd is invalid
+ assert(elf != NULL);
+
+ // Check that we actually have a elf file
+ if (gelf_getehdr(elf, &ehdr) ==0) {
+ DPRINTFR(Loader, "Not ELF\n");
+ elf_end(elf);
+ return NULL;
+ } else {
+ //Detect the architecture
+ //Since we don't know how to check for alpha right now, we'll
+ //just assume if it wasn't something else and it's 64 bit, that's
+ //what it must be.
+ if (ehdr.e_machine == EM_SPARC64 ||
+ ehdr.e_machine == EM_SPARC ||
+ ehdr.e_machine == EM_SPARCV9) {
+ arch = ObjectFile::SPARC;
+ } else if (ehdr.e_machine == EM_MIPS
+ && ehdr.e_ident[EI_CLASS] == ELFCLASS32) {
+ arch = ObjectFile::Mips;
+ } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) {
+ arch = ObjectFile::Alpha;
+ } else {
+ warn("Unknown architecture: %d\n", ehdr.e_machine);
+ arch = ObjectFile::UnknownArch;
+ }
+
+ //Detect the operating system
+ switch (ehdr.e_ident[EI_OSABI])
+ {
+
+ case ELFOSABI_LINUX:
+ opSys = ObjectFile::Linux;
+ break;
+ case ELFOSABI_SOLARIS:
+ opSys = ObjectFile::Solaris;
+ break;
+ case ELFOSABI_TRU64:
+ opSys = ObjectFile::Tru64;
+ break;
+ default:
+ opSys = ObjectFile::UnknownOpSys;
+ }
+
+ //take a look at the .note.ABI section
+ //It can let us know what's what.
+ if (opSys == ObjectFile::UnknownOpSys) {
+ Elf_Scn *section;
+ GElf_Shdr shdr;
+ Elf_Data *data;
+ uint32_t osAbi;;
+ int secIdx = 1;
+
+ // Get the first section
+ section = elf_getscn(elf, secIdx);
+
+ // While there are no more sections
+ while (section != NULL && opSys == ObjectFile::UnknownOpSys) {
+ gelf_getshdr(section, &shdr);
+ if (shdr.sh_type == SHT_NOTE && !strcmp(".note.ABI-tag",
+ elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) {
+ // we have found a ABI note section
+ // Check the 5th 32bit word for OS 0 == linux, 1 == hurd,
+ // 2 == solaris, 3 == freebsd
+ data = elf_rawdata(section, NULL);
+ assert(data->d_buf);
+ if(ehdr.e_ident[EI_DATA] == ELFDATA2LSB)
+ osAbi = htole(((uint32_t*)data->d_buf)[4]);
+ else
+ osAbi = htobe(((uint32_t*)data->d_buf)[4]);
+
+ switch(osAbi) {
+ case 0:
+ opSys = ObjectFile::Linux;
+ break;
+ case 2:
+ opSys = ObjectFile::Solaris;
+ break;
+ }
+ } // if section found
+ if (!strcmp(".SUNW_version", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name)))
+ opSys = ObjectFile::Solaris;
+ if (!strcmp(".stab.index", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name)))
+ opSys = ObjectFile::Solaris;
+
+ section = elf_getscn(elf, ++secIdx);
+ } // while sections
+ }
+
+ elf_end(elf);
+ return new ElfObject(fname, fd, len, data, arch, opSys);
+ }
+}
+
+
+ElfObject::ElfObject(const string &_filename, int _fd,
+ size_t _len, uint8_t *_data,
+ Arch _arch, OpSys _opSys)
+ : ObjectFile(_filename, _fd, _len, _data, _arch, _opSys)
+
+{
+ Elf *elf;
+ GElf_Ehdr ehdr;
+
+ // check that header matches library version
+ if (elf_version(EV_CURRENT) == EV_NONE)
+ panic("wrong elf version number!");
+
+ // get a pointer to elf structure
+ elf = elf_memory((char*)fileData,len);
+ // will only fail if fd is invalid
+ assert(elf != NULL);
+
+ // Check that we actually have a elf file
+ if (gelf_getehdr(elf, &ehdr) ==0) {
+ panic("Not ELF, shouldn't be here");
+ }
+
+ entry = ehdr.e_entry;
+
+
+ // initialize segment sizes to 0 in case they're not present
+ text.size = data.size = bss.size = 0;
+
+ for (int i = 0; i < ehdr.e_phnum; ++i) {
+ GElf_Phdr phdr;
+ if (gelf_getphdr(elf, i, &phdr) == 0) {
+ panic("gelf_getphdr failed for section %d", i);
+ }
+
+ // for now we don't care about non-loadable segments
+ if (!(phdr.p_type & PT_LOAD))
+ continue;
+
+ // the headers don't explicitly distinguish text from data,
+ // but empirically the text segment comes first.
+ if (text.size == 0) { // haven't seen text segment yet
+ text.baseAddr = phdr.p_vaddr;
+ text.size = phdr.p_filesz;
+ text.fileImage = fileData + phdr.p_offset;
+ // if there's any padding at the end that's not in the
+ // file, call it the bss. This happens in the "text"
+ // segment if there's only one loadable segment (as for
+ // kernel images).
+ bss.size = phdr.p_memsz - phdr.p_filesz;
+ bss.baseAddr = phdr.p_vaddr + phdr.p_filesz;
+ bss.fileImage = NULL;
+ } else if (data.size == 0) { // have text, this must be data
+ data.baseAddr = phdr.p_vaddr;
+ data.size = phdr.p_filesz;
+ data.fileImage = fileData + phdr.p_offset;
+ // if there's any padding at the end that's not in the
+ // file, call it the bss. Warn if this happens for both
+ // the text & data segments (should only have one bss).
+ if (phdr.p_memsz - phdr.p_filesz > 0 && bss.size != 0) {
+ warn("Two implied bss segments in file!\n");
+ }
+ bss.size = phdr.p_memsz - phdr.p_filesz;
+ bss.baseAddr = phdr.p_vaddr + phdr.p_filesz;
+ bss.fileImage = NULL;
+ } else {
+ warn("More than two loadable segments in ELF object.");
+ warn("Ignoring segment @ 0x%x length 0x%x.",
+ phdr.p_vaddr, phdr.p_filesz);
+ }
+ }
+
+ // should have found at least one loadable segment
+ assert(text.size != 0);
+
+ DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n",
+ text.baseAddr, text.size, data.baseAddr, data.size,
+ bss.baseAddr, bss.size);
+
+ elf_end(elf);
+
+ // We will actually read the sections when we need to load them
+}
+
+
+bool
+ElfObject::loadSomeSymbols(SymbolTable *symtab, int binding)
+{
+ Elf *elf;
+ int sec_idx = 1; // there is a 0 but it is nothing, go figure
+ Elf_Scn *section;
+ GElf_Shdr shdr;
+ Elf_Data *data;
+ int count, ii;
+ bool found = false;
+ GElf_Sym sym;
+
+ if (!symtab)
+ return false;
+
+ // check that header matches library version
+ if (elf_version(EV_CURRENT) == EV_NONE)
+ panic("wrong elf version number!");
+
+ // get a pointer to elf structure
+ elf = elf_memory((char*)fileData,len);
+
+ assert(elf != NULL);
+
+ // Get the first section
+ section = elf_getscn(elf, sec_idx);
+
+ // While there are no more sections
+ while (section != NULL) {
+ gelf_getshdr(section, &shdr);
+
+ if (shdr.sh_type == SHT_SYMTAB) {
+ found = true;
+ data = elf_getdata(section, NULL);
+ count = shdr.sh_size / shdr.sh_entsize;
+ DPRINTF(Loader, "Found Symbol Table, %d symbols present\n", count);
+
+ // loop through all the symbols, only loading global ones
+ for (ii = 0; ii < count; ++ii) {
+ gelf_getsym(data, ii, &sym);
+ if (GELF_ST_BIND(sym.st_info) == binding) {
+ symtab->insert(sym.st_value,
+ elf_strptr(elf, shdr.sh_link, sym.st_name));
+ }
+ }
+ }
+ ++sec_idx;
+ section = elf_getscn(elf, sec_idx);
+ }
+
+ elf_end(elf);
+
+ return found;
+}
+
+bool
+ElfObject::loadGlobalSymbols(SymbolTable *symtab)
+{
+ return loadSomeSymbols(symtab, STB_GLOBAL);
+}
+
+bool
+ElfObject::loadLocalSymbols(SymbolTable *symtab)
+{
+ return loadSomeSymbols(symtab, STB_LOCAL);
+}
diff --git a/src/base/loader/elf_object.hh b/src/base/loader/elf_object.hh
new file mode 100644
index 000000000..72c265edd
--- /dev/null
+++ b/src/base/loader/elf_object.hh
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ELF_OBJECT_HH__
+#define __ELF_OBJECT_HH__
+
+#include "base/loader/object_file.hh"
+
+class ElfObject : public ObjectFile
+{
+ protected:
+
+ /// Helper functions for loadGlobalSymbols() and loadLocalSymbols().
+ bool loadSomeSymbols(SymbolTable *symtab, int binding);
+
+ ElfObject(const std::string &_filename, int _fd,
+ size_t _len, uint8_t *_data,
+ Arch _arch, OpSys _opSys);
+
+ public:
+ virtual ~ElfObject() {}
+
+ virtual bool loadGlobalSymbols(SymbolTable *symtab);
+ virtual bool loadLocalSymbols(SymbolTable *symtab);
+
+ static ObjectFile *tryFile(const std::string &fname, int fd,
+ size_t len, uint8_t *data);
+};
+
+#endif // __ELF_OBJECT_HH__
diff --git a/src/base/loader/exec_aout.h b/src/base/loader/exec_aout.h
new file mode 100644
index 000000000..eed44baee
--- /dev/null
+++ b/src/base/loader/exec_aout.h
@@ -0,0 +1,61 @@
+/*
+ * Taken from NetBSD sys/exec_aout.h
+ */
+
+/* $NetBSD: exec_aout.h,v 1.29 2002/12/10 17:14:31 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1993, 1994 Christopher G. Demetriou
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Christopher G. Demetriou.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SYS_EXEC_AOUT_H_
+#define _SYS_EXEC_AOUT_H_
+
+#ifndef N_PAGSIZ
+#define N_PAGSIZ(ex) (AOUT_LDPGSZ)
+#endif
+
+/* a_magic */
+#define OMAGIC 0407 /* old impure format */
+#define NMAGIC 0410 /* read-only text */
+#define ZMAGIC 0413 /* demand load format */
+
+#define N_ALIGN(ex,x) \
+ (N_GETMAGIC(ex) == ZMAGIC ? \
+ ((x) + AOUT_LDPGSZ - 1) & ~(AOUT_LDPGSZ - 1) : (x))
+
+/* Valid magic number check. */
+#define N_BADMAG(ex) \
+ (N_GETMAGIC(ex) != NMAGIC && N_GETMAGIC(ex) != OMAGIC && \
+ N_GETMAGIC(ex) != ZMAGIC)
+
+//Only alpha will be able to load aout for now
+#include "arch/alpha/aout_machdep.h"
+
+#endif /* !_SYS_EXEC_AOUT_H_ */
diff --git a/src/base/loader/exec_ecoff.h b/src/base/loader/exec_ecoff.h
new file mode 100644
index 000000000..555589806
--- /dev/null
+++ b/src/base/loader/exec_ecoff.h
@@ -0,0 +1,110 @@
+/*
+ * Taken from NetBSD sys/exec_ecoff.h
+ */
+
+/* $NetBSD: exec_ecoff.h,v 1.13 2003/01/18 09:53:18 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1994 Adam Glass
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Adam Glass.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SYS_EXEC_ECOFF_H_
+#define _SYS_EXEC_ECOFF_H_
+
+//Only alpha will be able to load ecoff files for now
+#include "arch/alpha/ecoff_machdep.h"
+
+struct ecoff_filehdr {
+ coff_ushort f_magic; /* magic number */
+ coff_ushort f_nscns; /* # of sections */
+ coff_uint f_timdat; /* time and date stamp */
+ coff_ulong f_symptr; /* file offset of symbol table */
+ coff_uint f_nsyms; /* # of symbol table entries */
+ coff_ushort f_opthdr; /* sizeof the optional header */
+ coff_ushort f_flags; /* flags??? */
+};
+
+struct ecoff_aouthdr {
+ coff_ushort magic;
+ coff_ushort vstamp;
+ ECOFF_PAD
+ coff_ulong tsize;
+ coff_ulong dsize;
+ coff_ulong bsize;
+ coff_ulong entry;
+ coff_ulong text_start;
+ coff_ulong data_start;
+ coff_ulong bss_start;
+ ECOFF_MACHDEP;
+};
+
+struct ecoff_scnhdr { /* needed for size info */
+ char s_name[8]; /* name */
+ coff_ulong s_paddr; /* physical addr? for ROMing?*/
+ coff_ulong s_vaddr; /* virtual addr? */
+ coff_ulong s_size; /* size */
+ coff_ulong s_scnptr; /* file offset of raw data */
+ coff_ulong s_relptr; /* file offset of reloc data */
+ coff_ulong s_lnnoptr; /* file offset of line data */
+ coff_ushort s_nreloc; /* # of relocation entries */
+ coff_ushort s_nlnno; /* # of line entries */
+ coff_uint s_flags; /* flags */
+};
+
+struct ecoff_exechdr {
+ struct ecoff_filehdr f;
+ struct ecoff_aouthdr a;
+};
+
+#define ECOFF_HDR_SIZE (sizeof(struct ecoff_exechdr))
+
+#define ECOFF_OMAGIC 0407
+#define ECOFF_NMAGIC 0410
+#define ECOFF_ZMAGIC 0413
+
+#define ECOFF_ROUND(value, by) \
+ (((value) + (by) - 1) & ~((by) - 1))
+
+#define ECOFF_BLOCK_ALIGN(ep, value) \
+ ((ep)->a.magic == ECOFF_ZMAGIC ? ECOFF_ROUND((value), ECOFF_LDPGSZ) : \
+ (value))
+
+#define ECOFF_TXTOFF(ep) \
+ ((ep)->a.magic == ECOFF_ZMAGIC ? 0 : \
+ ECOFF_ROUND(ECOFF_HDR_SIZE + (ep)->f.f_nscns * \
+ sizeof(struct ecoff_scnhdr), ECOFF_SEGMENT_ALIGNMENT(ep)))
+
+#define ECOFF_DATOFF(ep) \
+ (ECOFF_BLOCK_ALIGN((ep), ECOFF_TXTOFF(ep) + (ep)->a.tsize))
+
+#define ECOFF_SEGMENT_ALIGN(ep, value) \
+ (ECOFF_ROUND((value), ((ep)->a.magic == ECOFF_ZMAGIC ? ECOFF_LDPGSZ : \
+ ECOFF_SEGMENT_ALIGNMENT(ep))))
+
+#endif /* !_SYS_EXEC_ECOFF_H_ */
diff --git a/src/base/loader/object_file.cc b/src/base/loader/object_file.cc
new file mode 100644
index 000000000..c6dfced1d
--- /dev/null
+++ b/src/base/loader/object_file.cc
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2002-2004 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <list>
+#include <string>
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "base/cprintf.hh"
+#include "base/loader/object_file.hh"
+#include "base/loader/symtab.hh"
+
+#include "base/loader/ecoff_object.hh"
+#include "base/loader/aout_object.hh"
+#include "base/loader/elf_object.hh"
+
+#include "mem/translating_port.hh"
+
+using namespace std;
+
+ObjectFile::ObjectFile(const string &_filename, int _fd,
+ size_t _len, uint8_t *_data,
+ Arch _arch, OpSys _opSys)
+ : filename(_filename), descriptor(_fd), fileData(_data), len(_len),
+ arch(_arch), opSys(_opSys)
+{
+}
+
+
+ObjectFile::~ObjectFile()
+{
+ close();
+}
+
+
+bool
+ObjectFile::loadSection(Section *sec, Port *memPort, Addr addrMask)
+{
+ if (sec->size != 0) {
+ Addr addr = sec->baseAddr & addrMask;
+ if (sec->fileImage) {
+ memPort->writeBlob(addr, sec->fileImage, sec->size);
+ }
+ else {
+ // no image: must be bss
+ memPort->memsetBlob(addr, 0, sec->size);
+ }
+ }
+ return true;
+}
+
+
+bool
+ObjectFile::loadSections(Port *memPort, Addr addrMask)
+{
+ return (loadSection(&text, memPort, addrMask)
+ && loadSection(&data, memPort, addrMask)
+ && loadSection(&bss, memPort, addrMask));
+}
+
+
+void
+ObjectFile::close()
+{
+ if (descriptor >= 0) {
+ ::close(descriptor);
+ descriptor = -1;
+ }
+
+ if (fileData) {
+ ::munmap(fileData, len);
+ fileData = NULL;
+ }
+}
+
+
+ObjectFile *
+createObjectFile(const string &fname)
+{
+ // open the file
+ int fd = open(fname.c_str(), O_RDONLY);
+ if (fd < 0) {
+ return NULL;
+ }
+
+ // find the length of the file by seeking to the end
+ size_t len = (size_t)lseek(fd, 0, SEEK_END);
+
+ // mmap the whole shebang
+ uint8_t *fileData =
+ (uint8_t *)mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);
+ if (fileData == MAP_FAILED) {
+ close(fd);
+ return NULL;
+ }
+
+ ObjectFile *fileObj = NULL;
+
+ // figure out what we have here
+ if ((fileObj = EcoffObject::tryFile(fname, fd, len, fileData)) != NULL) {
+ return fileObj;
+ }
+
+ if ((fileObj = AoutObject::tryFile(fname, fd, len, fileData)) != NULL) {
+ return fileObj;
+ }
+
+ if ((fileObj = ElfObject::tryFile(fname, fd, len, fileData)) != NULL) {
+ return fileObj;
+ }
+
+ // don't know what it is
+ close(fd);
+ munmap(fileData, len);
+ return NULL;
+}
diff --git a/src/base/loader/object_file.hh b/src/base/loader/object_file.hh
new file mode 100644
index 000000000..b43989cb5
--- /dev/null
+++ b/src/base/loader/object_file.hh
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2002-2004 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __OBJECT_FILE_HH__
+#define __OBJECT_FILE_HH__
+
+#include <limits>
+#include <string>
+
+#include "sim/host.hh" // for Addr
+
+class Port;
+class SymbolTable;
+
+class ObjectFile
+{
+ public:
+
+ enum Arch {
+ UnknownArch,
+ Alpha,
+ SPARC,
+ Mips
+ };
+
+ enum OpSys {
+ UnknownOpSys,
+ Tru64,
+ Linux,
+ Solaris
+ };
+
+ protected:
+ const std::string filename;
+ int descriptor;
+ uint8_t *fileData;
+ size_t len;
+
+ Arch arch;
+ OpSys opSys;
+
+ ObjectFile(const std::string &_filename, int _fd,
+ size_t _len, uint8_t *_data,
+ Arch _arch, OpSys _opSys);
+
+ public:
+ virtual ~ObjectFile();
+
+ void close();
+
+ virtual bool loadSections(Port *memPort, Addr addrMask =
+ std::numeric_limits<Addr>::max());
+ virtual bool loadGlobalSymbols(SymbolTable *symtab) = 0;
+ virtual bool loadLocalSymbols(SymbolTable *symtab) = 0;
+
+ Arch getArch() const { return arch; }
+ OpSys getOpSys() const { return opSys; }
+
+ protected:
+
+ struct Section {
+ Addr baseAddr;
+ uint8_t *fileImage;
+ size_t size;
+ };
+
+ Addr entry;
+ Addr globalPtr;
+
+ Section text;
+ Section data;
+ Section bss;
+
+ bool loadSection(Section *sec, Port *memPort, Addr addrMask);
+ void setGlobalPointer(Addr global_ptr) { globalPtr = global_ptr; }
+
+ public:
+ Addr entryPoint() const { return entry; }
+
+ Addr globalPointer() const { return globalPtr; }
+
+ Addr textBase() const { return text.baseAddr; }
+ Addr dataBase() const { return data.baseAddr; }
+ Addr bssBase() const { return bss.baseAddr; }
+
+ size_t textSize() const { return text.size; }
+ size_t dataSize() const { return data.size; }
+ size_t bssSize() const { return bss.size; }
+};
+
+ObjectFile *createObjectFile(const std::string &fname);
+
+
+#endif // __OBJECT_FILE_HH__
diff --git a/src/base/loader/symtab.cc b/src/base/loader/symtab.cc
new file mode 100644
index 000000000..25f54f9bf
--- /dev/null
+++ b/src/base/loader/symtab.cc
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+
+#include "base/loader/symtab.hh"
+#include "base/misc.hh"
+#include "base/str.hh"
+#include "sim/host.hh"
+#include "sim/serialize.hh"
+
+using namespace std;
+
+SymbolTable *debugSymbolTable = NULL;
+
+void
+SymbolTable::clear()
+{
+ addrTable.clear();
+ symbolTable.clear();
+}
+
+bool
+SymbolTable::insert(Addr address, string symbol)
+{
+ if (symbol.empty())
+ return false;
+
+ if (!addrTable.insert(make_pair(address, symbol)).second)
+ return false;
+
+ if (!symbolTable.insert(make_pair(symbol, address)).second)
+ return false;
+
+ return true;
+}
+
+
+bool
+SymbolTable::load(const string &filename)
+{
+ string buffer;
+ ifstream file(filename.c_str());
+
+ if (!file)
+ fatal("file error: Can't open symbol table file %s\n", filename);
+
+ while (!file.eof()) {
+ getline(file, buffer);
+ if (buffer.empty())
+ continue;
+
+ int idx = buffer.find(',');
+ if (idx == string::npos)
+ return false;
+
+ string address = buffer.substr(0, idx);
+ eat_white(address);
+ if (address.empty())
+ return false;
+
+ string symbol = buffer.substr(idx + 1);
+ eat_white(symbol);
+ if (symbol.empty())
+ return false;
+
+ Addr addr;
+ if (!to_number(address, addr))
+ return false;
+
+ if (!insert(addr, symbol))
+ return false;
+ }
+
+ file.close();
+
+ return true;
+}
+
+void
+SymbolTable::serialize(const string &base, ostream &os)
+{
+ paramOut(os, base + ".size", addrTable.size());
+
+ int i = 0;
+ ATable::const_iterator p, end = addrTable.end();
+ for (p = addrTable.begin(); p != end; ++p) {
+ paramOut(os, csprintf("%s.addr_%d", base, i), p->first);
+ paramOut(os, csprintf("%s.symbol_%d", base, i), p->second);
+ ++i;
+ }
+}
+
+void
+SymbolTable::unserialize(const string &base, Checkpoint *cp,
+ const string &section)
+{
+ clear();
+ int size;
+ paramIn(cp, section, base + ".size", size);
+ for (int i = 0; i < size; ++i) {
+ Addr addr;
+ std::string symbol;
+
+ paramIn(cp, section, csprintf("%s.addr_%d", base, i), addr);
+ paramIn(cp, section, csprintf("%s.symbol_%d", base, i), symbol);
+ insert(addr, symbol);
+ }
+}
diff --git a/src/base/loader/symtab.hh b/src/base/loader/symtab.hh
new file mode 100644
index 000000000..ebcda1345
--- /dev/null
+++ b/src/base/loader/symtab.hh
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SYMTAB_HH__
+#define __SYMTAB_HH__
+
+#include <iosfwd>
+#include <map>
+
+#include "arch/isa_traits.hh" // for Addr
+
+class Checkpoint;
+class SymbolTable
+{
+ public:
+ typedef std::map<Addr, std::string> ATable;
+ typedef std::map<std::string, Addr> STable;
+
+ private:
+ ATable addrTable;
+ STable symbolTable;
+
+ private:
+ bool
+ upperBound(Addr addr, ATable::const_iterator &iter) const
+ {
+ // find first key *larger* than desired address
+ iter = addrTable.upper_bound(addr);
+
+ // if very first key is larger, we're out of luck
+ if (iter == addrTable.begin())
+ return false;
+
+ return true;
+ }
+
+ public:
+ SymbolTable() {}
+ SymbolTable(const std::string &file) { load(file); }
+ ~SymbolTable() {}
+
+ void clear();
+ bool insert(Addr address, std::string symbol);
+ bool load(const std::string &file);
+
+ const ATable &getAddrTable() const { return addrTable; }
+ const STable &getSymbolTable() const { return symbolTable; }
+
+ public:
+ void serialize(const std::string &base, std::ostream &os);
+ void unserialize(const std::string &base, Checkpoint *cp,
+ const std::string &section);
+
+ public:
+ bool
+ findSymbol(Addr address, std::string &symbol) const
+ {
+ ATable::const_iterator i = addrTable.find(address);
+ if (i == addrTable.end())
+ return false;
+
+ symbol = (*i).second;
+ return true;
+ }
+
+ bool
+ findAddress(const std::string &symbol, Addr &address) const
+ {
+ STable::const_iterator i = symbolTable.find(symbol);
+ if (i == symbolTable.end())
+ return false;
+
+ address = (*i).second;
+ return true;
+ }
+
+ /// Find the nearest symbol equal to or less than the supplied
+ /// address (e.g., the label for the enclosing function).
+ /// @param address The address to look up.
+ /// @param symbol Return reference for symbol string.
+ /// @param sym_address Return reference for symbol address.
+ /// @param next_sym_address Address of following symbol (for
+ /// determining valid range of symbol).
+ /// @retval True if a symbol was found.
+ bool
+ findNearestSymbol(Addr addr, std::string &symbol, Addr &symaddr,
+ Addr &nextaddr) const
+ {
+ ATable::const_iterator i;
+ if (!upperBound(addr, i))
+ return false;
+
+ nextaddr = i->first;
+ --i;
+ symaddr = i->first;
+ symbol = i->second;
+ return true;
+ }
+
+ /// Overload for findNearestSymbol() for callers who don't care
+ /// about next_sym_address.
+ bool
+ findNearestSymbol(Addr addr, std::string &symbol, Addr &symaddr) const
+ {
+ ATable::const_iterator i;
+ if (!upperBound(addr, i))
+ return false;
+
+ --i;
+ symaddr = i->first;
+ symbol = i->second;
+ return true;
+ }
+
+
+ bool
+ findNearestAddr(Addr addr, Addr &symaddr, Addr &nextaddr) const
+ {
+ ATable::const_iterator i;
+ if (!upperBound(addr, i))
+ return false;
+
+ nextaddr = i->first;
+ --i;
+ symaddr = i->first;
+ return true;
+ }
+
+ bool
+ findNearestAddr(Addr addr, Addr &symaddr) const
+ {
+ ATable::const_iterator i;
+ if (!upperBound(addr, i))
+ return false;
+
+ --i;
+ symaddr = i->first;
+ return true;
+ }
+};
+
+/// Global unified debugging symbol table (for target). Conceptually
+/// there should be one of these per System object for full system,
+/// and per Process object for non-full-system, but so far one big
+/// global one has worked well enough.
+extern SymbolTable *debugSymbolTable;
+
+#endif // __SYMTAB_HH__
diff --git a/src/base/match.cc b/src/base/match.cc
new file mode 100644
index 000000000..4f1f49b57
--- /dev/null
+++ b/src/base/match.cc
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "base/match.hh"
+#include "base/str.hh"
+
+using namespace std;
+
+ObjectMatch::ObjectMatch()
+{
+}
+
+ObjectMatch::ObjectMatch(const string &expr)
+{
+ setExpression(expr);
+}
+
+void
+ObjectMatch::setExpression(const string &expr)
+{
+ tokens.resize(1);
+ tokenize(tokens[0], expr, '.');
+}
+
+void
+ObjectMatch::setExpression(const vector<string> &expr)
+{
+ if (expr.empty()) {
+ tokens.resize(0);
+ } else {
+ tokens.resize(expr.size());
+ for (int i = 0; i < expr.size(); ++i)
+ tokenize(tokens[i], expr[i], '.');
+ }
+}
+
+/**
+ * @todo this should probably be changed to just use regular
+ * expression code
+ */
+bool
+ObjectMatch::domatch(const string &name) const
+{
+ vector<string> name_tokens;
+ tokenize(name_tokens, name, '.');
+ int ntsize = name_tokens.size();
+
+ int num_expr = tokens.size();
+ for (int i = 0; i < num_expr; ++i) {
+ const vector<string> &token = tokens[i];
+ int jstop = token.size();
+
+ bool match = true;
+ for (int j = 0; j < jstop; ++j) {
+ if (j >= ntsize)
+ break;
+
+ const string &var = token[j];
+ if (var != "*" && var != name_tokens[j]) {
+ match = false;
+ break;
+ }
+ }
+
+ if (match == true)
+ return true;
+ }
+
+ return false;
+}
+
diff --git a/src/base/match.hh b/src/base/match.hh
new file mode 100644
index 000000000..1b0a083a7
--- /dev/null
+++ b/src/base/match.hh
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* @file
+ * User Console Definitions
+ */
+
+#ifndef __BASE_MATCH_HH__
+#define __BASE_MATCH_HH__
+
+#include <string>
+#include <vector>
+
+class ObjectMatch
+{
+ protected:
+ std::vector<std::vector<std::string> > tokens;
+ bool domatch(const std::string &name) const;
+
+ public:
+ ObjectMatch();
+ ObjectMatch(const std::string &expression);
+ void setExpression(const std::string &expression);
+ void setExpression(const std::vector<std::string> &expression);
+ bool match(const std::string &name) const
+ {
+ return tokens.empty() ? false : domatch(name);
+ }
+};
+
+#endif // __BASE_MATCH_HH__
+
diff --git a/src/base/misc.cc b/src/base/misc.cc
new file mode 100644
index 000000000..f3c86827b
--- /dev/null
+++ b/src/base/misc.cc
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <iostream>
+#include <string>
+
+#include "base/cprintf.hh"
+#include "base/hostinfo.hh"
+#include "base/misc.hh"
+#include "base/output.hh"
+#include "base/trace.hh"
+#include "sim/host.hh"
+#include "sim/root.hh"
+
+using namespace std;
+
+void
+__panic(const string &format, cp::ArgList &args, const char *func,
+ const char *file, int line)
+{
+ string fmt = "panic: " + format;
+ switch (fmt[fmt.size() - 1]) {
+ case '\n':
+ case '\r':
+ break;
+ default:
+ fmt += "\n";
+ }
+
+ fmt += " @ cycle %d\n[%s:%s, line %d]\n";
+
+ args.append(curTick);
+ args.append(func);
+ args.append(file);
+ args.append(line);
+ args.dump(cerr, fmt);
+
+ delete &args;
+
+ abort();
+}
+
+void
+__fatal(const string &format, cp::ArgList &args, const char *func,
+ const char *file, int line)
+{
+ string fmt = "fatal: " + format;
+
+ switch (fmt[fmt.size() - 1]) {
+ case '\n':
+ case '\r':
+ break;
+ default:
+ fmt += "\n";
+ }
+
+ fmt += " @ cycle %d\n[%s:%s, line %d]\n";
+ fmt += "Memory Usage: %ld KBytes\n";
+
+ args.append(curTick);
+ args.append(func);
+ args.append(file);
+ args.append(line);
+ args.append(memUsage());
+ args.dump(cerr, fmt);
+
+ delete &args;
+
+ exit(1);
+}
+
+void
+__warn(const string &format, cp::ArgList &args, const char *func,
+ const char *file, int line)
+{
+ string fmt = "warn: " + format;
+
+ switch (fmt[fmt.size() - 1]) {
+ case '\n':
+ case '\r':
+ break;
+ default:
+ fmt += "\n";
+ }
+
+#ifdef VERBOSE_WARN
+ fmt += " @ cycle %d\n[%s:%s, line %d]\n";
+ args.append(curTick);
+ args.append(func);
+ args.append(file);
+ args.append(line);
+#endif
+
+ args.dump(cerr, fmt);
+ if (simout.isFile(*outputStream))
+ args.dump(*outputStream, fmt);
+
+ delete &args;
+}
diff --git a/src/base/misc.hh b/src/base/misc.hh
new file mode 100644
index 000000000..9255c69c6
--- /dev/null
+++ b/src/base/misc.hh
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MISC_HH__
+#define __MISC_HH__
+
+#include <assert.h>
+#include "base/cprintf.hh"
+
+//
+// This implements a cprintf based panic() function. panic() should
+// be called when something happens that should never ever happen
+// regardless of what the user does (i.e., an acutal m5 bug). panic()
+// calls abort which can dump core or enter the debugger.
+//
+//
+void __panic(const std::string&, cp::ArgList &, const char*, const char*, int)
+ __attribute__((noreturn));
+#define __panic__(format, args...) \
+ __panic(format, (*(new cp::ArgList), args), \
+ __FUNCTION__, __FILE__, __LINE__)
+#define panic(args...) \
+ __panic__(args, cp::ArgListNull())
+
+//
+// This implements a cprintf based fatal() function. fatal() should
+// be called when the simulation cannot continue due to some condition
+// that is the user's fault (bad configuration, invalid arguments,
+// etc.) and not a simulator bug. fatal() calls exit(1), i.e., a
+// "normal" exit with an error code, as opposed to abort() like
+// panic() does.
+//
+void __fatal(const std::string&, cp::ArgList &, const char*, const char*, int)
+ __attribute__((noreturn));
+#define __fatal__(format, args...) \
+ __fatal(format, (*(new cp::ArgList), args), \
+ __FUNCTION__, __FILE__, __LINE__)
+#define fatal(args...) \
+ __fatal__(args, cp::ArgListNull())
+
+//
+// This implements a cprintf based warn
+//
+void __warn(const std::string&, cp::ArgList &, const char*, const char*, int);
+#define __warn__(format, args...) \
+ __warn(format, (*(new cp::ArgList), args), \
+ __FUNCTION__, __FILE__, __LINE__)
+#define warn(args...) \
+ __warn__(args, cp::ArgListNull())
+
+//
+// assert() that prints out the current cycle
+//
+#define m5_assert(TEST) \
+ if (!(TEST)) { \
+ std::cerr << "Assertion failure, curTick = " << curTick << std::endl; \
+ } \
+ assert(TEST);
+
+#endif // __MISC_HH__
diff --git a/src/base/mod_num.hh b/src/base/mod_num.hh
new file mode 100644
index 000000000..fabbb56a9
--- /dev/null
+++ b/src/base/mod_num.hh
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+template<class T, T MV>
+class ModNum {
+ private:
+ T value;
+
+ // Compiler should optimize this
+ void setValue(T n) { value = n % MV; }
+
+ public:
+ ModNum() {}
+ ModNum(T n) { setValue(n); }
+ ModNum(const ModNum<T, MV> &n) : value(n.value) {}
+
+ ModNum operator=(T n) {
+ setValue(n);
+ return *this;
+ }
+
+ const ModNum operator=(ModNum n) {
+ value = n.value;
+ return *this;
+ }
+
+ // Return the value if object used as RHS
+ operator T() const { return value; }
+
+ //
+ // Operator "+="
+ //
+ const ModNum<T, MV> operator+=(ModNum<T, MV> r) {
+ setValue(value + r.value);
+ return *this;
+ }
+
+ const ModNum<T, MV> operator+=(T r) {
+ setValue(value + r);
+ return *this;
+ }
+
+ //
+ // Operator "-="
+ //
+ const ModNum<T, MV> operator-=(ModNum<T, MV> r) {
+ setValue(value - r.value);
+ return *this;
+ }
+
+ const ModNum<T, MV> operator-=(T r) {
+ setValue(value - r);
+ return *this;
+ }
+
+ //
+ // Operator "++"
+ //
+ // PREFIX (like ++a)
+ const ModNum<T, MV> operator++() {
+ *this += 1;
+ return *this;
+ }
+
+ // POSTFIX (like a++)
+ const ModNum<T, MV> operator++(int) {
+ ModNum<T, MV> rv = *this;
+
+ *this += 1;
+
+ return rv;
+ }
+
+ //
+ // Operator "--"
+ //
+ // PREFIX (like --a)
+ const ModNum<T, MV> operator--() {
+ *this -= 1;
+ return *this;
+ }
+
+ // POSTFIX (like a--)
+ const ModNum<T, MV> operator--(int) {
+ ModNum<T, MV> rv = *this;
+ *this -= 1;
+ return rv;
+ }
+};
+
+
+//
+// Define operator "+" like this to avoid creating a temporary
+//
+template<class T, T MV>
+inline ModNum<T, MV>
+operator+(ModNum<T, MV> l, ModNum<T, MV> r) {
+ l += r;
+ return l;
+}
+
+template<class T, T MV>
+inline ModNum<T, MV>
+operator+(ModNum<T, MV> l, T r) {
+ l += r;
+ return l;
+}
+
+template<class T, T MV>
+inline ModNum<T, MV>
+operator+(T l, ModNum<T, MV> r) {
+ r += l;
+ return r;
+}
+
+
+//
+// Define operator "-" like this to avoid creating a temporary
+//
+template<class T, T MV>
+inline ModNum<T, MV>
+operator-(ModNum<T, MV> l, ModNum<T, MV> r) {
+ l -= r;
+ return l;
+}
+
+template<class T, T MV>
+inline ModNum<T, MV>
+operator-(ModNum<T, MV> l, T r) {
+ l -= r;
+ return l;
+}
+
+template<class T, T MV>
+inline ModNum<T, MV>
+operator-(T l, ModNum<T, MV> r) {
+ r -= l;
+ return r;
+}
+
+
+//
+// Comparison operators
+// (all other cases are handled with conversons)
+//
+template<class T, T MV>
+inline bool
+operator<(ModNum<T, MV> l, ModNum<T, MV> r) {
+ return l.value < r.value;
+}
+
+template<class T, T MV>
+inline bool
+operator>(ModNum<T, MV> l, ModNum<T, MV> r) {
+ return l.value > r.value;
+}
+
+template<class T, T MV>
+inline bool
+operator==(ModNum<T, MV> l, ModNum<T, MV> r) {
+ return l.value == r.value;
+}
+
+template<class T, T MV>
+inline bool
+operator<=(ModNum<T, MV> l, ModNum<T, MV> r) {
+ return l.value <= r.value;
+}
+
+template<class T, T MV>
+inline bool
+operator>=(ModNum<T, MV> l, ModNum<T, MV> r) {
+ return l.value >= r.value;
+}
+
+
diff --git a/src/base/mysql.cc b/src/base/mysql.cc
new file mode 100644
index 000000000..c8d6e933a
--- /dev/null
+++ b/src/base/mysql.cc
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <iostream>
+
+#include "base/mysql.hh"
+#include "base/trace.hh"
+
+using namespace std;
+
+namespace MySQL {
+
+inline const char *
+charstar(const string &string)
+{
+ return string.empty() ? NULL : string.c_str();
+}
+
+ostream &
+operator<<(ostream &stream, const Error &error)
+{
+ stream << error.string();
+ return stream;
+}
+
+/*
+ * The connection class
+ */
+Connection::Connection()
+ : valid(false)
+{
+}
+
+Connection::~Connection()
+{
+ if (valid)
+ close();
+}
+
+
+bool
+Connection::connect(const string &xhost, const string &xuser,
+ const string &xpasswd, const string &xdatabase)
+{
+ if (connected())
+ return error.set("Already Connected");
+
+ _host = xhost;
+ _user = xuser;
+ _passwd = xpasswd;
+ _database = xdatabase;
+
+ error.clear();
+
+ mysql_init(&mysql);
+ mysql_options(&mysql, MYSQL_OPT_COMPRESS, 0); // might want to be 1
+ mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "odbc");
+ if (!mysql_real_connect(&mysql, charstar(_host), charstar(_user),
+ charstar(_passwd), charstar(_database),
+ 0, NULL, 0))
+ return error.set(mysql_error(&mysql));
+
+ valid = true;
+ return false;
+}
+
+void
+Connection::close()
+{
+ mysql_close(&mysql);
+}
+
+bool
+Connection::query(const string &sql)
+{
+ DPRINTF(SQL, "Sending SQL query to server:\n%s", sql);
+ error.clear();
+ if (mysql_real_query(&mysql, sql.c_str(), sql.size()))
+ error.set(mysql_error(&mysql));
+
+ return error;
+}
+
+
+/* namespace MySQL */ }
diff --git a/src/base/mysql.hh b/src/base/mysql.hh
new file mode 100644
index 000000000..ae28a9dfb
--- /dev/null
+++ b/src/base/mysql.hh
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_MYSQL_HH__
+#define __BASE_MYSQL_HH__
+
+#define TO_BE_INCLUDED_LATER 0
+
+#include <cassert>
+#include <iosfwd>
+#include <mysql_version.h>
+#include <mysql.h>
+#include <string>
+#include <sstream>
+
+namespace MySQL {
+
+class Error
+{
+ protected:
+ const char *error;
+
+ public:
+ Error() : error(NULL) {}
+
+ Error &clear() { error = NULL; return *this; }
+ Error &set(const char *err) { error = err; return *this; }
+
+ const char *string() const { return error; }
+
+ operator bool() const { return error != NULL; }
+ bool operator!() const { return error == NULL; }
+};
+
+std::ostream &operator<<(std::ostream &stream, const Error &error);
+
+class Result
+{
+ private:
+ MYSQL_RES *result;
+ int *refcount;
+
+ void
+ decref()
+ {
+ if (!refcount)
+ return;
+
+ *refcount -= 1;
+ if (*refcount == 0) {
+ mysql_free_result(result);
+ delete refcount;
+ }
+
+ refcount = NULL;
+ }
+
+ public:
+ Result()
+ : result(0), refcount(NULL)
+ { }
+
+ Result(MYSQL_RES *res)
+ : result(res)
+ {
+ if (result)
+ refcount = new int(1);
+ else
+ refcount = NULL;
+ }
+
+ Result(const Result &result)
+ : result(result.result), refcount(result.refcount)
+ {
+ if (result)
+ *refcount += 1;
+ }
+
+ ~Result()
+ {
+ decref();
+ }
+
+ const Result &
+ operator=(MYSQL_RES *res)
+ {
+ decref();
+ result = res;
+ if (result)
+ refcount = new int(1);
+
+ return *this;
+ }
+
+ const Result &
+ operator=(const Result &res)
+ {
+ decref();
+ result = res.result;
+ refcount = res.refcount;
+ if (result)
+ *refcount += 1;
+
+ return *this;
+ }
+
+ operator bool() const { return result != NULL; }
+ bool operator!() const { return result == NULL; }
+
+ unsigned
+ num_fields()
+ {
+ assert(result);
+ return mysql_num_fields(result);
+ }
+
+ MYSQL_ROW
+ fetch_row()
+ {
+ return mysql_fetch_row(result);
+ }
+
+ unsigned long *
+ fetch_lengths()
+ {
+ return mysql_fetch_lengths(result);
+ }
+};
+
+typedef MYSQL_ROW Row;
+
+class Connection
+{
+ protected:
+ MYSQL mysql;
+ bool valid;
+
+ protected:
+ std::string _host;
+ std::string _user;
+ std::string _passwd;
+ std::string _database;
+
+ public:
+ Connection();
+ virtual ~Connection();
+
+ bool connected() const { return valid; }
+ bool connect(const std::string &host, const std::string &user,
+ const std::string &passwd, const std::string &database);
+ void close();
+
+ public:
+ Error error;
+ operator MYSQL *() { return &mysql; }
+
+ public:
+ bool query(const std::string &sql);
+
+ bool
+ query(const std::stringstream &sql)
+ {
+ return query(sql.str());
+ }
+
+ bool
+ autocommit(bool mode)
+ {
+ return mysql_autocommit(&mysql, mode);
+ }
+
+ bool
+ commit()
+ {
+ return mysql_commit(&mysql);
+ }
+
+ bool
+ rollback()
+ {
+ return mysql_rollback(&mysql);
+ }
+
+ unsigned
+ field_count()
+ {
+ return mysql_field_count(&mysql);
+ }
+
+ unsigned
+ affected_rows()
+ {
+ return mysql_affected_rows(&mysql);
+ }
+
+ unsigned
+ insert_id()
+ {
+ return mysql_insert_id(&mysql);
+ }
+
+
+ Result
+ store_result()
+ {
+ error.clear();
+ Result result = mysql_store_result(&mysql);
+ if (!result)
+ error.set(mysql_error(&mysql));
+
+ return result;
+ }
+};
+
+#if 0
+class BindProxy
+{
+ MYSQL_BIND *bind;
+ BindProxy(MYSQL_BIND *b) : bind(b) {}
+
+ void operator=(bool &buffer)
+ {
+ bind->buffer_type = MYSQL_TYPE_TINY;
+ bind->buffer = (char *)&buffer;
+ }
+
+ void operator=(int8_t &buffer)
+ {
+ bind->buffer_type = MYSQL_TYPE_TINY;
+ bind->buffer = (char *)&buffer;
+ }
+
+ void operator=(int16_t &buffer)
+ {
+ bind->buffer_type = MYSQL_TYPE_SHORT;
+ bind->buffer = (char *)&buffer;
+ }
+
+ void operator=(int32_t &buffer)
+ {
+ bind->buffer_type = MYSQL_TYPE_LONG;
+ bind->buffer = (char *)&buffer;
+ }
+
+ void operator=(int64_t &buffer)
+ {
+ bind->buffer_type = MYSQL_TYPE_LONGLONG;
+ bind->buffer = (char *)&buffer;
+ }
+
+ void operator=(uint8_t &buffer)
+ {
+ bind->buffer_type = MYSQL_TYPE_TINY;
+ bind->buffer = (char *)&buffer;
+ }
+
+ void operator=(uint16_t &buffer)
+ {
+ bind->buffer_type = MYSQL_TYPE_SHORT;
+ bind->buffer = (char *)&buffer;
+ }
+
+ void operator=(uint32_t &buffer)
+ {
+ bind->buffer_type = MYSQL_TYPE_LONG;
+ bind->buffer = (char *)&buffer;
+ }
+
+ void operator=(uint64_t &buffer)
+ {
+ bind->buffer_type = MYSQL_TYPE_LONGLONG;
+ bind->buffer = (char *)&buffer;
+ }
+
+ void operator=(float &buffer)
+ {
+ bind->buffer_type = MYSQL_TYPE_FLOAT;
+ bind->buffer = (char *)&buffer;
+ }
+
+ void operator=(double &buffer)
+ {
+ bind->buffer_type = MYSQL_TYPE_DOUBLE;
+ bind->buffer = (char *)&buffer;
+ }
+
+ void operator=(Time &buffer)
+ {
+ bind->buffer_type = MYSQL_TYPE_DATE;
+ bind->buffer = (char *)&buffer;
+ }
+
+ void operator=(const char *buffer)
+ {
+ bind->buffer_type = MYSQL_TYPE_VAR_STRING;
+ bind->buffer = buffer;
+ }
+
+ void operator=(const std::string &buffer)
+ {
+ bind->buffer_type = MYSQL_TYPE_VAR_STRING;
+ bind->buffer = (char *)&buffer;
+ bind->length = buffer.length;
+ }
+
+ bool
+ set_null(bool null)
+ {
+ bind->is_null = null;
+ }
+};
+
+class Statement
+{
+ protected:
+ Error &error;
+ MYSQL_STMT *stmt;
+ MYSQL_BIND *bind;
+ int size;
+
+ public:
+ Statement(Connection &mysql)
+ : error(mysql.error), bind(NULL), size(0)
+ {
+ stmt = mysql_stmt_init(mysql);
+ assert(valid() && "mysql_stmt_init(), out of memory\n");
+ }
+
+ ~Statement()
+ {
+ assert(valid());
+ error.clear();
+ if (mysql_stmt_close(stmt))
+ error.set(mysql_stmt_error(stmt));
+
+ if (bind)
+ delete [] bind;
+ }
+
+ bool valid()
+ {
+ return stmt != NULL;
+ }
+
+ void prepare(const std::string &query)
+ {
+ assert(valid());
+ mysql.error.clear();
+ if (mysql_stmt_prepare(mysql, query, strlen(query)))
+ mysql.error.set(mysql_stmt_error(stmt));
+
+ int size = count();
+ bind = new MYSQL_BIND[size];
+ }
+
+ unsigned count()
+ {
+ assert(valid());
+ return mysql_stmt_param_count(stmt);
+ }
+
+ unsigned affected()
+ {
+ assert(valid());
+ return mysql_stmt_affected_rows(stmt);
+ }
+
+ void bind(MYSQL_BIND *bind)
+ {
+ mysql.error.clear();
+ if (mysql_stmt_bind_param(stmt, bind))
+ mysql.error.set(mysql_stmt_error(stmt));
+ }
+
+ BindProxy operator[](int index)
+ {
+ assert(index > 0 && index < N);
+ return &bind[N];
+ }
+
+ operator MYSQL_BIND *()
+ {
+ return bind;
+ }
+
+ void operator()()
+ {
+ assert(valid());
+ error.clear();
+ if (mysql_stmt_execute(stmt))
+ error.set(mysql_stmt_error(stmt));
+ }
+}
+#endif
+
+/* namespace MySQL */ }
+
+#endif // __BASE_MYSQL_HH__
diff --git a/src/base/output.cc b/src/base/output.cc
new file mode 100644
index 000000000..2b1733f21
--- /dev/null
+++ b/src/base/output.cc
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <fstream>
+
+#include "base/misc.hh"
+#include "base/output.hh"
+
+using namespace std;
+
+OutputDirectory simout;
+
+/**
+ *
+ */
+OutputDirectory::OutputDirectory()
+{}
+
+OutputDirectory::~OutputDirectory()
+{}
+
+void
+OutputDirectory::setDirectory(const string &d)
+{
+ if (!dir.empty())
+ panic("Output directory already set!\n");
+
+ dir = d;
+
+ if (dir != ".") {
+ if (mkdir(dir.c_str(), 0777) < 0 && errno != EEXIST)
+ panic("couldn't make output dir %s: %s\n",
+ dir, strerror(errno));
+ }
+
+ // guarantee that directory ends with a '/'
+ if (dir[dir.size() - 1] != '/')
+ dir += "/";
+}
+
+const string &
+OutputDirectory::directory()
+{
+ if (dir.empty())
+ panic("Output directory not set!");
+
+ return dir;
+}
+
+string
+OutputDirectory::resolve(const string &name)
+{
+ return (name[0] != '/') ? dir + name : name;
+}
+
+ostream *
+OutputDirectory::create(const string &name)
+{
+ if (name == "cerr" || name == "stderr")
+ return &cerr;
+
+ if (name == "cout" || name == "stdout")
+ return &cout;
+
+ ofstream *file = new ofstream(resolve(name).c_str(), ios::trunc);
+ if (!file->is_open())
+ panic("Cannot open file %s", name);
+
+ return file;
+}
+
+ostream *
+OutputDirectory::find(const string &name)
+{
+ if (name == "cerr" || name == "stderr")
+ return &cerr;
+
+ if (name == "cout" || name == "stdout")
+ return &cout;
+
+ string filename = resolve(name);
+ map_t::iterator i = files.find(filename);
+ if (i != files.end())
+ return (*i).second;
+
+ ofstream *file = new ofstream(filename.c_str(), ios::trunc);
+ if (!file->is_open())
+ panic("Cannot open file %s", filename);
+
+ files[filename] = file;
+ return file;
+}
+
+bool
+OutputDirectory::isFile(const std::ostream *os)
+{
+ return os && os != &cerr && os != &cout;
+}
diff --git a/src/base/output.hh b/src/base/output.hh
new file mode 100644
index 000000000..3bbe73e3b
--- /dev/null
+++ b/src/base/output.hh
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_OUTPUT_HH__
+#define __BASE_OUTPUT_HH__
+
+#include <iosfwd>
+#include <map>
+#include <string>
+
+class OutputDirectory
+{
+ private:
+ typedef std::map<std::string, std::ostream *> map_t;
+
+ map_t files;
+ std::string dir;
+
+ public:
+ OutputDirectory();
+ ~OutputDirectory();
+
+ void setDirectory(const std::string &dir);
+ const std::string &directory();
+
+ std::string resolve(const std::string &name);
+ std::ostream *create(const std::string &name);
+ std::ostream *find(const std::string &name);
+
+ static bool isFile(const std::ostream *os);
+ static inline bool isFile(const std::ostream &os) { return isFile(&os); }
+};
+
+extern OutputDirectory simout;
+
+#endif // __BASE_OUTPUT_HH__
diff --git a/src/base/pollevent.cc b/src/base/pollevent.cc
new file mode 100644
index 000000000..99044fc09
--- /dev/null
+++ b/src/base/pollevent.cc
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+
+#include <fcntl.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include "sim/async.hh"
+#include "sim/host.hh"
+#include "base/misc.hh"
+#include "base/pollevent.hh"
+#include "sim/root.hh"
+#include "sim/serialize.hh"
+
+using namespace std;
+
+PollQueue pollQueue;
+
+/////////////////////////////////////////////////////
+//
+PollEvent::PollEvent(int _fd, int _events)
+ : queue(NULL), enabled(true)
+{
+ pfd.fd = _fd;
+ pfd.events = _events;
+}
+
+PollEvent::~PollEvent()
+{
+ if (queue)
+ queue->remove(this);
+}
+
+void
+PollEvent::disable()
+{
+ if (!enabled) return;
+ enabled = false;
+
+ if (queue)
+ queue->copy();
+}
+
+void
+PollEvent::enable()
+{
+ if (enabled) return;
+ enabled = true;
+
+ if (queue)
+ queue->copy();
+}
+
+void
+PollEvent::serialize(ostream &os)
+{
+ SERIALIZE_SCALAR(pfd.fd);
+ SERIALIZE_SCALAR(pfd.events);
+ SERIALIZE_SCALAR(enabled);
+}
+
+void
+PollEvent::unserialize(Checkpoint *cp, const std::string &section)
+{
+ UNSERIALIZE_SCALAR(pfd.fd);
+ UNSERIALIZE_SCALAR(pfd.events);
+ UNSERIALIZE_SCALAR(enabled);
+}
+
+/////////////////////////////////////////////////////
+//
+PollQueue::PollQueue()
+ : poll_fds(NULL), max_size(0), num_fds(0)
+{ }
+
+PollQueue::~PollQueue()
+{
+ removeHandler();
+ for (int i = 0; i < num_fds; i++)
+ setupAsyncIO(poll_fds[0].fd, false);
+
+ delete [] poll_fds;
+}
+
+void
+PollQueue::copy()
+{
+ eventvec_t::iterator i = events.begin();
+ eventvec_t::iterator end = events.end();
+
+ num_fds = 0;
+
+ while (i < end) {
+ if ((*i)->enabled)
+ poll_fds[num_fds++] = (*i)->pfd;
+ ++i;
+ }
+}
+
+void
+PollQueue::remove(PollEvent *event)
+{
+ eventvec_t::iterator i = events.begin();
+ eventvec_t::iterator end = events.end();
+
+ while (i < end) {
+ if (*i == event) {
+ events.erase(i);
+ copy();
+ event->queue = NULL;
+ return;
+ }
+
+ ++i;
+ }
+
+ panic("Event does not exist. Cannot remove.");
+}
+
+void
+PollQueue::schedule(PollEvent *event)
+{
+ if (event->queue)
+ panic("Event already scheduled!");
+
+ event->queue = this;
+ events.push_back(event);
+ setupAsyncIO(event->pfd.fd, true);
+
+ // if we ran out of space in the fd array, double the capacity
+ // if this is the first time that we've scheduled an event, create
+ // the array with an initial size of 16
+ if (++num_fds > max_size) {
+ if (max_size > 0) {
+ delete [] poll_fds;
+ max_size *= 2;
+ } else {
+ max_size = 16;
+ setupHandler();
+ }
+
+ poll_fds = new pollfd[max_size];
+ }
+
+ copy();
+}
+
+void
+PollQueue::service()
+{
+ int ret = poll(poll_fds, num_fds, 0);
+
+ if (ret <= 0)
+ return;
+
+ for (int i = 0; i < num_fds; i++) {
+ int revents = poll_fds[i].revents;
+ if (revents) {
+ events[i]->process(revents);
+ if (--ret <= 0)
+ break;
+ }
+ }
+}
+
+struct sigaction PollQueue::oldio;
+struct sigaction PollQueue::oldalrm;
+bool PollQueue::handler = false;
+
+void
+PollQueue::setupAsyncIO(int fd, bool set)
+{
+ int flags = fcntl(fd, F_GETFL);
+ if (flags == -1)
+ panic("Could not set up async IO");
+
+ if (set)
+ flags |= FASYNC;
+ else
+ flags &= ~(FASYNC);
+
+ if (fcntl(fd, F_SETFL, flags) == -1)
+ panic("Could not set up async IO");
+
+ if (set) {
+ if (fcntl(fd, F_SETOWN, getpid()) == -1)
+ panic("Could not set up async IO");
+ }
+}
+
+void
+PollQueue::setupHandler()
+{
+ struct sigaction act;
+
+ act.sa_handler = handleIO;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_RESTART;
+
+ if (sigaction(SIGIO, &act, &oldio) == -1)
+ panic("could not do sigaction");
+
+ act.sa_handler = handleALRM;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_RESTART;
+
+ if (sigaction(SIGALRM, &act, &oldalrm) == -1)
+ panic("could not do sigaction");
+
+ alarm(1);
+
+ handler = true;
+}
+
+void
+PollQueue::removeHandler()
+{
+ if (sigaction(SIGIO, &oldio, NULL) == -1)
+ panic("could not remove handler");
+
+ if (sigaction(SIGIO, &oldalrm, NULL) == -1)
+ panic("could not remove handler");
+}
+
+void
+PollQueue::handleIO(int sig)
+{
+ if (sig != SIGIO)
+ panic("Wrong Handler");
+
+ async_event = true;
+ async_io = true;
+}
+
+void
+PollQueue::handleALRM(int sig)
+{
+ if (sig != SIGALRM)
+ panic("Wrong Handler");
+
+ async_event = true;
+ async_alarm = true;
+ alarm(1);
+}
+
diff --git a/src/base/pollevent.hh b/src/base/pollevent.hh
new file mode 100644
index 000000000..d39931797
--- /dev/null
+++ b/src/base/pollevent.hh
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __POLLEVENT_H__
+#define __POLLEVENT_H__
+
+#include <vector>
+#include <poll.h>
+#include "sim/root.hh"
+
+class Checkpoint;
+class PollQueue;
+
+class PollEvent
+{
+ private:
+ friend class PollQueue;
+
+ protected:
+ pollfd pfd;
+ PollQueue *queue;
+ bool enabled;
+
+ public:
+ PollEvent(int fd, int event);
+ virtual ~PollEvent();
+
+ void disable();
+ void enable();
+ virtual void process(int revent) = 0;
+
+ bool queued() { return queue != 0; }
+
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+};
+
+class PollQueue
+{
+ private:
+ typedef std::vector<PollEvent *> eventvec_t;
+ eventvec_t events;
+
+ pollfd *poll_fds;
+ int max_size;
+ int num_fds;
+
+ public:
+ PollQueue();
+ ~PollQueue();
+
+ void copy();
+ void remove(PollEvent *event);
+ void schedule(PollEvent *event);
+ void service();
+
+ protected:
+ static bool handler;
+ static struct sigaction oldio;
+ static struct sigaction oldalrm;
+
+ public:
+ static void setupAsyncIO(int fd, bool set);
+ static void handleIO(int);
+ static void handleALRM(int);
+ static void removeHandler();
+ static void setupHandler();
+};
+
+extern PollQueue pollQueue;
+
+#endif // __POLLEVENT_H__
diff --git a/src/base/predictor.hh b/src/base/predictor.hh
new file mode 100644
index 000000000..37aa29989
--- /dev/null
+++ b/src/base/predictor.hh
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//
+// Abstract base class for a generic predictor
+//
+//
+
+#ifndef __PREDICTOR_HH__
+#define __PREDICTOR_HH__
+
+class GenericPredictor {
+
+ public:
+ virtual void clear() = 0;
+
+ virtual unsigned predict(unsigned long _index) = 0;
+ virtual unsigned predict(unsigned long _index, unsigned &pdata) = 0;
+
+ virtual unsigned peek(unsigned long _index) = 0;
+
+ virtual void record(unsigned long _index, unsigned _actual_value,
+ unsigned _pred_value) = 0;
+ virtual void record(unsigned long _index, unsigned _actual_value,
+ unsigned _pred_value, unsigned _pdata) = 0;
+
+ virtual unsigned value(unsigned long _index) = 0;
+
+ virtual void regStats() = 0;
+ virtual void regFormulas() = 0;
+
+ virtual ~GenericPredictor() {};
+};
+
+#endif // __PREDICTOR_HH__
diff --git a/src/base/random.cc b/src/base/random.cc
new file mode 100644
index 000000000..4aac14101
--- /dev/null
+++ b/src/base/random.cc
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <cstdlib>
+#include <cmath>
+
+#include "sim/param.hh"
+#include "base/random.hh"
+#include "base/trace.hh"
+
+using namespace std;
+
+class RandomContext : public ParamContext
+{
+ public:
+ RandomContext(const string &_iniSection)
+ : ::ParamContext(_iniSection) {}
+ ~RandomContext() {}
+
+ void checkParams();
+};
+
+RandomContext paramContext("random");
+
+Param<unsigned>
+seed(&paramContext, "seed", "seed to random number generator", 1);
+
+void
+RandomContext::checkParams()
+{
+ ::srand48(seed);
+}
+
+long
+getLong()
+{
+ return mrand48();
+}
+
+int64_t
+getUniform(int64_t min, int64_t max)
+{
+ double r;
+ r = drand48() * (max-min) + min;
+ return (int64_t)round(r);
+}
+
+uint64_t
+getUniformPos(uint64_t min, uint64_t max)
+{
+ double r;
+ r = drand48() * (max-min) + min;
+ return (uint64_t)round(r);
+}
+
+
+// idea for generating a double from erand48
+double
+getDouble()
+{
+ union {
+ uint32_t _long[2];
+ uint16_t _short[4];
+ };
+
+ _long[0] = mrand48();
+ _long[1] = mrand48();
+
+ return ldexp((double) _short[0], -48) +
+ ldexp((double) _short[1], -32) +
+ ldexp((double) _short[2], -16);
+}
diff --git a/src/base/random.hh b/src/base/random.hh
new file mode 100644
index 000000000..def7a4bce
--- /dev/null
+++ b/src/base/random.hh
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_RANDOM_HH__
+#define __BASE_RANDOM_HH__
+
+#include "sim/host.hh"
+
+long getLong();
+double getDouble();
+uint64_t getUniformPos(uint64_t min, uint64_t max);
+int64_t getUniform(int64_t min, int64_t max);
+
+template <typename T>
+struct Random;
+
+template<> struct Random<int8_t>
+{
+ static int8_t get()
+ { return getLong() & (int8_t)-1; }
+
+ static int8_t uniform(int8_t min, int8_t max)
+ { return getUniform(min, max); }
+};
+
+template<> struct Random<uint8_t>
+{
+ static uint8_t get()
+ { return getLong() & (uint8_t)-1; }
+
+ static uint8_t uniform(uint8_t min, uint8_t max)
+ { return getUniformPos(min, max); }
+};
+
+template<> struct Random<int16_t>
+{
+ static int16_t get()
+ { return getLong() & (int16_t)-1; }
+
+ static int16_t uniform(int16_t min, int16_t max)
+ { return getUniform(min, max); }
+};
+
+template<> struct Random<uint16_t>
+{
+ static uint16_t get()
+ { return getLong() & (uint16_t)-1; }
+
+ static uint16_t uniform(uint16_t min, uint16_t max)
+ { return getUniformPos(min, max); }
+};
+
+template<> struct Random<int32_t>
+{
+ static int32_t get()
+ { return (int32_t)getLong(); }
+
+ static int32_t uniform(int32_t min, int32_t max)
+ { return getUniform(min, max); }
+};
+
+template<> struct Random<uint32_t>
+{
+ static uint32_t get()
+ { return (uint32_t)getLong(); }
+
+ static uint32_t uniform(uint32_t min, uint32_t max)
+ { return getUniformPos(min, max); }
+};
+
+template<> struct Random<int64_t>
+{
+ static int64_t get()
+ { return (int64_t)getLong() << 32 || (uint64_t)getLong(); }
+
+ static int64_t uniform(int64_t min, int64_t max)
+ { return getUniform(min, max); }
+};
+
+template<> struct Random<uint64_t>
+{
+ static uint64_t get()
+ { return (uint64_t)getLong() << 32 || (uint64_t)getLong(); }
+
+ static uint64_t uniform(uint64_t min, uint64_t max)
+ { return getUniformPos(min, max); }
+};
+
+template<> struct Random<float>
+{
+ static float get()
+ { return getDouble(); }
+};
+
+template<> struct Random<double>
+{
+ static double get()
+ { return getDouble(); }
+};
+
+#endif // __BASE_RANDOM_HH__
diff --git a/src/base/range.cc b/src/base/range.cc
new file mode 100644
index 000000000..a4e50fc4f
--- /dev/null
+++ b/src/base/range.cc
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "base/intmath.hh"
+#include "base/range.hh"
+#include "base/str.hh"
+
+using namespace std;
+
+template <class T>
+bool
+__x_parse_range(const std::string &str, T &first, T &last)
+{
+ std::vector<std::string> values;
+ tokenize(values, str, ':');
+
+ T thefirst, thelast;
+
+ if (values.size() != 2)
+ return false;
+
+ std::string s = values[0];
+ std::string e = values[1];
+
+ if (!to_number(s, thefirst))
+ return false;
+
+ bool increment = (e[0] == '+');
+ if (increment)
+ e = e.substr(1);
+
+ if (!to_number(e, thelast))
+ return false;
+
+ if (increment)
+ thelast += thefirst - 1;
+
+ first = thefirst;
+ last = thelast;
+
+ return true;
+}
+
+#define RANGE_PARSE(type) \
+template<> bool \
+__parse_range(const std::string &s, type &first, type &last) \
+{ return __x_parse_range(s, first, last); }
+
+RANGE_PARSE(unsigned long long);
+RANGE_PARSE(signed long long);
+RANGE_PARSE(unsigned long);
+RANGE_PARSE(signed long);
+RANGE_PARSE(unsigned int);
+RANGE_PARSE(signed int);
+RANGE_PARSE(unsigned short);
+RANGE_PARSE(signed short);
+RANGE_PARSE(unsigned char);
+RANGE_PARSE(signed char);
diff --git a/src/base/range.hh b/src/base/range.hh
new file mode 100644
index 000000000..4e3e0fd6e
--- /dev/null
+++ b/src/base/range.hh
@@ -0,0 +1,355 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_RANGE_HH__
+#define __BASE_RANGE_HH__
+
+#include <cassert>
+#include <iostream>
+#include <string>
+
+/**
+ * @param s range string
+ * EndExclusive Ranges are in the following format:
+ * @verbatim
+ * <range> := {<start_val>}:{<end>}
+ * <start> := <end_val> | +<delta>
+ * @endverbatim
+ */
+template <class T>
+bool __parse_range(const std::string &s, T &start, T &end);
+
+template <class T>
+struct Range
+{
+ T start;
+ T end;
+
+ Range() { invalidate(); }
+
+ template <class U>
+ Range(const std::pair<U, U> &r)
+ : start(r.first), end(r.second)
+ {}
+
+ template <class U>
+ Range(const Range<U> &r)
+ : start(r.start), end(r.end)
+ {}
+
+ Range(const std::string &s)
+ {
+ if (!__parse_range(s, start, end))
+ invalidate();
+ }
+
+ template <class U>
+ const Range<T> &operator=(const Range<U> &r)
+ {
+ start = r.start;
+ end = r.end;
+ return *this;
+ }
+
+ template <class U>
+ const Range<T> &operator=(const std::pair<U, U> &r)
+ {
+ start = r.first;
+ end = r.second;
+ return *this;
+ }
+
+ const Range &operator=(const std::string &s)
+ {
+ if (!__parse_range(s, start, end))
+ invalidate();
+ return *this;
+ }
+
+ void invalidate() { start = 1; end = 0; }
+ T size() const { return end - start + 1; }
+ bool valid() const { return start < end; }
+};
+
+template <class T>
+inline std::ostream &
+operator<<(std::ostream &o, const Range<T> &r)
+{
+ o << '[' << r.start << "," << r.end << ']';
+ return o;
+}
+
+template <class T>
+inline Range<T>
+RangeEx(T start, T end)
+{ return std::make_pair(start, end - 1); }
+
+template <class T>
+inline Range<T>
+RangeIn(T start, T end)
+{ return std::make_pair(start, end); }
+
+template <class T, class U>
+inline Range<T>
+RangeSize(T start, U size)
+{ return std::make_pair(start, start + size - 1); }
+
+////////////////////////////////////////////////////////////////////////
+//
+// Range to Range Comparisons
+//
+
+/**
+ * @param range1 is a range.
+ * @param range2 is a range.
+ * @return if range1 and range2 are identical.
+ */
+template <class T, class U>
+inline bool
+operator==(const Range<T> &range1, const Range<U> &range2)
+{
+ return range1.start == range2.start && range1.end == range2.end;
+}
+
+/**
+ * @param range1 is a range.
+ * @param range2 is a range.
+ * @return if range1 and range2 are not identical.
+ */
+template <class T, class U>
+inline bool
+operator!=(const Range<T> &range1, const Range<U> &range2)
+{
+ return range1.start != range2.start || range1.end != range2.end;
+}
+
+/**
+ * @param range1 is a range.
+ * @param range2 is a range.
+ * @return if range1 is less than range2 and does not overlap range1.
+ */
+template <class T, class U>
+inline bool
+operator<(const Range<T> &range1, const Range<U> &range2)
+{
+ return range1.start < range2.start;
+}
+
+/**
+ * @param range1 is a range.
+ * @param range2 is a range.
+ * @return if range1 is less than range2. range1 may overlap range2,
+ * but not extend beyond the end of range2.
+ */
+template <class T, class U>
+inline bool
+operator<=(const Range<T> &range1, const Range<U> &range2)
+{
+ return range1.start <= range2.start;
+}
+
+/**
+ * @param range1 is a range.
+ * @param range2 is a range.
+ * @return if range1 is greater than range2 and does not overlap range2.
+ */
+template <class T, class U>
+inline bool
+operator>(const Range<T> &range1, const Range<U> &range2)
+{
+ return range1.start > range2.start;
+}
+
+/**
+ * @param range1 is a range.
+ * @param range2 is a range.
+ * @return if range1 is greater than range2. range1 may overlap range2,
+ * but not extend beyond the beginning of range2.
+ */
+template <class T, class U>
+inline bool
+operator>=(const Range<T> &range1, const Range<U> &range2)
+{
+ return range1.start >= range2.start;
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// Position to Range Comparisons
+//
+
+/**
+ * @param pos position compared to the range.
+ * @param range range compared against.
+ * @return indicates that position pos is within the range.
+ */
+template <class T, class U>
+inline bool
+operator==(const T &pos, const Range<U> &range)
+{
+ return pos >= range.start && pos <= range.end;
+}
+
+/**
+ * @param pos position compared to the range.
+ * @param range range compared against.
+ * @return indicates that position pos is not within the range.
+ */
+template <class T, class U>
+inline bool
+operator!=(const T &pos, const Range<U> &range)
+{
+ return pos < range.start || pos > range.end;
+}
+
+/**
+ * @param pos position compared to the range.
+ * @param range range compared against.
+ * @return indicates that position pos is below the range.
+ */
+template <class T, class U>
+inline bool
+operator<(const T &pos, const Range<U> &range)
+{
+ return pos < range.start;
+}
+
+/**
+ * @param pos position compared to the range.
+ * @param range range compared against.
+ * @return indicates that position pos is below or in the range.
+ */
+template <class T, class U>
+inline bool
+operator<=(const T &pos, const Range<U> &range)
+{
+ return pos <= range.end;
+}
+
+/**
+ * @param pos position compared to the range.
+ * @param range range compared against.
+ * @return indicates that position pos is above the range.
+ */
+template <class T, class U>
+inline bool
+operator>(const T &pos, const Range<U> &range)
+{
+ return pos > range.end;
+}
+
+/**
+ * @param pos position compared to the range.
+ * @param range range compared against.
+ * @return indicates that position pos is above or in the range.
+ */
+template <class T, class U>
+inline bool
+operator>=(const T &pos, const Range<U> &range)
+{
+ return pos >= range.start;
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// Range to Position Comparisons (for symmetry)
+//
+
+/**
+ * @param range range compared against.
+ * @param pos position compared to the range.
+ * @return indicates that position pos is within the range.
+ */
+template <class T, class U>
+inline bool
+operator==(const Range<T> &range, const U &pos)
+{
+ return pos >= range.start && pos <= range.end;
+}
+
+/**
+ * @param range range compared against.
+ * @param pos position compared to the range.
+ * @return indicates that position pos is not within the range.
+ */
+template <class T, class U>
+inline bool
+operator!=(const Range<T> &range, const U &pos)
+{
+ return pos < range.start || pos > range.end;
+}
+
+/**
+ * @param range range compared against.
+ * @param pos position compared to the range.
+ * @return indicates that position pos is above the range.
+ */
+template <class T, class U>
+inline bool
+operator<(const Range<T> &range, const U &pos)
+{
+ return range.end < pos;
+}
+
+/**
+ * @param range range compared against.
+ * @param pos position compared to the range.
+ * @return indicates that position pos is above or in the range.
+ */
+template <class T, class U>
+inline bool
+operator<=(const Range<T> &range, const U &pos)
+{
+ return range.start <= pos;
+}
+
+/**
+ * @param range range compared against.
+ * @param pos position compared to the range.
+ * 'range > pos' indicates that position pos is below the range.
+ */
+template <class T, class U>
+inline bool
+operator>(const Range<T> &range, const U &pos)
+{
+ return range.start > pos;
+}
+
+/**
+ * @param range range compared against.
+ * @param pos position compared to the range.
+ * 'range >= pos' indicates that position pos is below or in the range.
+ */
+template <class T, class U>
+inline bool
+operator>=(const Range<T> &range, const U &pos)
+{
+ return range.end >= pos;
+}
+
+#endif // __BASE_RANGE_HH__
diff --git a/src/base/refcnt.hh b/src/base/refcnt.hh
new file mode 100644
index 000000000..de589f7c5
--- /dev/null
+++ b/src/base/refcnt.hh
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __REFCNT_HH__
+#define __REFCNT_HH__
+
+#include <stddef.h> //For the NULL macro definition
+
+class RefCounted
+{
+ private:
+ int count;
+
+ private:
+ RefCounted(const RefCounted &);
+
+ public:
+ RefCounted() : count(0) {}
+ virtual ~RefCounted() {}
+
+ void incref() { ++count; }
+ void decref() { if (--count <= 0) delete this; }
+};
+
+template <class T>
+class RefCountingPtr
+{
+ protected:
+ T *data;
+
+ void copy(T *d)
+ {
+ data = d;
+ if (data)
+ data->incref();
+ }
+ void del()
+ {
+ if (data)
+ data->decref();
+ }
+ void set(T *d)
+ {
+ if (data == d)
+ return;
+
+ del();
+ copy(d);
+ }
+
+
+ public:
+ RefCountingPtr() : data(NULL) {}
+ RefCountingPtr(T *data) { copy(data); }
+ RefCountingPtr(const RefCountingPtr &r) { copy(r.data); }
+ ~RefCountingPtr() { del(); }
+
+ T *operator->() { return data; }
+ T &operator*() { return *data; }
+ T *get() { return data; }
+
+ const T *operator->() const { return data; }
+ const T &operator*() const { return *data; }
+ const T *get() const { return data; }
+
+ RefCountingPtr &operator=(T *p) { set(p); return *this; }
+ RefCountingPtr &operator=(const RefCountingPtr &r)
+ { return operator=(r.data); }
+
+ bool operator!() const { return data == 0; }
+ operator bool() const { return data != 0; }
+};
+
+template<class T>
+bool operator==(const RefCountingPtr<T> &l, const RefCountingPtr<T> &r)
+{ return l.get() == r.get(); }
+
+template<class T>
+bool operator==(const RefCountingPtr<T> &l, const T *r)
+{ return l.get() == r; }
+
+template<class T>
+bool operator==(const T &l, const RefCountingPtr<T> &r)
+{ return l == r.get(); }
+
+template<class T>
+bool operator!=(const RefCountingPtr<T> &l, const RefCountingPtr<T> &r)
+{ return l.get() != r.get(); }
+
+template<class T>
+bool operator!=(const RefCountingPtr<T> &l, const T *r)
+{ return l.get() != r; }
+
+template<class T>
+bool operator!=(const T &l, const RefCountingPtr<T> &r)
+{ return l != r.get(); }
+
+#endif // __REFCNT_HH__
diff --git a/src/base/remote_gdb.cc b/src/base/remote_gdb.cc
new file mode 100644
index 000000000..41d0c1471
--- /dev/null
+++ b/src/base/remote_gdb.cc
@@ -0,0 +1,1175 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratories.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)kgdb_stub.c 8.4 (Berkeley) 1/12/94
+ */
+
+/*-
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * $NetBSD: kgdb_stub.c,v 1.8 2001/07/07 22:58:00 wdk Exp $
+ *
+ * Taken from NetBSD
+ *
+ * "Stub" to allow remote cpu to debug over a serial line using gdb.
+ */
+
+#include <sys/signal.h>
+
+#include <string>
+#include <unistd.h>
+
+#include "arch/vtophys.hh"
+#include "base/intmath.hh"
+#include "base/kgdb.h"
+#include "base/remote_gdb.hh"
+#include "base/socket.hh"
+#include "base/trace.hh"
+#include "config/full_system.hh"
+#include "cpu/exec_context.hh"
+#include "cpu/static_inst.hh"
+#include "mem/physical.hh"
+#include "mem/port.hh"
+#include "sim/system.hh"
+
+using namespace std;
+using namespace TheISA;
+
+#ifndef NDEBUG
+vector<RemoteGDB *> debuggers;
+int current_debugger = -1;
+
+void
+debugger()
+{
+ if (current_debugger >= 0 && current_debugger < debuggers.size()) {
+ RemoteGDB *gdb = debuggers[current_debugger];
+ if (!gdb->isattached())
+ gdb->listener->accept();
+ if (gdb->isattached())
+ gdb->trap(ALPHA_KENTRY_IF);
+ }
+}
+#endif
+
+///////////////////////////////////////////////////////////
+//
+//
+//
+
+GDBListener::Event::Event(GDBListener *l, int fd, int e)
+ : PollEvent(fd, e), listener(l)
+{}
+
+void
+GDBListener::Event::process(int revent)
+{
+ listener->accept();
+}
+
+GDBListener::GDBListener(RemoteGDB *g, int p)
+ : event(NULL), gdb(g), port(p)
+{
+ assert(!gdb->listener);
+ gdb->listener = this;
+}
+
+GDBListener::~GDBListener()
+{
+ if (event)
+ delete event;
+}
+
+string
+GDBListener::name()
+{
+ return gdb->name() + ".listener";
+}
+
+void
+GDBListener::listen()
+{
+ while (!listener.listen(port, true)) {
+ DPRINTF(GDBMisc, "Can't bind port %d\n", port);
+ port++;
+ }
+
+ event = new Event(this, listener.getfd(), POLLIN);
+ pollQueue.schedule(event);
+
+#ifndef NDEBUG
+ gdb->number = debuggers.size();
+ debuggers.push_back(gdb);
+#endif
+
+#ifndef NDEBUG
+ ccprintf(cerr, "%d: %s: listening for remote gdb #%d on port %d\n",
+ curTick, name(), gdb->number, port);
+#else
+ ccprintf(cerr, "%d: %s: listening for remote gdb on port %d\n",
+ curTick, name(), port);
+#endif
+}
+
+void
+GDBListener::accept()
+{
+ if (!listener.islistening())
+ panic("GDBListener::accept(): cannot accept if we're not listening!");
+
+ int sfd = listener.accept(true);
+
+ if (sfd != -1) {
+ if (gdb->isattached())
+ close(sfd);
+ else
+ gdb->attach(sfd);
+ }
+}
+
+///////////////////////////////////////////////////////////
+//
+//
+//
+int digit2i(char);
+char i2digit(int);
+void mem2hex(void *, const void *, int);
+const char *hex2mem(void *, const char *, int);
+Addr hex2i(const char **);
+
+RemoteGDB::Event::Event(RemoteGDB *g, int fd, int e)
+ : PollEvent(fd, e), gdb(g)
+{}
+
+void
+RemoteGDB::Event::process(int revent)
+{
+ if (revent & POLLIN)
+ gdb->trap(ALPHA_KENTRY_IF);
+ else if (revent & POLLNVAL)
+ gdb->detach();
+}
+
+RemoteGDB::RemoteGDB(System *_system, ExecContext *c)
+ : event(NULL), listener(NULL), number(-1), fd(-1),
+ active(false), attached(false),
+ system(_system), pmem(_system->physmem), context(c)
+{
+ memset(gdbregs, 0, sizeof(gdbregs));
+}
+
+RemoteGDB::~RemoteGDB()
+{
+ if (event)
+ delete event;
+}
+
+string
+RemoteGDB::name()
+{
+ return system->name() + ".remote_gdb";
+}
+
+bool
+RemoteGDB::isattached()
+{ return attached; }
+
+void
+RemoteGDB::attach(int f)
+{
+ fd = f;
+
+ event = new Event(this, fd, POLLIN);
+ pollQueue.schedule(event);
+
+ attached = true;
+ DPRINTFN("remote gdb attached\n");
+}
+
+void
+RemoteGDB::detach()
+{
+ attached = false;
+ close(fd);
+ fd = -1;
+
+ pollQueue.remove(event);
+ DPRINTFN("remote gdb detached\n");
+}
+
+const char *
+gdb_command(char cmd)
+{
+ switch (cmd) {
+ case KGDB_SIGNAL: return "KGDB_SIGNAL";
+ case KGDB_SET_BAUD: return "KGDB_SET_BAUD";
+ case KGDB_SET_BREAK: return "KGDB_SET_BREAK";
+ case KGDB_CONT: return "KGDB_CONT";
+ case KGDB_ASYNC_CONT: return "KGDB_ASYNC_CONT";
+ case KGDB_DEBUG: return "KGDB_DEBUG";
+ case KGDB_DETACH: return "KGDB_DETACH";
+ case KGDB_REG_R: return "KGDB_REG_R";
+ case KGDB_REG_W: return "KGDB_REG_W";
+ case KGDB_SET_THREAD: return "KGDB_SET_THREAD";
+ case KGDB_CYCLE_STEP: return "KGDB_CYCLE_STEP";
+ case KGDB_SIG_CYCLE_STEP: return "KGDB_SIG_CYCLE_STEP";
+ case KGDB_KILL: return "KGDB_KILL";
+ case KGDB_MEM_W: return "KGDB_MEM_W";
+ case KGDB_MEM_R: return "KGDB_MEM_R";
+ case KGDB_SET_REG: return "KGDB_SET_REG";
+ case KGDB_READ_REG: return "KGDB_READ_REG";
+ case KGDB_QUERY_VAR: return "KGDB_QUERY_VAR";
+ case KGDB_SET_VAR: return "KGDB_SET_VAR";
+ case KGDB_RESET: return "KGDB_RESET";
+ case KGDB_STEP: return "KGDB_STEP";
+ case KGDB_ASYNC_STEP: return "KGDB_ASYNC_STEP";
+ case KGDB_THREAD_ALIVE: return "KGDB_THREAD_ALIVE";
+ case KGDB_TARGET_EXIT: return "KGDB_TARGET_EXIT";
+ case KGDB_BINARY_DLOAD: return "KGDB_BINARY_DLOAD";
+ case KGDB_CLR_HW_BKPT: return "KGDB_CLR_HW_BKPT";
+ case KGDB_SET_HW_BKPT: return "KGDB_SET_HW_BKPT";
+ case KGDB_START: return "KGDB_START";
+ case KGDB_END: return "KGDB_END";
+ case KGDB_GOODP: return "KGDB_GOODP";
+ case KGDB_BADP: return "KGDB_BADP";
+ default: return "KGDB_UNKNOWN";
+ }
+}
+
+///////////////////////////////////////////////////////////
+// RemoteGDB::acc
+//
+// Determine if the mapping at va..(va+len) is valid.
+//
+bool
+RemoteGDB::acc(Addr va, size_t len)
+{
+ Addr last_va;
+
+ va = TheISA::TruncPage(va);
+ last_va = TheISA::RoundPage(va + len);
+
+ do {
+ if (TheISA::IsK0Seg(va)) {
+ if (va < (TheISA::K0SegBase + pmem->size())) {
+ DPRINTF(GDBAcc, "acc: Mapping is valid K0SEG <= "
+ "%#x < K0SEG + size\n", va);
+ return true;
+ } else {
+ DPRINTF(GDBAcc, "acc: Mapping invalid %#x > K0SEG + size\n",
+ va);
+ return false;
+ }
+ }
+
+ /**
+ * This code says that all accesses to palcode (instruction and data)
+ * are valid since there isn't a va->pa mapping because palcode is
+ * accessed physically. At some point this should probably be cleaned up
+ * but there is no easy way to do it.
+ */
+
+ if (AlphaISA::PcPAL(va) || va < 0x10000)
+ return true;
+
+ Addr ptbr = context->readMiscReg(AlphaISA::IPR_PALtemp20);
+ TheISA::PageTableEntry pte = TheISA::kernel_pte_lookup(context->getPhysPort(), ptbr, va);
+ if (!pte.valid()) {
+ DPRINTF(GDBAcc, "acc: %#x pte is invalid\n", va);
+ return false;
+ }
+ va += TheISA::PageBytes;
+ } while (va < last_va);
+
+ DPRINTF(GDBAcc, "acc: %#x mapping is valid\n", va);
+ return true;
+}
+
+///////////////////////////////////////////////////////////
+// RemoteGDB::signal
+//
+// Translate a trap number into a Unix-compatible signal number.
+// (GDB only understands Unix signal numbers.)
+//
+int
+RemoteGDB::signal(int type)
+{
+ switch (type) {
+ case ALPHA_KENTRY_INT:
+ return (SIGTRAP);
+
+ case ALPHA_KENTRY_UNA:
+ return (SIGBUS);
+
+ case ALPHA_KENTRY_ARITH:
+ return (SIGFPE);
+
+ case ALPHA_KENTRY_IF:
+ return (SIGILL);
+
+ case ALPHA_KENTRY_MM:
+ return (SIGSEGV);
+
+ default:
+ panic("unknown signal type");
+ return 0;
+ }
+}
+
+///////////////////////////////////////////////////////////
+// RemoteGDB::getregs
+//
+// Translate the kernel debugger register format into
+// the GDB register format.
+void
+RemoteGDB::getregs()
+{
+ memset(gdbregs, 0, sizeof(gdbregs));
+
+ gdbregs[KGDB_REG_PC] = context->readPC();
+
+ // @todo: Currently this is very Alpha specific.
+ if (AlphaISA::PcPAL(gdbregs[KGDB_REG_PC])) {
+ for (int i = 0; i < TheISA::NumIntArchRegs; ++i) {
+ gdbregs[i] = context->readIntReg(AlphaISA::reg_redir[i]);
+ }
+ } else {
+ for (int i = 0; i < TheISA::NumIntArchRegs; ++i) {
+ gdbregs[i] = context->readIntReg(i);
+ }
+ }
+
+#ifdef KGDB_FP_REGS
+ for (int i = 0; i < TheISA::NumFloatArchRegs; ++i) {
+ gdbregs[i + KGDB_REG_F0] = context->readFloatRegBits(i);
+ }
+#endif
+}
+
+///////////////////////////////////////////////////////////
+// RemoteGDB::setregs
+//
+// Translate the GDB register format into the kernel
+// debugger register format.
+//
+void
+RemoteGDB::setregs()
+{
+ // @todo: Currently this is very Alpha specific.
+ if (AlphaISA::PcPAL(gdbregs[KGDB_REG_PC])) {
+ for (int i = 0; i < TheISA::NumIntArchRegs; ++i) {
+ context->setIntReg(AlphaISA::reg_redir[i], gdbregs[i]);
+ }
+ } else {
+ for (int i = 0; i < TheISA::NumIntArchRegs; ++i) {
+ context->setIntReg(i, gdbregs[i]);
+ }
+ }
+
+#ifdef KGDB_FP_REGS
+ for (int i = 0; i < TheISA::NumFloatArchRegs; ++i) {
+ context->setFloatRegBits(i, gdbregs[i + KGDB_REG_F0]);
+ }
+#endif
+ context->setPC(gdbregs[KGDB_REG_PC]);
+}
+
+void
+RemoteGDB::setTempBreakpoint(TempBreakpoint &bkpt, Addr addr)
+{
+ DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", addr);
+
+ bkpt.address = addr;
+ insertHardBreak(addr, 4);
+}
+
+void
+RemoteGDB::clearTempBreakpoint(TempBreakpoint &bkpt)
+{
+ DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n",
+ bkpt.address);
+
+
+ removeHardBreak(bkpt.address, 4);
+ bkpt.address = 0;
+}
+
+void
+RemoteGDB::clearSingleStep()
+{
+ DPRINTF(GDBMisc, "clearSingleStep bt_addr=%#x nt_addr=%#x\n",
+ takenBkpt.address, notTakenBkpt.address);
+
+ if (takenBkpt.address != 0)
+ clearTempBreakpoint(takenBkpt);
+
+ if (notTakenBkpt.address != 0)
+ clearTempBreakpoint(notTakenBkpt);
+}
+
+void
+RemoteGDB::setSingleStep()
+{
+ Addr pc = context->readPC();
+ Addr npc, bpc;
+ bool set_bt = false;
+
+ npc = pc + sizeof(MachInst);
+
+ // User was stopped at pc, e.g. the instruction at pc was not
+ // executed.
+ MachInst inst = read<MachInst>(pc);
+ StaticInstPtr si(inst);
+ if (si->hasBranchTarget(pc, context, bpc)) {
+ // Don't bother setting a breakpoint on the taken branch if it
+ // is the same as the next pc
+ if (bpc != npc)
+ set_bt = true;
+ }
+
+ DPRINTF(GDBMisc, "setSingleStep bt_addr=%#x nt_addr=%#x\n",
+ takenBkpt.address, notTakenBkpt.address);
+
+ setTempBreakpoint(notTakenBkpt, npc);
+
+ if (set_bt)
+ setTempBreakpoint(takenBkpt, bpc);
+}
+
+/////////////////////////
+//
+//
+
+uint8_t
+RemoteGDB::getbyte()
+{
+ uint8_t b;
+ ::read(fd, &b, 1);
+ return b;
+}
+
+void
+RemoteGDB::putbyte(uint8_t b)
+{
+ ::write(fd, &b, 1);
+}
+
+// Send a packet to gdb
+void
+RemoteGDB::send(const char *bp)
+{
+ const char *p;
+ uint8_t csum, c;
+
+ DPRINTF(GDBSend, "send: %s\n", bp);
+
+ do {
+ p = bp;
+ putbyte(KGDB_START);
+ for (csum = 0; (c = *p); p++) {
+ putbyte(c);
+ csum += c;
+ }
+ putbyte(KGDB_END);
+ putbyte(i2digit(csum >> 4));
+ putbyte(i2digit(csum));
+ } while ((c = getbyte() & 0x7f) == KGDB_BADP);
+}
+
+// Receive a packet from gdb
+int
+RemoteGDB::recv(char *bp, int maxlen)
+{
+ char *p;
+ int c, csum;
+ int len;
+
+ do {
+ p = bp;
+ csum = len = 0;
+ while ((c = getbyte()) != KGDB_START)
+ ;
+
+ while ((c = getbyte()) != KGDB_END && len < maxlen) {
+ c &= 0x7f;
+ csum += c;
+ *p++ = c;
+ len++;
+ }
+ csum &= 0xff;
+ *p = '\0';
+
+ if (len >= maxlen) {
+ putbyte(KGDB_BADP);
+ continue;
+ }
+
+ csum -= digit2i(getbyte()) * 16;
+ csum -= digit2i(getbyte());
+
+ if (csum == 0) {
+ putbyte(KGDB_GOODP);
+ // Sequence present?
+ if (bp[2] == ':') {
+ putbyte(bp[0]);
+ putbyte(bp[1]);
+ len -= 3;
+ bcopy(bp + 3, bp, len);
+ }
+ break;
+ }
+ putbyte(KGDB_BADP);
+ } while (1);
+
+ DPRINTF(GDBRecv, "recv: %s: %s\n", gdb_command(*bp), bp);
+
+ return (len);
+}
+
+// Read bytes from kernel address space for debugger.
+bool
+RemoteGDB::read(Addr vaddr, size_t size, char *data)
+{
+ static Addr lastaddr = 0;
+ static size_t lastsize = 0;
+
+ if (vaddr < 10) {
+ DPRINTF(GDBRead, "read: reading memory location zero!\n");
+ vaddr = lastaddr + lastsize;
+ }
+
+ DPRINTF(GDBRead, "read: addr=%#x, size=%d", vaddr, size);
+
+ context->getVirtPort(context)->readBlob(vaddr, (uint8_t*)data, size);
+
+#if TRACING_ON
+ if (DTRACE(GDBRead)) {
+ if (DTRACE(GDBExtra)) {
+ char buf[1024];
+ mem2hex(buf, data, size);
+ DPRINTFNR(": %s\n", buf);
+ } else
+ DPRINTFNR("\n");
+ }
+#endif
+
+ return true;
+}
+
+// Write bytes to kernel address space for debugger.
+bool
+RemoteGDB::write(Addr vaddr, size_t size, const char *data)
+{
+ static Addr lastaddr = 0;
+ static size_t lastsize = 0;
+
+ if (vaddr < 10) {
+ DPRINTF(GDBWrite, "write: writing memory location zero!\n");
+ vaddr = lastaddr + lastsize;
+ }
+
+ if (DTRACE(GDBWrite)) {
+ DPRINTFN("write: addr=%#x, size=%d", vaddr, size);
+ if (DTRACE(GDBExtra)) {
+ char buf[1024];
+ mem2hex(buf, data, size);
+ DPRINTFNR(": %s\n", buf);
+ } else
+ DPRINTFNR("\n");
+ }
+
+ context->getVirtPort(context)->writeBlob(vaddr, (uint8_t*)data, size);
+
+#ifdef IMB
+ alpha_pal_imb();
+#endif
+
+ return true;
+}
+
+
+PCEventQueue *RemoteGDB::getPcEventQueue()
+{
+ return &system->pcEventQueue;
+}
+
+
+RemoteGDB::HardBreakpoint::HardBreakpoint(RemoteGDB *_gdb, Addr pc)
+ : PCEvent(_gdb->getPcEventQueue(), "HardBreakpoint Event", pc),
+ gdb(_gdb), refcount(0)
+{
+ DPRINTF(GDBMisc, "creating hardware breakpoint at %#x\n", evpc);
+}
+
+void
+RemoteGDB::HardBreakpoint::process(ExecContext *xc)
+{
+ DPRINTF(GDBMisc, "handling hardware breakpoint at %#x\n", pc());
+
+ if (xc == gdb->context)
+ gdb->trap(ALPHA_KENTRY_INT);
+}
+
+bool
+RemoteGDB::insertSoftBreak(Addr addr, size_t len)
+{
+ if (len != sizeof(MachInst))
+ panic("invalid length\n");
+
+ return insertHardBreak(addr, len);
+}
+
+bool
+RemoteGDB::removeSoftBreak(Addr addr, size_t len)
+{
+ if (len != sizeof(MachInst))
+ panic("invalid length\n");
+
+ return removeHardBreak(addr, len);
+}
+
+bool
+RemoteGDB::insertHardBreak(Addr addr, size_t len)
+{
+ if (len != sizeof(MachInst))
+ panic("invalid length\n");
+
+ DPRINTF(GDBMisc, "inserting hardware breakpoint at %#x\n", addr);
+
+ HardBreakpoint *&bkpt = hardBreakMap[addr];
+ if (bkpt == 0)
+ bkpt = new HardBreakpoint(this, addr);
+
+ bkpt->refcount++;
+
+ return true;
+}
+
+bool
+RemoteGDB::removeHardBreak(Addr addr, size_t len)
+{
+ if (len != sizeof(MachInst))
+ panic("invalid length\n");
+
+ DPRINTF(GDBMisc, "removing hardware breakpoint at %#x\n", addr);
+
+ break_iter_t i = hardBreakMap.find(addr);
+ if (i == hardBreakMap.end())
+ return false;
+
+ HardBreakpoint *hbp = (*i).second;
+ if (--hbp->refcount == 0) {
+ delete hbp;
+ hardBreakMap.erase(i);
+ }
+
+ return true;
+}
+
+const char *
+break_type(char c)
+{
+ switch(c) {
+ case '0': return "software breakpoint";
+ case '1': return "hardware breakpoint";
+ case '2': return "write watchpoint";
+ case '3': return "read watchpoint";
+ case '4': return "access watchpoint";
+ default: return "unknown breakpoint/watchpoint";
+ }
+}
+
+// This function does all command processing for interfacing to a
+// remote gdb. Note that the error codes are ignored by gdb at
+// present, but might eventually become meaningful. (XXX) It might
+// makes sense to use POSIX errno values, because that is what the
+// gdb/remote.c functions want to return.
+bool
+RemoteGDB::trap(int type)
+{
+ uint64_t val;
+ size_t datalen, len;
+ char data[KGDB_BUFLEN + 1];
+ char buffer[sizeof(gdbregs) * 2 + 256];
+ char temp[KGDB_BUFLEN];
+ const char *p;
+ char command, subcmd;
+ string var;
+ bool ret;
+
+ if (!attached)
+ return false;
+
+ DPRINTF(GDBMisc, "trap: PC=%#x NPC=%#x\n",
+ context->readPC(), context->readNextPC());
+
+ clearSingleStep();
+
+ /*
+ * The first entry to this function is normally through
+ * a breakpoint trap in kgdb_connect(), in which case we
+ * must advance past the breakpoint because gdb will not.
+ *
+ * On the first entry here, we expect that gdb is not yet
+ * listening to us, so just enter the interaction loop.
+ * After the debugger is "active" (connected) it will be
+ * waiting for a "signaled" message from us.
+ */
+ if (!active)
+ active = true;
+ else
+ // Tell remote host that an exception has occurred.
+ snprintf((char *)buffer, sizeof(buffer), "S%02x", signal(type));
+ send(buffer);
+
+ // Stick frame regs into our reg cache.
+ getregs();
+
+ for (;;) {
+ datalen = recv(data, sizeof(data));
+ data[sizeof(data) - 1] = 0; // Sentinel
+ command = data[0];
+ subcmd = 0;
+ p = data + 1;
+ switch (command) {
+
+ case KGDB_SIGNAL:
+ // if this command came from a running gdb, answer it --
+ // the other guy has no way of knowing if we're in or out
+ // of this loop when he issues a "remote-signal".
+ snprintf((char *)buffer, sizeof(buffer), "S%02x", signal(type));
+ send(buffer);
+ continue;
+
+ case KGDB_REG_R:
+ if (2 * sizeof(gdbregs) > sizeof(buffer))
+ panic("buffer too small");
+
+ mem2hex(buffer, gdbregs, sizeof(gdbregs));
+ send(buffer);
+ continue;
+
+ case KGDB_REG_W:
+ p = hex2mem(gdbregs, p, sizeof(gdbregs));
+ if (p == NULL || *p != '\0')
+ send("E01");
+ else {
+ setregs();
+ send("OK");
+ }
+ continue;
+
+#if 0
+ case KGDB_SET_REG:
+ val = hex2i(&p);
+ if (*p++ != '=') {
+ send("E01");
+ continue;
+ }
+ if (val < 0 && val >= KGDB_NUMREGS) {
+ send("E01");
+ continue;
+ }
+
+ gdbregs[val] = hex2i(&p);
+ setregs();
+ send("OK");
+
+ continue;
+#endif
+
+ case KGDB_MEM_R:
+ val = hex2i(&p);
+ if (*p++ != ',') {
+ send("E02");
+ continue;
+ }
+ len = hex2i(&p);
+ if (*p != '\0') {
+ send("E03");
+ continue;
+ }
+ if (len > sizeof(buffer)) {
+ send("E04");
+ continue;
+ }
+ if (!acc(val, len)) {
+ send("E05");
+ continue;
+ }
+
+ if (read(val, (size_t)len, (char *)buffer)) {
+ mem2hex(temp, buffer, len);
+ send(temp);
+ } else {
+ send("E05");
+ }
+ continue;
+
+ case KGDB_MEM_W:
+ val = hex2i(&p);
+ if (*p++ != ',') {
+ send("E06");
+ continue;
+ }
+ len = hex2i(&p);
+ if (*p++ != ':') {
+ send("E07");
+ continue;
+ }
+ if (len > datalen - (p - data)) {
+ send("E08");
+ continue;
+ }
+ p = hex2mem(buffer, p, sizeof(buffer));
+ if (p == NULL) {
+ send("E09");
+ continue;
+ }
+ if (!acc(val, len)) {
+ send("E0A");
+ continue;
+ }
+ if (write(val, (size_t)len, (char *)buffer))
+ send("OK");
+ else
+ send("E0B");
+ continue;
+
+ case KGDB_SET_THREAD:
+ subcmd = *p++;
+ val = hex2i(&p);
+ if (val == 0)
+ send("OK");
+ else
+ send("E01");
+ continue;
+
+ case KGDB_DETACH:
+ case KGDB_KILL:
+ active = false;
+ clearSingleStep();
+ detach();
+ goto out;
+
+ case KGDB_ASYNC_CONT:
+ subcmd = hex2i(&p);
+ if (*p++ == ';') {
+ val = hex2i(&p);
+ context->setPC(val);
+ context->setNextPC(val + sizeof(MachInst));
+ }
+ clearSingleStep();
+ goto out;
+
+ case KGDB_CONT:
+ if (p - data < datalen) {
+ val = hex2i(&p);
+ context->setPC(val);
+ context->setNextPC(val + sizeof(MachInst));
+ }
+ clearSingleStep();
+ goto out;
+
+ case KGDB_ASYNC_STEP:
+ subcmd = hex2i(&p);
+ if (*p++ == ';') {
+ val = hex2i(&p);
+ context->setPC(val);
+ context->setNextPC(val + sizeof(MachInst));
+ }
+ setSingleStep();
+ goto out;
+
+ case KGDB_STEP:
+ if (p - data < datalen) {
+ val = hex2i(&p);
+ context->setPC(val);
+ context->setNextPC(val + sizeof(MachInst));
+ }
+ setSingleStep();
+ goto out;
+
+ case KGDB_CLR_HW_BKPT:
+ subcmd = *p++;
+ if (*p++ != ',') send("E0D");
+ val = hex2i(&p);
+ if (*p++ != ',') send("E0D");
+ len = hex2i(&p);
+
+ DPRINTF(GDBMisc, "clear %s, addr=%#x, len=%d\n",
+ break_type(subcmd), val, len);
+
+ ret = false;
+
+ switch (subcmd) {
+ case '0': // software breakpoint
+ ret = removeSoftBreak(val, len);
+ break;
+
+ case '1': // hardware breakpoint
+ ret = removeHardBreak(val, len);
+ break;
+
+ case '2': // write watchpoint
+ case '3': // read watchpoint
+ case '4': // access watchpoint
+ default: // unknown
+ send("");
+ break;
+ }
+
+ send(ret ? "OK" : "E0C");
+ continue;
+
+ case KGDB_SET_HW_BKPT:
+ subcmd = *p++;
+ if (*p++ != ',') send("E0D");
+ val = hex2i(&p);
+ if (*p++ != ',') send("E0D");
+ len = hex2i(&p);
+
+ DPRINTF(GDBMisc, "set %s, addr=%#x, len=%d\n",
+ break_type(subcmd), val, len);
+
+ ret = false;
+
+ switch (subcmd) {
+ case '0': // software breakpoint
+ ret = insertSoftBreak(val, len);
+ break;
+
+ case '1': // hardware breakpoint
+ ret = insertHardBreak(val, len);
+ break;
+
+ case '2': // write watchpoint
+ case '3': // read watchpoint
+ case '4': // access watchpoint
+ default: // unknown
+ send("");
+ break;
+ }
+
+ send(ret ? "OK" : "E0C");
+ continue;
+
+ case KGDB_QUERY_VAR:
+ var = string(p, datalen - 1);
+ if (var == "C")
+ send("QC0");
+ else
+ send("");
+ continue;
+
+ case KGDB_SET_BAUD:
+ case KGDB_SET_BREAK:
+ case KGDB_DEBUG:
+ case KGDB_CYCLE_STEP:
+ case KGDB_SIG_CYCLE_STEP:
+ case KGDB_READ_REG:
+ case KGDB_SET_VAR:
+ case KGDB_RESET:
+ case KGDB_THREAD_ALIVE:
+ case KGDB_TARGET_EXIT:
+ case KGDB_BINARY_DLOAD:
+ // Unsupported command
+ DPRINTF(GDBMisc, "Unsupported command: %s\n",
+ gdb_command(command));
+ DDUMP(GDBMisc, (uint8_t *)data, datalen);
+ send("");
+ continue;
+
+ default:
+ // Unknown command.
+ DPRINTF(GDBMisc, "Unknown command: %c(%#x)\n",
+ command, command);
+ send("");
+ continue;
+
+
+ }
+ }
+
+ out:
+ return true;
+}
+
+// Convert a hex digit into an integer.
+// This returns -1 if the argument passed is no valid hex digit.
+int
+digit2i(char c)
+{
+ if (c >= '0' && c <= '9')
+ return (c - '0');
+ else if (c >= 'a' && c <= 'f')
+ return (c - 'a' + 10);
+ else if (c >= 'A' && c <= 'F')
+
+ return (c - 'A' + 10);
+ else
+ return (-1);
+}
+
+// Convert the low 4 bits of an integer into an hex digit.
+char
+i2digit(int n)
+{
+ return ("0123456789abcdef"[n & 0x0f]);
+}
+
+// Convert a byte array into an hex string.
+void
+mem2hex(void *vdst, const void *vsrc, int len)
+{
+ char *dst = (char *)vdst;
+ const char *src = (const char *)vsrc;
+
+ while (len--) {
+ *dst++ = i2digit(*src >> 4);
+ *dst++ = i2digit(*src++);
+ }
+ *dst = '\0';
+}
+
+// Convert an hex string into a byte array.
+// This returns a pointer to the character following the last valid
+// hex digit. If the string ends in the middle of a byte, NULL is
+// returned.
+const char *
+hex2mem(void *vdst, const char *src, int maxlen)
+{
+ char *dst = (char *)vdst;
+ int msb, lsb;
+
+ while (*src && maxlen--) {
+ msb = digit2i(*src++);
+ if (msb < 0)
+ return (src - 1);
+ lsb = digit2i(*src++);
+ if (lsb < 0)
+ return (NULL);
+ *dst++ = (msb << 4) | lsb;
+ }
+ return (src);
+}
+
+// Convert an hex string into an integer.
+// This returns a pointer to the character following the last valid
+// hex digit.
+Addr
+hex2i(const char **srcp)
+{
+ const char *src = *srcp;
+ Addr r = 0;
+ int nibble;
+
+ while ((nibble = digit2i(*src)) >= 0) {
+ r *= 16;
+ r += nibble;
+ src++;
+ }
+ *srcp = src;
+ return (r);
+}
+
diff --git a/src/base/remote_gdb.hh b/src/base/remote_gdb.hh
new file mode 100644
index 000000000..b7abf5116
--- /dev/null
+++ b/src/base/remote_gdb.hh
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __REMOTE_GDB_HH__
+#define __REMOTE_GDB_HH__
+
+#include <map>
+
+#include "base/kgdb.h"
+#include "cpu/pc_event.hh"
+#include "base/pollevent.hh"
+#include "base/socket.hh"
+
+class System;
+class ExecContext;
+class PhysicalMemory;
+
+class GDBListener;
+class RemoteGDB
+{
+ protected:
+ typedef TheISA::MachInst MachInst;
+ private:
+ friend void debugger();
+ friend class GDBListener;
+
+ protected:
+ class Event : public PollEvent
+ {
+ protected:
+ RemoteGDB *gdb;
+
+ public:
+ Event(RemoteGDB *g, int fd, int e);
+ void process(int revent);
+ };
+
+ friend class Event;
+ Event *event;
+ GDBListener *listener;
+ int number;
+
+ protected:
+ int fd;
+ uint64_t gdbregs[KGDB_NUMREGS];
+
+ protected:
+#ifdef notyet
+ label_t recover;
+#endif
+ bool active;
+ bool attached;
+
+ System *system;
+ PhysicalMemory *pmem;
+ ExecContext *context;
+
+ protected:
+ uint8_t getbyte();
+ void putbyte(uint8_t b);
+
+ int recv(char *data, int len);
+ void send(const char *data);
+
+ protected:
+ // Machine memory
+ bool read(Addr addr, size_t size, char *data);
+ bool write(Addr addr, size_t size, const char *data);
+
+ template <class T> T read(Addr addr);
+ template <class T> void write(Addr addr, T data);
+
+ public:
+ RemoteGDB(System *system, ExecContext *context);
+ ~RemoteGDB();
+
+ void replaceExecContext(ExecContext *xc) { context = xc; }
+
+ void attach(int fd);
+ void detach();
+ bool isattached();
+
+ bool acc(Addr addr, size_t len);
+ static int signal(int type);
+ bool trap(int type);
+
+ protected:
+ void getregs();
+ void setregs();
+
+ void clearSingleStep();
+ void setSingleStep();
+
+ PCEventQueue *getPcEventQueue();
+
+ protected:
+ class HardBreakpoint : public PCEvent
+ {
+ private:
+ RemoteGDB *gdb;
+
+ public:
+ int refcount;
+
+ public:
+ HardBreakpoint(RemoteGDB *_gdb, Addr addr);
+ std::string name() { return gdb->name() + ".hwbkpt"; }
+
+ virtual void process(ExecContext *xc);
+ };
+ friend class HardBreakpoint;
+
+ typedef std::map<Addr, HardBreakpoint *> break_map_t;
+ typedef break_map_t::iterator break_iter_t;
+ break_map_t hardBreakMap;
+
+ bool insertSoftBreak(Addr addr, size_t len);
+ bool removeSoftBreak(Addr addr, size_t len);
+ bool insertHardBreak(Addr addr, size_t len);
+ bool removeHardBreak(Addr addr, size_t len);
+
+ protected:
+ struct TempBreakpoint {
+ Addr address; // set here
+ MachInst bkpt_inst; // saved instruction at bkpt
+ int init_count; // number of times to skip bkpt
+ int count; // current count
+ };
+
+ TempBreakpoint notTakenBkpt;
+ TempBreakpoint takenBkpt;
+
+ void clearTempBreakpoint(TempBreakpoint &bkpt);
+ void setTempBreakpoint(TempBreakpoint &bkpt, Addr addr);
+
+ public:
+ std::string name();
+};
+
+template <class T>
+inline T
+RemoteGDB::read(Addr addr)
+{
+ T temp;
+ read(addr, sizeof(T), (char *)&temp);
+ return temp;
+}
+
+template <class T>
+inline void
+RemoteGDB::write(Addr addr, T data)
+{ write(addr, sizeof(T), (const char *)&data); }
+
+class GDBListener
+{
+ protected:
+ class Event : public PollEvent
+ {
+ protected:
+ GDBListener *listener;
+
+ public:
+ Event(GDBListener *l, int fd, int e);
+ void process(int revent);
+ };
+
+ friend class Event;
+ Event *event;
+
+ protected:
+ ListenSocket listener;
+ RemoteGDB *gdb;
+ int port;
+
+ public:
+ GDBListener(RemoteGDB *g, int p);
+ ~GDBListener();
+
+ void accept();
+ void listen();
+ std::string name();
+};
+
+#endif /* __REMOTE_GDB_H__ */
diff --git a/src/base/res_list.hh b/src/base/res_list.hh
new file mode 100644
index 000000000..960ed108e
--- /dev/null
+++ b/src/base/res_list.hh
@@ -0,0 +1,755 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __RES_LIST_HH__
+#define __RES_LIST_HH__
+
+#include "base/cprintf.hh"
+#include <assert.h>
+
+#define DEBUG_REMOVE 0
+
+#define DEBUG_MEMORY 0
+//#define DEBUG_MEMORY DEBUG
+
+class res_list_base
+{
+#if DEBUG_MEMORY
+ protected:
+ static long long allocated_elements;
+ static long long allocated_lists;
+
+ public:
+ long long get_elements(void) {
+ return allocated_elements;
+ }
+ long long get_lists(void) {
+ return allocated_lists;
+ }
+
+#endif
+};
+
+#if DEBUG_MEMORY
+extern void what_the(void);
+#endif
+
+template<class T>
+class res_list : public res_list_base
+{
+ public:
+ class iterator;
+
+ class res_element
+ {
+ res_element *next;
+ res_element *prev;
+ T *data;
+ bool allocate_data;
+
+ public:
+ // always adds to the END of the list
+ res_element(res_element *_prev, bool allocate);
+ ~res_element();
+ void dump(void);
+
+ friend class res_list<T>;
+ friend class res_list<T>::iterator;
+ };
+
+ class iterator
+ {
+ private:
+ res_element *p;
+
+ friend class res_list<T>;
+
+ public:
+ // Constructors
+ iterator(res_element *q) : p(q) {}
+ iterator(void) { p=0; };
+
+ void dump(void);
+ T* data_ptr(void);
+ res_element *res_el_ptr(void) { return p;}
+ void point_to(T &d) { p->data = &d; }
+
+ iterator next(void) { return iterator(p->next); }
+ iterator prev(void) { return iterator(p->prev); }
+ bool operator== (iterator x) { return (x.p == this->p); }
+ bool operator != (iterator x) { return (x.p != this->p); }
+ T &operator * (void) { return *(p->data); }
+ T* operator -> (void) { return p->data; }
+ bool isnull(void) { return (p==0); }
+ bool notnull(void) { return (p!=0); }
+ };
+
+ private:
+ iterator unused_elements;
+ iterator head_ptr;
+ iterator tail_ptr;
+
+ unsigned base_elements;
+ unsigned extra_elements;
+ unsigned active_elements;
+ bool allocate_storage;
+ unsigned build_size;
+
+ int remove_count;
+
+ //
+ // Allocate new elements, and assign them to the unused_elements
+ // list.
+ //
+ unsigned allocate_elements(unsigned num, bool allocate_storage);
+
+ public:
+ //
+ // List Constructor
+ //
+ res_list(unsigned size, bool alloc_storage = false,
+ unsigned build_sz = 5);
+
+ //
+ // List Destructor
+ //
+ ~res_list();
+
+ iterator head(void) {return head_ptr;};
+ iterator tail(void) {return tail_ptr;};
+
+ unsigned num_free(void) { return size() - count(); }
+ unsigned size(void) { return base_elements + extra_elements; }
+ unsigned count(void) { return active_elements; }
+ bool empty(void) { return count() == 0; }
+ bool full(void);
+
+ //
+ // Insert with data copy
+ //
+ iterator insert_after(iterator prev, T *d);
+ iterator insert_after(iterator prev, T &d);
+ iterator insert_before(iterator prev, T *d);
+ iterator insert_before(iterator prev, T &d);
+
+ //
+ // Insert new list element (no data copy)
+ //
+ iterator insert_after(iterator prev);
+ iterator insert_before(iterator prev);
+
+ iterator add_tail(T *d) { return insert_after(tail_ptr, d); }
+ iterator add_tail(T &d) { return insert_after(tail_ptr, d); }
+ iterator add_tail(void) { return insert_after(tail_ptr); }
+ iterator add_head(T *d) { return insert_before(head_ptr, d); }
+ iterator add_head(T &d) { return insert_before(head_ptr, d); }
+ iterator add_head(void) { return insert_before(head_ptr); }
+
+ iterator remove(iterator q);
+ iterator remove_head(void) {return remove(head_ptr);}
+ iterator remove_tail(void) {return remove(tail_ptr);}
+
+ bool in_list(iterator j);
+ void free_extras(void);
+ void clear(void);
+ void dump(void);
+ void raw_dump(void);
+};
+
+template <class T>
+inline
+res_list<T>::res_element::res_element(res_element *_prev, bool allocate)
+{
+ allocate_data = allocate;
+ prev = _prev;
+ next = 0;
+
+ if (prev)
+ prev->next = this;
+
+ if (allocate)
+ data = new T;
+ else
+ data = 0;
+
+#if DEBUG_MEMORY
+ ++allocated_elements;
+#endif
+}
+
+template <class T>
+inline
+res_list<T>::res_element::~res_element(void)
+{
+ if (prev)
+ prev->next = next;
+
+ if (next)
+ next->prev = prev;
+
+ if (allocate_data)
+ delete data;
+
+#if DEBUG_MEMORY
+ --allocated_elements;
+#endif
+}
+
+template <class T>
+inline void
+res_list<T>::res_element::dump(void)
+{
+ cprintf(" prev = %#x\n", prev);
+ cprintf(" next = %#x\n", next);
+ cprintf(" data = %#x\n", data);
+}
+
+template <class T>
+inline void
+res_list<T>::iterator::dump(void)
+{
+ if (p && p->data)
+ p->data->dump();
+ else {
+ if (!p)
+ cprintf(" Null Pointer\n");
+ else
+ cprintf(" Null 'data' Pointer\n");
+ }
+}
+
+template <class T>
+inline T *
+res_list<T>::iterator::data_ptr(void)
+{
+ if (p)
+ return p->data;
+ else
+ return 0;
+}
+
+
+//
+// Allocate new elements, and assign them to the unused_elements
+// list.
+//
+template <class T>
+inline unsigned
+res_list<T>::allocate_elements(unsigned num, bool allocate_storage)
+{
+ res_element *pnew, *plast = 0, *pfirst=0;
+
+ for (int i=0; i<num; ++i) {
+ pnew = new res_element(plast, allocate_storage);
+ if (i==0)
+ pfirst = pnew;
+ plast = pnew;
+ }
+
+ if (unused_elements.notnull()) {
+ // Add these new elements to the front of the list
+ plast->next = unused_elements.res_el_ptr();
+ unused_elements.res_el_ptr()->prev = plast;
+ }
+
+ unused_elements = iterator(pfirst);
+
+ return num;
+}
+
+template <class T>
+inline
+res_list<T>::res_list(unsigned size, bool alloc_storage, unsigned build_sz)
+{
+#if DEBUG_MEMORY
+ ++allocated_lists;
+#endif
+ extra_elements = 0;
+ active_elements = 0;
+ build_size = build_sz;
+ allocate_storage = alloc_storage;
+ remove_count = 0;
+
+ // Create the new elements
+ base_elements = allocate_elements(size, alloc_storage);
+
+ // The list of active elements
+ head_ptr = iterator(0);
+ tail_ptr = iterator(0);
+}
+
+//
+// List Destructor
+//
+template <class T>
+inline
+res_list<T>::~res_list(void)
+{
+ iterator n;
+
+#if DEBUG_MEMORY
+ --allocated_lists;
+#endif
+
+ // put everything into the unused list
+ clear();
+
+ // rudely delete all the res_elements
+ for (iterator p = unused_elements;
+ p.notnull();
+ p = n) {
+
+ n = p.next();
+
+ // delete the res_element
+ // (it will take care of deleting the data)
+ delete p.res_el_ptr();
+ }
+}
+
+template <class T>
+inline bool
+res_list<T>::full(void)
+{
+ if (build_size)
+ return false;
+ else
+ return unused_elements.isnull();
+}
+
+//
+// Insert with data copy
+//
+template <class T>
+inline typename res_list<T>::iterator
+res_list<T>::insert_after(iterator prev, T *d)
+{
+ iterator p;
+
+ if (!allocate_storage)
+ this->panic("Can't copy data... not allocating storage");
+
+ p = insert_after(prev);
+ if (p.notnull())
+ *p = *d;
+
+ return p;
+}
+
+
+template <class T>
+inline typename res_list<T>::iterator
+res_list<T>::insert_after(iterator prev, T &d)
+{
+ iterator p;
+
+ p = insert_after(prev);
+ if (p.notnull()) {
+
+ if (allocate_storage) {
+ // if we allocate storage, then copy the contents of the
+ // specified object to our object
+ *p = d;
+ }
+ else {
+ // if we don't allocate storage, then we just want to
+ // point to the specified object
+ p.point_to(d);
+ }
+ }
+
+ return p;
+}
+
+
+template <class T>
+inline typename res_list<T>::iterator
+res_list<T>::insert_after(iterator prev)
+{
+
+#if DEBUG_MEMORY
+ if (active_elements > 2*base_elements) {
+ what_the();
+ }
+#endif
+
+ // If we have no unused elements, make some more
+ if (unused_elements.isnull()) {
+
+ if (build_size == 0) {
+ return 0; // No space left, and can't allocate more....
+ }
+
+ extra_elements += allocate_elements(build_size, allocate_storage);
+ }
+
+ // grab the first unused element
+ res_element *p = unused_elements.res_el_ptr();
+
+ unused_elements = unused_elements.next();
+
+ ++active_elements;
+
+ // Insert the new element
+ if (head_ptr.isnull()) {
+ //
+ // Special case #1: Empty List
+ //
+ head_ptr = p;
+ tail_ptr = p;
+ p->prev = 0;
+ p->next = 0;
+ }
+ else if (prev.isnull()) {
+ //
+ // Special case #2: Insert at head
+ //
+
+ // our next ptr points to old head element
+ p->next = head_ptr.res_el_ptr();
+
+ // our element becomes the new head element
+ head_ptr = p;
+
+ // no previous element for the head
+ p->prev = 0;
+
+ // old head element points back to this element
+ p->next->prev = p;
+ }
+ else if (prev.next().isnull()) {
+ //
+ // Special case #3 Insert at tail
+ //
+
+ // our prev pointer points to old tail element
+ p->prev = tail_ptr.res_el_ptr();
+
+ // our element becomes the new tail
+ tail_ptr = p;
+
+ // no next element for the tail
+ p->next = 0;
+
+ // old tail element point to this element
+ p->prev->next = p;
+ }
+ else {
+ //
+ // Normal insertion (after prev)
+ //
+ p->prev = prev.res_el_ptr();
+ p->next = prev.next().res_el_ptr();
+
+ prev.res_el_ptr()->next = p;
+ p->next->prev = p;
+ }
+
+ return iterator(p);
+}
+
+template <class T>
+inline typename res_list<T>::iterator
+res_list<T>::insert_before(iterator next, T &d)
+{
+ iterator p;
+
+ p = insert_before(next);
+ if (p.notnull()) {
+
+ if (allocate_storage) {
+ // if we allocate storage, then copy the contents of the
+ // specified object to our object
+ *p = d;
+ }
+ else {
+ // if we don't allocate storage, then we just want to
+ // point to the specified object
+ p.point_to(d);
+ }
+ }
+
+ return p;
+}
+
+
+template <class T>
+inline typename res_list<T>::iterator
+res_list<T>::insert_before(iterator next)
+{
+
+#if DEBUG_MEMORY
+ if (active_elements > 2*base_elements) {
+ what_the();
+ }
+#endif
+
+ // If we have no unused elements, make some more
+ if (unused_elements.isnull()) {
+
+ if (build_size == 0) {
+ return 0; // No space left, and can't allocate more....
+ }
+
+ extra_elements += allocate_elements(build_size, allocate_storage);
+ }
+
+ // grab the first unused element
+ res_element *p = unused_elements.res_el_ptr();
+
+ unused_elements = unused_elements.next();
+
+ ++active_elements;
+
+ // Insert the new element
+ if (head_ptr.isnull()) {
+ //
+ // Special case #1: Empty List
+ //
+ head_ptr = p;
+ tail_ptr = p;
+ p->prev = 0;
+ p->next = 0;
+ }
+ else if (next.isnull()) {
+ //
+ // Special case #2 Insert at tail
+ //
+
+ // our prev pointer points to old tail element
+ p->prev = tail_ptr.res_el_ptr();
+
+ // our element becomes the new tail
+ tail_ptr = p;
+
+ // no next element for the tail
+ p->next = 0;
+
+ // old tail element point to this element
+ p->prev->next = p;
+ }
+ else if (next.prev().isnull()) {
+ //
+ // Special case #3: Insert at head
+ //
+
+ // our next ptr points to old head element
+ p->next = head_ptr.res_el_ptr();
+
+ // our element becomes the new head element
+ head_ptr = p;
+
+ // no previous element for the head
+ p->prev = 0;
+
+ // old head element points back to this element
+ p->next->prev = p;
+ }
+ else {
+ //
+ // Normal insertion (before next)
+ //
+ p->next = next.res_el_ptr();
+ p->prev = next.prev().res_el_ptr();
+
+ next.res_el_ptr()->prev = p;
+ p->prev->next = p;
+ }
+
+ return iterator(p);
+}
+
+
+template <class T>
+inline typename res_list<T>::iterator
+res_list<T>::remove(iterator q)
+{
+ res_element *p = q.res_el_ptr();
+ iterator n = 0;
+
+ // Handle the special cases
+ if (active_elements == 1) { // This is the only element
+ head_ptr = 0;
+ tail_ptr = 0;
+ }
+ else if (q == head_ptr) { // This is the head element
+ head_ptr = q.next();
+ head_ptr.res_el_ptr()->prev = 0;
+
+ n = head_ptr;
+ }
+ else if (q == tail_ptr) { // This is the tail element
+ tail_ptr = q.prev();
+ tail_ptr.res_el_ptr()->next = 0;
+ }
+ else { // This is between two elements
+ p->prev->next = p->next;
+ p->next->prev = p->prev;
+
+ // Get the "next" element for return
+ n = p->next;
+ }
+
+ --active_elements;
+
+ // Put this element back onto the unused list
+ p->next = unused_elements.res_el_ptr();
+ p->prev = 0;
+ if (p->next) { // NULL if unused list is empty
+ p->next->prev = p;
+ }
+
+ if (!allocate_storage) {
+ p->data = 0;
+ }
+
+ unused_elements = q;
+
+ // A little "garbage collection"
+ if (++remove_count > 10) {
+ // free_extras();
+ remove_count = 0;
+ }
+
+#if DEBUG_REMOVE
+ unsigned unused_count = 0;
+ for (iterator i=unused_elements;
+ i.notnull();
+ i = i.next()) {
+
+ ++unused_count;
+ }
+
+ assert((active_elements+unused_count) == (base_elements+extra_elements));
+#endif
+
+ return iterator(n);
+}
+
+
+template <class T>
+inline bool
+res_list<T>::in_list(iterator j)
+{
+ iterator i;
+
+ for (i=head(); i.notnull(); i=i.next()) {
+ if (j.res_el_ptr() == i.res_el_ptr()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+template <class T>
+inline void
+res_list<T>::free_extras(void)
+{
+ unsigned num_unused = base_elements + extra_elements - active_elements;
+ unsigned to_free = extra_elements;
+ res_element *p;
+
+
+ if (extra_elements != 0) {
+ //
+ // Free min(extra_elements, # unused elements)
+ //
+ if (extra_elements > num_unused) {
+ to_free = num_unused;
+ }
+
+ p = unused_elements.res_el_ptr();
+ for (int i=0; i<to_free; ++i) {
+ res_element *q = p->next;
+
+ delete p;
+
+ p = q;
+ }
+
+ // update the unused element pointer to point to the first
+ // element that wasn't deleted.
+ unused_elements = iterator(p);
+
+ // Update the number of extra elements
+ extra_elements -= to_free;
+ }
+
+ return;
+}
+
+
+template <class T>
+inline void
+res_list<T>::clear(void)
+{
+ iterator i,n;
+
+ for (i=head_ptr; i.notnull(); i=n) {
+ n = i.next();
+ remove(i);
+ }
+
+ free_extras();
+}
+
+template <class T>
+inline void
+res_list<T>::dump(void)
+{
+ for (iterator i=head(); !i.isnull(); i=i.next())
+ i->dump();
+}
+
+template <class T>
+inline void
+res_list<T>::raw_dump(void)
+{
+ int j = 0;
+ res_element *p;
+ for (iterator i=head(); !i.isnull(); i=i.next()) {
+ cprintf("Element %d:\n", j);
+
+ if (i.notnull()) {
+ p = i.res_el_ptr();
+ cprintf(" points to res_element @ %#x\n", p);
+ p->dump();
+ cprintf(" Data Element:\n");
+ i->dump();
+ }
+ else {
+ cprintf(" NULL iterator!\n");
+ }
+
+ ++j;
+ }
+
+}
+
+#endif // __RES_LIST_HH__
diff --git a/src/base/sat_counter.cc b/src/base/sat_counter.cc
new file mode 100644
index 000000000..7920f6c81
--- /dev/null
+++ b/src/base/sat_counter.cc
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sstream>
+
+#include "base/sat_counter.hh"
+#include "base/statistics.hh"
+#include "sim/stats.hh"
+
+
+using namespace std;
+
+
+SaturatingCounterPred::SaturatingCounterPred(string p_name,
+ string z_name,
+ string o_name,
+ unsigned _index_bits,
+ unsigned _counter_bits,
+ unsigned _zero_change,
+ unsigned _one_change,
+ unsigned _thresh,
+ unsigned _init_value)
+{
+ pred_name = p_name;
+ zero_name = z_name;
+ one_name = o_name;
+
+ index_bits = _index_bits;
+ counter_bits = _counter_bits;
+ zero_change = _zero_change;
+ one_change = _one_change;
+ thresh = _thresh;
+ init_value = _init_value;
+
+ max_index = (1 << index_bits) - 1;
+ max_value = (1 << counter_bits) - 1;
+
+ table = new unsigned[max_index + 1];
+
+ // Initialize with the right parameters & clear the counter
+ for (int i = 0; i <= max_index; ++i)
+ table[i] = init_value;
+}
+
+void SaturatingCounterPred::regStats()
+{
+ using namespace Stats;
+ stringstream name, description;
+
+ //
+ // Number of predictions
+ //
+ name << pred_name << ":" << zero_name << ":preds";
+ description << "number of predictions of " << zero_name;
+ predicted_zero
+ .name(name.str())
+ .desc(description.str())
+ ;
+ description.str("");
+ name.str("");
+
+ name << pred_name << ":" << one_name << ":preds";
+ description << "number of predictions of " << one_name;
+ predicted_one
+ .name(name.str())
+ .desc(description.str())
+ ;
+ description.str("");
+ name.str("");
+
+ //
+ // Count the number of correct predictions
+ //
+ name << pred_name << ":" << zero_name << ":corr_preds";
+ description << "number of correct " << zero_name << " preds";
+ correct_pred_zero
+ .name(name.str())
+ .desc(description.str())
+ ;
+ description.str("");
+ name.str("");
+
+ name << pred_name << ":" << one_name << ":corr_preds";
+ description << "number of correct " << one_name << " preds";
+ correct_pred_one
+ .name(name.str())
+ .desc(description.str())
+ ;
+ description.str("");
+ name.str("");
+
+ //
+ // Number of predictor updates
+ //
+ name << pred_name << ":" << zero_name << ":updates";
+ description << "number of actual " << zero_name << "s";
+ record_zero
+ .name(name.str())
+ .desc(description.str())
+ ;
+ description.str("");
+ name.str("");
+
+ name << pred_name << ":" << one_name << ":updates";
+ description << "number of actual " << one_name << "s";
+ record_one
+ .name(name.str())
+ .desc(description.str())
+ ;
+ description.str("");
+ name.str("");
+}
+
+void SaturatingCounterPred::regFormulas()
+{
+ using namespace Stats;
+ stringstream name, description;
+
+ //
+ // Number of predictions
+ //
+ name << pred_name << ":predictions";
+ preds_total
+ .name(name.str())
+ .desc("total number of predictions made")
+ ;
+ preds_total = predicted_zero + predicted_one;
+ name.str("");
+
+ //
+ // Fraction of all predictions that are one or zero
+ //
+ name << pred_name << ":" << zero_name << ":pred_frac";
+ description << "fraction of all preds that were " << zero_name;
+ pred_frac_zero
+ .name(name.str())
+ .desc(description.str())
+ ;
+ pred_frac_zero = 100 * predicted_zero / preds_total;
+ description.str("");
+ name.str("");
+
+ name << pred_name << ":" << one_name << ":pred_frac";
+ description << "fraction of all preds that were " << one_name;
+ pred_frac_one
+ .name(name.str())
+ .desc(description.str())
+ ;
+ pred_frac_one = 100 * predicted_one / preds_total;
+ description.str("");
+ name.str("");
+
+
+ //
+ // Count the number of correct predictions
+ //
+ name << pred_name << ":correct_preds";
+ correct_total
+ .name(name.str())
+ .desc("total correct predictions made")
+ ;
+ correct_total = correct_pred_one + correct_pred_zero;
+ name.str("");
+
+ //
+ // Number of predictor updates
+ //
+ name << pred_name << ":updates";
+ updates_total
+ .name(name.str())
+ .desc("total number of updates")
+ ;
+ updates_total = record_zero + record_one;
+ name.str("");
+
+ //
+ // Prediction accuracy rates
+ //
+ name << pred_name << ":pred_rate";
+ pred_rate
+ .name(name.str())
+ .desc("correct fraction of all preds")
+ ;
+ pred_rate = correct_total / updates_total;
+ name.str("");
+
+ name << pred_name << ":" << zero_name << ":pred_rate";
+ description << "fraction of " << zero_name << " preds that were correct";
+ frac_correct_zero
+ .name(name.str())
+ .desc(description.str())
+ ;
+ frac_correct_zero = 100 * correct_pred_zero /
+ (correct_pred_zero + record_one - correct_pred_one);
+ description.str("");
+ name.str("");
+
+ name << pred_name << ":" << one_name << ":pred_rate";
+ description << "fraction of " << one_name << " preds that were correct";
+ frac_correct_one
+ .name(name.str())
+ .desc(description.str())
+ ;
+ frac_correct_one = 100 * correct_pred_one /
+ (correct_pred_one + record_zero - correct_pred_zero);
+ description.str("");
+ name.str("");
+
+ //
+ // Coverage
+ //
+ name << pred_name << ":" << zero_name << ":coverage";
+ description << "fraction of " << zero_name
+ << "s that were predicted correctly";
+ coverage_zero
+ .name(name.str())
+ .desc(description.str())
+ ;
+ coverage_zero = 100 * correct_pred_zero / record_zero;
+ description.str("");
+ name.str("");
+
+ name << pred_name << ":" << one_name << ":coverage";
+ description << "fraction of " << one_name
+ << "s that were predicted correctly";
+ coverage_one
+ .name(name.str())
+ .desc(description.str())
+ ;
+ coverage_one = 100 * correct_pred_one / record_one;
+ description.str("");
+ name.str("");
+}
+
+
+
+
+
+
+
+
+
+
diff --git a/src/base/sat_counter.hh b/src/base/sat_counter.hh
new file mode 100644
index 000000000..d7be17b6f
--- /dev/null
+++ b/src/base/sat_counter.hh
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SAT_COUNTER_HH__
+#define __SAT_COUNTER_HH__
+
+#include <string>
+
+#include "base/predictor.hh"
+
+#include "base/statistics.hh"
+#include "sim/stats.hh"
+
+//
+//
+// A simple saturating counter predictor
+//
+//
+class SaturatingCounterPred : public GenericPredictor
+{
+ private:
+ std::string pred_name;
+ std::string zero_name;
+ std::string one_name;
+
+ unsigned index_bits;
+ unsigned counter_bits;
+ unsigned zero_change;
+ unsigned one_change;
+ unsigned thresh;
+ unsigned init_value;
+
+ unsigned max_value; // maximum counter value
+
+ unsigned long max_index; // also the index mask value
+ unsigned *table;
+
+ // Statistics
+ Stats::Scalar<> predicted_one; // Total predictions of one, preds_one
+ Stats::Scalar<> predicted_zero; // Total predictions of zero, preds_zero
+ Stats::Scalar<> correct_pred_one; // Total correct predictions of one, correct_one
+ Stats::Scalar<> correct_pred_zero; // Total correct predictions of zero, correct_zero
+
+ Stats::Scalar<> record_zero; //updates_zero
+ Stats::Scalar<> record_one; //updates_one
+
+ Stats::Formula preds_total;
+ Stats::Formula pred_frac_zero;
+ Stats::Formula pred_frac_one;
+ Stats::Formula correct_total;
+ Stats::Formula updates_total;
+ Stats::Formula pred_rate;
+ Stats::Formula frac_correct_zero;
+ Stats::Formula frac_correct_one;
+ Stats::Formula coverage_zero;
+ Stats::Formula coverage_one;
+
+ private:
+ bool pred_one(unsigned &counter) { return counter > thresh; }
+ bool pred_zero(unsigned &counter) { return counter <= thresh; }
+
+ void update_one(unsigned &counter) {
+
+ if (one_change)
+ counter += one_change;
+ else
+ counter = 0;
+
+ // check for wrap
+ if (counter > max_value)
+ counter = max_value;
+ }
+
+ void update_zero(unsigned &counter) {
+ if (zero_change) {
+ // check for wrap
+ if (counter < zero_change)
+ counter = 0;
+ else
+ counter -= zero_change;
+ } else
+ counter = 0;
+ }
+
+
+ public:
+
+ SaturatingCounterPred(std::string p_name,
+ std::string z_name, std::string o_name,
+ unsigned _index_bits, unsigned _counter_bits = 2,
+ unsigned _zero_change = 1, unsigned _one_change = 1,
+ unsigned _thresh = 1, unsigned _init_value = 0);
+
+ void clear() {
+ for (int i = 0; i <= max_index; ++i)
+ table[i] = init_value;
+ }
+
+ // Record the ACTUAL result... and indicate whether the prediction
+ // corresponding to this event was correct
+ void record(unsigned long _index, unsigned _val, unsigned _predicted,
+ unsigned _pdata)
+ {
+ record(_index, _val, _predicted);
+ }
+
+ void record(unsigned long _index, unsigned _val, unsigned _predicted) {
+ unsigned long index = _index & max_index;
+
+ if (_val) {
+ update_one(table[index]);
+ ++record_one;
+
+ if (_predicted)
+ ++correct_pred_one;
+ } else {
+ update_zero(table[index]);
+ ++record_zero;
+
+ if (!_predicted)
+ ++correct_pred_zero;
+ }
+ }
+
+ unsigned value(unsigned long _index) {
+ unsigned long index = _index & max_index;
+
+ return table[index];
+ }
+
+
+ unsigned predict(unsigned long _index, unsigned &pdata) {
+ return predict(_index);
+ }
+
+ unsigned predict(unsigned long _index) {
+ unsigned long index = _index & max_index;
+
+ if (pred_one(table[index])) {
+ ++predicted_one;
+ return 1;
+ }
+
+ ++predicted_zero;
+ return 0;
+ }
+
+ // No internal state is changed here
+ unsigned peek(unsigned long _index) {
+ unsigned long index = _index & max_index;
+
+ if (pred_one(table[index]))
+ return 1;
+
+ return 0;
+ }
+
+
+ //=======================================================
+ void regStats();
+ void regFormulas();
+};
+
+
+#endif // __SAT_COUNTER_HH__
diff --git a/src/base/sched_list.hh b/src/base/sched_list.hh
new file mode 100644
index 000000000..f794e3514
--- /dev/null
+++ b/src/base/sched_list.hh
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SCHED_LIST_HH
+#define SCHED_LIST_HH
+
+#include <list>
+#include "base/intmath.hh"
+#include "base/misc.hh"
+
+
+// Any types you use this class for must be covered here...
+namespace {
+ void ClearEntry(int &i) { i = 0; };
+ void ClearEntry(unsigned &i) { i = 0; };
+ void ClearEntry(double &i) { i = 0; };
+ template <class T> void ClearEntry(std::list<T> &l) { l.clear(); };
+};
+
+
+//
+// this is a special list type that allows the user to insert elements at a
+// specified positive offset from the "current" element, but only allow them
+// be extracted from the "current" element
+//
+
+
+template <class T>
+class SchedList
+{
+ T *data_array;
+ unsigned position;
+ unsigned size;
+ unsigned mask;
+
+ public:
+ SchedList(unsigned size);
+ SchedList(void);
+
+ void init(unsigned size);
+
+ T &operator[](unsigned offset);
+
+ void advance(void);
+
+ void clear(void);
+};
+
+
+
+//
+// Constructor
+//
+template<class T>
+SchedList<T>::SchedList(unsigned _size)
+{
+ size = _size;
+
+ // size must be a power of two
+ if (!isPowerOf2(size)) {
+ panic("SchedList: size must be a power of two");
+ }
+
+ if (size < 2) {
+ panic("SchedList: you don't want a list that small");
+ }
+
+ // calculate the bit mask for the modulo operation
+ mask = size - 1;
+
+ data_array = new T[size];
+
+ if (!data_array) {
+ panic("SchedList: could not allocate memory");
+ }
+
+ clear();
+}
+
+template<class T>
+SchedList<T>::SchedList(void)
+{
+ data_array = 0;
+ size = 0;
+}
+
+
+template<class T> void
+SchedList<T>::init(unsigned _size)
+{
+ size = _size;
+
+ if (!data_array) {
+ // size must be a power of two
+ if (size & (size-1)) {
+ panic("SchedList: size must be a power of two");
+ }
+
+ if (size < 2) {
+ panic("SchedList: you don't want a list that small");
+ }
+
+ // calculate the bit mask for the modulo operation
+ mask = size - 1;
+
+ data_array = new T[size];
+
+ if (!data_array) {
+ panic("SchedList: could not allocate memory");
+ }
+
+ clear();
+ }
+}
+
+
+template<class T> void
+SchedList<T>::advance(void)
+{
+ ClearEntry(data_array[position]);
+
+ // position = (++position % size);
+ position = ++position & mask;
+}
+
+
+template<class T> void
+SchedList<T>::clear(void)
+{
+ for (unsigned i=0; i<size; ++i) {
+ ClearEntry(data_array[i]);
+ }
+
+ position = 0;
+}
+
+
+template<class T> T&
+SchedList<T>::operator[](unsigned offset)
+{
+ if (offset >= size) {
+ panic("SchedList: can't access element beyond current pointer");
+ }
+
+ // unsigned p = (position + offset) % size;
+ unsigned p = (position + offset) & mask;
+
+ return data_array[p];
+}
+
+
+
+#endif
diff --git a/src/base/socket.cc b/src/base/socket.cc
new file mode 100644
index 000000000..45a60e7e3
--- /dev/null
+++ b/src/base/socket.cc
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#include <errno.h>
+#include <unistd.h>
+
+#include "sim/host.hh"
+#include "base/misc.hh"
+#include "base/socket.hh"
+
+using namespace std;
+
+////////////////////////////////////////////////////////////////////////
+//
+//
+
+ListenSocket::ListenSocket()
+ : listening(false), fd(-1)
+{}
+
+ListenSocket::~ListenSocket()
+{
+ if (fd != -1)
+ close(fd);
+}
+
+// Create a socket and configure it for listening
+bool
+ListenSocket::listen(int port, bool reuse)
+{
+ if (listening)
+ panic("Socket already listening!");
+
+ fd = ::socket(PF_INET, SOCK_STREAM, 0);
+ if (fd < 0)
+ panic("Can't create socket:%s !", strerror(errno));
+
+ if (reuse) {
+ int i = 1;
+ if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&i,
+ sizeof(i)) < 0)
+ panic("ListenSocket(listen): setsockopt() SO_REUSEADDR failed!");
+ }
+
+ struct sockaddr_in sockaddr;
+ sockaddr.sin_family = PF_INET;
+ sockaddr.sin_addr.s_addr = INADDR_ANY;
+
+ sockaddr.sin_port = htons(port);
+ int ret = ::bind(fd, (struct sockaddr *)&sockaddr, sizeof (sockaddr));
+ if (ret != 0) {
+ if (ret == -1 && errno != EADDRINUSE)
+ panic("ListenSocket(listen): bind() failed!");
+ return false;
+ }
+
+ if (::listen(fd, 1) == -1)
+ panic("ListenSocket(listen): listen() failed!");
+
+ listening = true;
+
+ return true;
+}
+
+
+// Open a connection. Accept will block, so if you don't want it to,
+// make sure a connection is ready before you call accept.
+int
+ListenSocket::accept(bool nodelay)
+{
+ struct sockaddr_in sockaddr;
+ socklen_t slen = sizeof (sockaddr);
+ int sfd = ::accept(fd, (struct sockaddr *)&sockaddr, &slen);
+ if (sfd != -1 && nodelay) {
+ int i = 1;
+ ::setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (char *)&i, sizeof(i));
+ }
+
+ return sfd;
+}
diff --git a/src/base/socket.hh b/src/base/socket.hh
new file mode 100644
index 000000000..848405c09
--- /dev/null
+++ b/src/base/socket.hh
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SOCKET_HH__
+#define __SOCKET_HH__
+
+class ListenSocket
+{
+ protected:
+ bool listening;
+ int fd;
+
+ public:
+ ListenSocket();
+ virtual ~ListenSocket();
+
+ virtual int accept(bool nodelay = false);
+ virtual bool listen(int port, bool reuse = true);
+
+ int getfd() const { return fd; }
+ bool islistening() const { return listening; }
+};
+
+#endif //__SOCKET_HH__
diff --git a/src/base/statistics.cc b/src/base/statistics.cc
new file mode 100644
index 000000000..20de46347
--- /dev/null
+++ b/src/base/statistics.cc
@@ -0,0 +1,356 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <iomanip>
+#include <fstream>
+#include <list>
+#include <map>
+#include <string>
+
+#include "base/callback.hh"
+#include "base/cprintf.hh"
+#include "base/hostinfo.hh"
+#include "base/misc.hh"
+#include "base/statistics.hh"
+#include "base/str.hh"
+#include "base/time.hh"
+#include "base/trace.hh"
+#include "base/stats/statdb.hh"
+#include "config/stats_binning.hh"
+
+using namespace std;
+
+namespace Stats {
+
+StatData *
+DataAccess::find() const
+{
+ return Database::find(const_cast<void *>((const void *)this));
+}
+
+const StatData *
+getStatData(const void *stat)
+{
+ return Database::find(const_cast<void *>(stat));
+}
+
+void
+DataAccess::map(StatData *data)
+{
+ Database::regStat(this, data);
+}
+
+StatData *
+DataAccess::statData()
+{
+ StatData *ptr = find();
+ assert(ptr);
+ return ptr;
+}
+
+const StatData *
+DataAccess::statData() const
+{
+ const StatData *ptr = find();
+ assert(ptr);
+ return ptr;
+}
+
+void
+DataAccess::setInit()
+{
+ statData()->flags |= init;
+}
+
+void
+DataAccess::setPrint()
+{
+ Database::regPrint(this);
+}
+
+StatData::StatData()
+ : flags(none), precision(-1), prereq(0)
+{
+ static int count = 0;
+ id = count++;
+}
+
+StatData::~StatData()
+{
+}
+
+bool
+StatData::less(StatData *stat1, StatData *stat2)
+{
+ const string &name1 = stat1->name;
+ const string &name2 = stat2->name;
+
+ vector<string> v1;
+ vector<string> v2;
+
+ tokenize(v1, name1, '.');
+ tokenize(v2, name2, '.');
+
+ int last = min(v1.size(), v2.size()) - 1;
+ for (int i = 0; i < last; ++i)
+ if (v1[i] != v2[i])
+ return v1[i] < v2[i];
+
+ // Special compare for last element.
+ if (v1[last] == v2[last])
+ return v1.size() < v2.size();
+ else
+ return v1[last] < v2[last];
+
+ return false;
+}
+
+bool
+StatData::baseCheck() const
+{
+ if (!(flags & init)) {
+#ifdef DEBUG
+ cprintf("this is stat number %d\n", id);
+#endif
+ panic("Not all stats have been initialized");
+ return false;
+ }
+
+ if ((flags & print) && name.empty()) {
+ panic("all printable stats must be named");
+ return false;
+ }
+
+ return true;
+}
+
+
+void
+FormulaBase::result(VResult &vec) const
+{
+ if (root)
+ vec = root->result();
+}
+
+Result
+FormulaBase::total() const
+{
+ return root ? root->total() : 0.0;
+}
+
+size_t
+FormulaBase::size() const
+{
+ if (!root)
+ return 0;
+ else
+ return root->size();
+}
+
+bool
+FormulaBase::binned() const
+{
+ return root && root->binned();
+}
+
+void
+FormulaBase::reset()
+{
+}
+
+bool
+FormulaBase::zero() const
+{
+ VResult vec;
+ result(vec);
+ for (int i = 0; i < vec.size(); ++i)
+ if (vec[i] != 0.0)
+ return false;
+ return true;
+}
+
+void
+FormulaBase::update(StatData *)
+{
+}
+
+string
+FormulaBase::str() const
+{
+ return root ? root->str() : "";
+}
+
+Formula::Formula()
+{
+ setInit();
+}
+
+Formula::Formula(Temp r)
+{
+ root = r;
+ assert(size());
+}
+
+const Formula &
+Formula::operator=(Temp r)
+{
+ assert(!root && "Can't change formulas");
+ root = r;
+ assert(size());
+ return *this;
+}
+
+const Formula &
+Formula::operator+=(Temp r)
+{
+ if (root)
+ root = NodePtr(new BinaryNode<std::plus<Result> >(root, r));
+ else
+ root = r;
+ assert(size());
+ return *this;
+}
+
+MainBin::MainBin(const string &name)
+ : _name(name), mem(NULL), memsize(-1)
+{
+ Database::regBin(this, name);
+}
+
+MainBin::~MainBin()
+{
+ if (mem)
+ delete [] mem;
+}
+
+char *
+MainBin::memory(off_t off)
+{
+ if (memsize == -1)
+ memsize = ceilPow2((size_t) offset());
+
+ if (!mem) {
+ mem = new char[memsize];
+ memset(mem, 0, memsize);
+ }
+
+ assert(offset() <= size());
+ return mem + off;
+}
+
+void
+check()
+{
+ typedef Database::stat_list_t::iterator iter_t;
+
+ iter_t i, end = Database::stats().end();
+ for (i = Database::stats().begin(); i != end; ++i) {
+ StatData *data = *i;
+ assert(data);
+ if (!data->check() || !data->baseCheck())
+ panic("stat check failed for %s\n", data->name);
+ }
+
+ int j = 0;
+ for (i = Database::stats().begin(); i != end; ++i) {
+ StatData *data = *i;
+ if (!(data->flags & print))
+ data->name = "__Stat" + to_string(j++);
+ }
+
+ Database::stats().sort(StatData::less);
+
+#if STATS_BINNING
+ if (MainBin::curBin() == NULL) {
+ static MainBin mainBin("main bin");
+ mainBin.activate();
+ }
+#endif
+
+ if (i == end)
+ return;
+
+ iter_t last = i;
+ ++i;
+
+ for (i = Database::stats().begin(); i != end; ++i) {
+ if ((*i)->name == (*last)->name)
+ panic("same name used twice! name=%s\n", (*i)->name);
+
+ last = i;
+ }
+}
+
+CallbackQueue resetQueue;
+
+void
+reset()
+{
+ // reset non-binned stats
+ Database::stat_list_t::iterator i = Database::stats().begin();
+ Database::stat_list_t::iterator end = Database::stats().end();
+ while (i != end) {
+ StatData *data = *i;
+ if (!data->binned())
+ data->reset();
+ ++i;
+ }
+
+ // save the bin so we can go back to where we were
+ MainBin *orig = MainBin::curBin();
+
+ // reset binned stats
+ Database::bin_list_t::iterator bi = Database::bins().begin();
+ Database::bin_list_t::iterator be = Database::bins().end();
+ while (bi != be) {
+ MainBin *bin = *bi;
+ bin->activate();
+
+ i = Database::stats().begin();
+ while (i != end) {
+ StatData *data = *i;
+ if (data->binned())
+ data->reset();
+ ++i;
+ }
+ ++bi;
+ }
+
+ // restore bin
+ MainBin::curBin() = orig;
+
+ resetQueue.process();
+}
+
+void
+registerResetCallback(Callback *cb)
+{
+ resetQueue.add(cb);
+}
+
+/* namespace Stats */ }
diff --git a/src/base/statistics.hh b/src/base/statistics.hh
new file mode 100644
index 000000000..dd507c091
--- /dev/null
+++ b/src/base/statistics.hh
@@ -0,0 +1,2896 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * Declaration of Statistics objects.
+ */
+
+/**
+* @todo
+*
+* Generalized N-dimensinal vector
+* documentation
+* key stats
+* interval stats
+* -- these both can use the same function that prints out a
+* specific set of stats
+* VectorStandardDeviation totals
+* Document Namespaces
+*/
+#ifndef __BASE_STATISTICS_HH__
+#define __BASE_STATISTICS_HH__
+
+#include <algorithm>
+#include <cassert>
+#include <cmath>
+#include <functional>
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+#include "base/cprintf.hh"
+#include "base/intmath.hh"
+#include "base/refcnt.hh"
+#include "base/str.hh"
+#include "base/stats/bin.hh"
+#include "base/stats/flags.hh"
+#include "base/stats/visit.hh"
+#include "base/stats/types.hh"
+#include "config/stats_binning.hh"
+#include "sim/host.hh"
+
+class Callback;
+
+/** The current simulated cycle. */
+extern Tick curTick;
+
+/* A namespace for all of the Statistics */
+namespace Stats {
+
+/* Contains the statistic implementation details */
+//////////////////////////////////////////////////////////////////////
+//
+// Statistics Framework Base classes
+//
+//////////////////////////////////////////////////////////////////////
+struct StatData
+{
+ /** The name of the stat. */
+ std::string name;
+ /** The description of the stat. */
+ std::string desc;
+ /** The formatting flags. */
+ StatFlags flags;
+ /** The display precision. */
+ int precision;
+ /** A pointer to a prerequisite Stat. */
+ const StatData *prereq;
+ /**
+ * A unique stat ID for each stat in the simulator.
+ * Can be used externally for lookups as well as for debugging.
+ */
+ int id;
+
+ StatData();
+ virtual ~StatData();
+
+ /**
+ * @return true if the stat is binned.
+ */
+ virtual bool binned() const = 0;
+
+ /**
+ * Reset the corresponding stat to the default state.
+ */
+ virtual void reset() = 0;
+
+ /**
+ * @return true if this stat has a value and satisfies its
+ * requirement as a prereq
+ */
+ virtual bool zero() const = 0;
+
+ /**
+ * Check that this stat has been set up properly and is ready for
+ * use
+ * @return true for success
+ */
+ virtual bool check() const = 0;
+ bool baseCheck() const;
+
+ /**
+ * Visitor entry for outputing statistics data
+ */
+ virtual void visit(Visit &visitor) = 0;
+
+ /**
+ * Checks if the first stat's name is alphabetically less than the second.
+ * This function breaks names up at periods and considers each subname
+ * separately.
+ * @param stat1 The first stat.
+ * @param stat2 The second stat.
+ * @return stat1's name is alphabetically before stat2's
+ */
+ static bool less(StatData *stat1, StatData *stat2);
+};
+
+class ScalarData : public StatData
+{
+ public:
+ virtual Counter value() const = 0;
+ virtual Result result() const = 0;
+ virtual Result total() const = 0;
+ virtual void visit(Visit &visitor) { visitor.visit(*this); }
+};
+
+template <class Stat>
+class ScalarStatData : public ScalarData
+{
+ protected:
+ Stat &s;
+
+ public:
+ ScalarStatData(Stat &stat) : s(stat) {}
+
+ virtual bool binned() const { return s.binned(); }
+ virtual bool check() const { return s.check(); }
+ virtual Counter value() const { return s.value(); }
+ virtual Result result() const { return s.result(); }
+ virtual Result total() const { return s.total(); }
+ virtual void reset() { s.reset(); }
+ virtual bool zero() const { return s.zero(); }
+};
+
+struct VectorData : public StatData
+{
+ /** Names and descriptions of subfields. */
+ mutable std::vector<std::string> subnames;
+ mutable std::vector<std::string> subdescs;
+
+ virtual size_t size() const = 0;
+ virtual const VCounter &value() const = 0;
+ virtual const VResult &result() const = 0;
+ virtual Result total() const = 0;
+ void update()
+ {
+ if (!subnames.empty()) {
+ int s = size();
+ if (subnames.size() < s)
+ subnames.resize(s);
+
+ if (subdescs.size() < s)
+ subdescs.resize(s);
+ }
+ }
+};
+
+template <class Stat>
+class VectorStatData : public VectorData
+{
+ protected:
+ Stat &s;
+ mutable VCounter cvec;
+ mutable VResult rvec;
+
+ public:
+ VectorStatData(Stat &stat) : s(stat) {}
+
+ virtual bool binned() const { return s.binned(); }
+ virtual bool check() const { return s.check(); }
+ virtual bool zero() const { return s.zero(); }
+ virtual void reset() { s.reset(); }
+
+ virtual size_t size() const { return s.size(); }
+ virtual VCounter &value() const
+ {
+ s.value(cvec);
+ return cvec;
+ }
+ virtual const VResult &result() const
+ {
+ s.result(rvec);
+ return rvec;
+ }
+ virtual Result total() const { return s.total(); }
+ virtual void visit(Visit &visitor)
+ {
+ update();
+ s.update(this);
+ visitor.visit(*this);
+ }
+};
+
+struct DistDataData
+{
+ Counter min_val;
+ Counter max_val;
+ Counter underflow;
+ Counter overflow;
+ VCounter cvec;
+ Counter sum;
+ Counter squares;
+ Counter samples;
+
+ Counter min;
+ Counter max;
+ Counter bucket_size;
+ int size;
+ bool fancy;
+};
+
+struct DistData : public StatData
+{
+ /** Local storage for the entry values, used for printing. */
+ DistDataData data;
+};
+
+template <class Stat>
+class DistStatData : public DistData
+{
+ protected:
+ Stat &s;
+
+ public:
+ DistStatData(Stat &stat) : s(stat) {}
+
+ virtual bool binned() const { return s.binned(); }
+ virtual bool check() const { return s.check(); }
+ virtual void reset() { s.reset(); }
+ virtual bool zero() const { return s.zero(); }
+ virtual void visit(Visit &visitor)
+ {
+ s.update(this);
+ visitor.visit(*this);
+ }
+};
+
+struct VectorDistData : public StatData
+{
+ std::vector<DistDataData> data;
+
+ /** Names and descriptions of subfields. */
+ mutable std::vector<std::string> subnames;
+ mutable std::vector<std::string> subdescs;
+
+ /** Local storage for the entry values, used for printing. */
+ mutable VResult rvec;
+
+ virtual size_t size() const = 0;
+ void update()
+ {
+ int s = size();
+ if (subnames.size() < s)
+ subnames.resize(s);
+
+ if (subdescs.size() < s)
+ subdescs.resize(s);
+ }
+};
+
+template <class Stat>
+class VectorDistStatData : public VectorDistData
+{
+ protected:
+ Stat &s;
+ typedef typename Stat::bin_t bin_t;
+
+ public:
+ VectorDistStatData(Stat &stat) : s(stat) {}
+
+ virtual bool binned() const { return bin_t::binned; }
+ virtual bool check() const { return s.check(); }
+ virtual void reset() { s.reset(); }
+ virtual size_t size() const { return s.size(); }
+ virtual bool zero() const { return s.zero(); }
+ virtual void visit(Visit &visitor)
+ {
+ update();
+ s.update(this);
+ visitor.visit(*this);
+ }
+};
+
+struct Vector2dData : public StatData
+{
+ /** Names and descriptions of subfields. */
+ std::vector<std::string> subnames;
+ std::vector<std::string> subdescs;
+ std::vector<std::string> y_subnames;
+
+ /** Local storage for the entry values, used for printing. */
+ mutable VCounter cvec;
+ mutable int x;
+ mutable int y;
+
+ void update()
+ {
+ if (subnames.size() < x)
+ subnames.resize(x);
+ }
+};
+
+template <class Stat>
+class Vector2dStatData : public Vector2dData
+{
+ protected:
+ Stat &s;
+ typedef typename Stat::bin_t bin_t;
+
+ public:
+ Vector2dStatData(Stat &stat) : s(stat) {}
+
+ virtual bool binned() const { return bin_t::binned; }
+ virtual bool check() const { return s.check(); }
+ virtual void reset() { s.reset(); }
+ virtual bool zero() const { return s.zero(); }
+ virtual void visit(Visit &visitor)
+ {
+ update();
+ s.update(this);
+ visitor.visit(*this);
+ }
+};
+
+
+class DataAccess
+{
+ protected:
+ StatData *find() const;
+ void map(StatData *data);
+
+ StatData *statData();
+ const StatData *statData() const;
+
+ void setInit();
+ void setPrint();
+};
+
+template <class Parent, class Child, template <class> class Data>
+class Wrap : public Child
+{
+ protected:
+ Parent &self() { return *reinterpret_cast<Parent *>(this); }
+
+ protected:
+ Data<Child> *statData()
+ {
+ StatData *__data = DataAccess::statData();
+ Data<Child> *ptr = dynamic_cast<Data<Child> *>(__data);
+ assert(ptr);
+ return ptr;
+ }
+
+ public:
+ const Data<Child> *statData() const
+ {
+ const StatData *__data = DataAccess::statData();
+ const Data<Child> *ptr = dynamic_cast<const Data<Child> *>(__data);
+ assert(ptr);
+ return ptr;
+ }
+
+ protected:
+ /**
+ * Copy constructor, copies are not allowed.
+ */
+ Wrap(const Wrap &stat);
+ /**
+ * Can't copy stats.
+ */
+ void operator=(const Wrap &);
+
+ public:
+ Wrap()
+ {
+ map(new Data<Child>(*this));
+ }
+
+ /**
+ * Set the name and marks this stat to print at the end of simulation.
+ * @param name The new name.
+ * @return A reference to this stat.
+ */
+ Parent &name(const std::string &_name)
+ {
+ Data<Child> *data = this->statData();
+ data->name = _name;
+ this->setPrint();
+ return this->self();
+ }
+
+ /**
+ * Set the description and marks this stat to print at the end of
+ * simulation.
+ * @param desc The new description.
+ * @return A reference to this stat.
+ */
+ Parent &desc(const std::string &_desc)
+ {
+ this->statData()->desc = _desc;
+ return this->self();
+ }
+
+ /**
+ * Set the precision and marks this stat to print at the end of simulation.
+ * @param p The new precision
+ * @return A reference to this stat.
+ */
+ Parent &precision(int _precision)
+ {
+ this->statData()->precision = _precision;
+ return this->self();
+ }
+
+ /**
+ * Set the flags and marks this stat to print at the end of simulation.
+ * @param f The new flags.
+ * @return A reference to this stat.
+ */
+ Parent &flags(StatFlags _flags)
+ {
+ this->statData()->flags |= _flags;
+ return this->self();
+ }
+
+ /**
+ * Set the prerequisite stat and marks this stat to print at the end of
+ * simulation.
+ * @param prereq The prerequisite stat.
+ * @return A reference to this stat.
+ */
+ template <class Stat>
+ Parent &prereq(const Stat &prereq)
+ {
+ this->statData()->prereq = prereq.statData();
+ return this->self();
+ }
+};
+
+template <class Parent, class Child, template <class Child> class Data>
+class WrapVec : public Wrap<Parent, Child, Data>
+{
+ public:
+ // The following functions are specific to vectors. If you use them
+ // in a non vector context, you will get a nice compiler error!
+
+ /**
+ * Set the subfield name for the given index, and marks this stat to print
+ * at the end of simulation.
+ * @param index The subfield index.
+ * @param name The new name of the subfield.
+ * @return A reference to this stat.
+ */
+ Parent &subname(int index, const std::string &name)
+ {
+ std::vector<std::string> &subn = this->statData()->subnames;
+ if (subn.size() <= index)
+ subn.resize(index + 1);
+ subn[index] = name;
+ return this->self();
+ }
+
+ /**
+ * Set the subfield description for the given index and marks this stat to
+ * print at the end of simulation.
+ * @param index The subfield index.
+ * @param desc The new description of the subfield
+ * @return A reference to this stat.
+ */
+ Parent &subdesc(int index, const std::string &desc)
+ {
+ std::vector<std::string> &subd = this->statData()->subdescs;
+ if (subd.size() <= index)
+ subd.resize(index + 1);
+ subd[index] = desc;
+
+ return this->self();
+ }
+
+};
+
+template <class Parent, class Child, template <class Child> class Data>
+class WrapVec2d : public WrapVec<Parent, Child, Data>
+{
+ public:
+ /**
+ * @warning This makes the assumption that if you're gonna subnames a 2d
+ * vector, you're subnaming across all y
+ */
+ Parent &ysubnames(const char **names)
+ {
+ Data<Child> *data = this->statData();
+ data->y_subnames.resize(this->y);
+ for (int i = 0; i < this->y; ++i)
+ data->y_subnames[i] = names[i];
+ return this->self();
+ }
+ Parent &ysubname(int index, const std::string subname)
+ {
+ Data<Child> *data = this->statData();
+ assert(index < this->y);
+ data->y_subnames.resize(this->y);
+ data->y_subnames[index] = subname.c_str();
+ return this->self();
+ }
+};
+
+//////////////////////////////////////////////////////////////////////
+//
+// Simple Statistics
+//
+//////////////////////////////////////////////////////////////////////
+
+/**
+ * Templatized storage and interface for a simple scalar stat.
+ */
+struct StatStor
+{
+ public:
+ /** The paramaters for this storage type, none for a scalar. */
+ struct Params { };
+
+ private:
+ /** The statistic value. */
+ Counter data;
+
+ public:
+ /**
+ * Builds this storage element and calls the base constructor of the
+ * datatype.
+ */
+ StatStor(const Params &) : data(Counter()) {}
+
+ /**
+ * The the stat to the given value.
+ * @param val The new value.
+ * @param p The paramters of this storage type.
+ */
+ void set(Counter val, const Params &p) { data = val; }
+ /**
+ * Increment the stat by the given value.
+ * @param val The new value.
+ * @param p The paramters of this storage type.
+ */
+ void inc(Counter val, const Params &p) { data += val; }
+ /**
+ * Decrement the stat by the given value.
+ * @param val The new value.
+ * @param p The paramters of this storage type.
+ */
+ void dec(Counter val, const Params &p) { data -= val; }
+ /**
+ * Return the value of this stat as its base type.
+ * @param p The params of this storage type.
+ * @return The value of this stat.
+ */
+ Counter value(const Params &p) const { return data; }
+ /**
+ * Return the value of this stat as a result type.
+ * @param p The parameters of this storage type.
+ * @return The value of this stat.
+ */
+ Result result(const Params &p) const { return (Result)data; }
+ /**
+ * Reset stat value to default
+ */
+ void reset() { data = Counter(); }
+
+ /**
+ * @return true if zero value
+ */
+ bool zero() const { return data == Counter(); }
+};
+
+/**
+ * Templatized storage and interface to a per-cycle average stat. This keeps
+ * a current count and updates a total (count * cycles) when this count
+ * changes. This allows the quick calculation of a per cycle count of the item
+ * being watched. This is good for keeping track of residencies in structures
+ * among other things.
+ * @todo add lateny to the stat and fix binning.
+ */
+struct AvgStor
+{
+ public:
+ /** The paramaters for this storage type */
+ struct Params
+ {
+ /**
+ * The current count. We stash this here because the current
+ * value is not a binned value.
+ */
+ Counter current;
+ };
+
+ private:
+ /** The total count for all cycles. */
+ mutable Result total;
+ /** The cycle that current last changed. */
+ mutable Tick last;
+
+ public:
+ /**
+ * Build and initializes this stat storage.
+ */
+ AvgStor(Params &p) : total(0), last(0) { p.current = Counter(); }
+
+ /**
+ * Set the current count to the one provided, update the total and last
+ * set values.
+ * @param val The new count.
+ * @param p The parameters for this storage.
+ */
+ void set(Counter val, Params &p) {
+ total += p.current * (curTick - last);
+ last = curTick;
+ p.current = val;
+ }
+
+ /**
+ * Increment the current count by the provided value, calls set.
+ * @param val The amount to increment.
+ * @param p The parameters for this storage.
+ */
+ void inc(Counter val, Params &p) { set(p.current + val, p); }
+
+ /**
+ * Deccrement the current count by the provided value, calls set.
+ * @param val The amount to decrement.
+ * @param p The parameters for this storage.
+ */
+ void dec(Counter val, Params &p) { set(p.current - val, p); }
+
+ /**
+ * Return the current count.
+ * @param p The parameters for this storage.
+ * @return The current count.
+ */
+ Counter value(const Params &p) const { return p.current; }
+
+ /**
+ * Return the current average.
+ * @param p The parameters for this storage.
+ * @return The current average.
+ */
+ Result result(const Params &p) const
+ {
+ total += p.current * (curTick - last);
+ last = curTick;
+ return (Result)(total + p.current) / (Result)(curTick + 1);
+ }
+
+ /**
+ * Reset stat value to default
+ */
+ void reset()
+ {
+ total = 0;
+ last = curTick;
+ }
+
+ /**
+ * @return true if zero value
+ */
+ bool zero() const { return total == 0.0; }
+};
+
+/**
+ * Implementation of a scalar stat. The type of stat is determined by the
+ * Storage template. The storage for this stat is held within the Bin class.
+ * This allows for breaking down statistics across multiple bins easily.
+ */
+template <class Storage, class Bin>
+class ScalarBase : public DataAccess
+{
+ public:
+ /** Define the params of the storage class. */
+ typedef typename Storage::Params params_t;
+ /** Define the bin type. */
+ typedef typename Bin::template Bin<Storage> bin_t;
+
+ protected:
+ /** The bin of this stat. */
+ bin_t bin;
+ /** The parameters for this stat. */
+ params_t params;
+
+ protected:
+ /**
+ * Retrieve the storage from the bin.
+ * @return The storage object for this stat.
+ */
+ Storage *data() { return bin.data(params); }
+ /**
+ * Retrieve a const pointer to the storage from the bin.
+ * @return A const pointer to the storage object for this stat.
+ */
+ const Storage *data() const
+ {
+ bin_t *_bin = const_cast<bin_t *>(&bin);
+ params_t *_params = const_cast<params_t *>(&params);
+ return _bin->data(*_params);
+ }
+
+ public:
+ /**
+ * Return the current value of this stat as its base type.
+ * @return The current value.
+ */
+ Counter value() const { return data()->value(params); }
+
+ public:
+ /**
+ * Create and initialize this stat, register it with the database.
+ */
+ ScalarBase()
+ {
+ bin.init(params);
+ }
+
+ public:
+ // Common operators for stats
+ /**
+ * Increment the stat by 1. This calls the associated storage object inc
+ * function.
+ */
+ void operator++() { data()->inc(1, params); }
+ /**
+ * Decrement the stat by 1. This calls the associated storage object dec
+ * function.
+ */
+ void operator--() { data()->dec(1, params); }
+
+ /** Increment the stat by 1. */
+ void operator++(int) { ++*this; }
+ /** Decrement the stat by 1. */
+ void operator--(int) { --*this; }
+
+ /**
+ * Set the data value to the given value. This calls the associated storage
+ * object set function.
+ * @param v The new value.
+ */
+ template <typename U>
+ void operator=(const U &v) { data()->set(v, params); }
+
+ /**
+ * Increment the stat by the given value. This calls the associated
+ * storage object inc function.
+ * @param v The value to add.
+ */
+ template <typename U>
+ void operator+=(const U &v) { data()->inc(v, params); }
+
+ /**
+ * Decrement the stat by the given value. This calls the associated
+ * storage object dec function.
+ * @param v The value to substract.
+ */
+ template <typename U>
+ void operator-=(const U &v) { data()->dec(v, params); }
+
+ /**
+ * Return the number of elements, always 1 for a scalar.
+ * @return 1.
+ */
+ size_t size() const { return 1; }
+ /**
+ * Return true if stat is binned.
+ *@return True is stat is binned.
+ */
+ bool binned() const { return bin_t::binned; }
+
+ bool check() const { return bin.initialized(); }
+
+ /**
+ * Reset stat value to default
+ */
+ void reset() { bin.reset(); }
+
+ Counter value() { return data()->value(params); }
+
+ Result result() { return data()->result(params); }
+
+ Result total() { return result(); }
+
+ bool zero() { return result() == 0.0; }
+
+};
+
+class ProxyData : public ScalarData
+{
+ public:
+ virtual void visit(Visit &visitor) { visitor.visit(*this); }
+ virtual bool binned() const { return false; }
+ virtual std::string str() const { return to_string(value()); }
+ virtual size_t size() const { return 1; }
+ virtual bool zero() const { return value() == 0; }
+ virtual bool check() const { return true; }
+ virtual void reset() { }
+};
+
+template <class T>
+class ValueProxy : public ProxyData
+{
+ private:
+ T *scalar;
+
+ public:
+ ValueProxy(T &val) : scalar(&val) {}
+ virtual Counter value() const { return *scalar; }
+ virtual Result result() const { return *scalar; }
+ virtual Result total() const { return *scalar; }
+};
+
+template <class T>
+class FunctorProxy : public ProxyData
+{
+ private:
+ T *functor;
+
+ public:
+ FunctorProxy(T &func) : functor(&func) {}
+ virtual Counter value() const { return (*functor)(); }
+ virtual Result result() const { return (*functor)(); }
+ virtual Result total() const { return (*functor)(); }
+};
+
+class ValueBase : public DataAccess
+{
+ private:
+ ProxyData *proxy;
+
+ public:
+ ValueBase() : proxy(NULL) { }
+ ~ValueBase() { if (proxy) delete proxy; }
+
+ template <class T>
+ void scalar(T &value)
+ {
+ proxy = new ValueProxy<T>(value);
+ setInit();
+ }
+
+ template <class T>
+ void functor(T &func)
+ {
+ proxy = new FunctorProxy<T>(func);
+ setInit();
+ }
+
+ Counter value() { return proxy->value(); }
+ Result result() const { return proxy->result(); }
+ Result total() const { return proxy->total(); };
+ size_t size() const { return proxy->size(); }
+
+ bool binned() const { return proxy->binned(); }
+ std::string str() const { return proxy->str(); }
+ bool zero() const { return proxy->zero(); }
+ bool check() const { return proxy != NULL; }
+ void reset() { }
+};
+
+//////////////////////////////////////////////////////////////////////
+//
+// Vector Statistics
+//
+//////////////////////////////////////////////////////////////////////
+template <class Storage, class Bin>
+class ScalarProxy;
+
+/**
+ * Implementation of a vector of stats. The type of stat is determined by the
+ * Storage class. @sa ScalarBase
+ */
+template <class Storage, class Bin>
+class VectorBase : public DataAccess
+{
+ public:
+ /** Define the params of the storage class. */
+ typedef typename Storage::Params params_t;
+ /** Define the bin type. */
+ typedef typename Bin::template VectorBin<Storage> bin_t;
+
+ protected:
+ /** The bin of this stat. */
+ bin_t bin;
+ /** The parameters for this stat. */
+ params_t params;
+
+ protected:
+ /**
+ * Retrieve the storage from the bin for the given index.
+ * @param index The vector index to access.
+ * @return The storage object at the given index.
+ */
+ Storage *data(int index) { return bin.data(index, params); }
+ /**
+ * Retrieve a const pointer to the storage from the bin
+ * for the given index.
+ * @param index The vector index to access.
+ * @return A const pointer to the storage object at the given index.
+ */
+ const Storage *data(int index) const
+ {
+ bin_t *_bin = const_cast<bin_t *>(&bin);
+ params_t *_params = const_cast<params_t *>(&params);
+ return _bin->data(index, *_params);
+ }
+
+ public:
+ void value(VCounter &vec) const
+ {
+ vec.resize(size());
+ for (int i = 0; i < size(); ++i)
+ vec[i] = data(i)->value(params);
+ }
+
+ /**
+ * Copy the values to a local vector and return a reference to it.
+ * @return A reference to a vector of the stat values.
+ */
+ void result(VResult &vec) const
+ {
+ vec.resize(size());
+ for (int i = 0; i < size(); ++i)
+ vec[i] = data(i)->result(params);
+ }
+
+ /**
+ * @return True is stat is binned.
+ */
+ bool binned() const { return bin_t::binned; }
+
+ /**
+ * Return a total of all entries in this vector.
+ * @return The total of all vector entries.
+ */
+ Result total() const {
+ Result total = 0.0;
+ for (int i = 0; i < size(); ++i)
+ total += data(i)->result(params);
+ return total;
+ }
+
+ /**
+ * @return the number of elements in this vector.
+ */
+ size_t size() const { return bin.size(); }
+
+ bool zero() const
+ {
+ for (int i = 0; i < size(); ++i)
+ if (data(i)->zero())
+ return true;
+ return false;
+ }
+
+ bool check() const { return bin.initialized(); }
+ void reset() { bin.reset(); }
+
+ public:
+ VectorBase() {}
+
+ /** Friend this class with the associated scalar proxy. */
+ friend class ScalarProxy<Storage, Bin>;
+
+ /**
+ * Return a reference (ScalarProxy) to the stat at the given index.
+ * @param index The vector index to access.
+ * @return A reference of the stat.
+ */
+ ScalarProxy<Storage, Bin> operator[](int index);
+
+ void update(StatData *data) {}
+};
+
+const StatData * getStatData(const void *stat);
+
+/**
+ * A proxy class to access the stat at a given index in a VectorBase stat.
+ * Behaves like a ScalarBase.
+ */
+template <class Storage, class Bin>
+class ScalarProxy
+{
+ public:
+ /** Define the params of the storage class. */
+ typedef typename Storage::Params params_t;
+ /** Define the bin type. */
+ typedef typename Bin::template VectorBin<Storage> bin_t;
+
+ private:
+ /** Pointer to the bin in the parent VectorBase. */
+ bin_t *bin;
+ /** Pointer to the params in the parent VectorBase. */
+ params_t *params;
+ /** The index to access in the parent VectorBase. */
+ int index;
+ /** Keep a pointer to the original stat so was can get data */
+ void *stat;
+
+ protected:
+ /**
+ * Retrieve the storage from the bin.
+ * @return The storage from the bin for this stat.
+ */
+ Storage *data() { return bin->data(index, *params); }
+ /**
+ * Retrieve a const pointer to the storage from the bin.
+ * @return A const pointer to the storage for this stat.
+ */
+ const Storage *data() const
+ {
+ bin_t *_bin = const_cast<bin_t *>(bin);
+ params_t *_params = const_cast<params_t *>(params);
+ return _bin->data(index, *_params);
+ }
+
+ public:
+ /**
+ * Return the current value of this stat as its base type.
+ * @return The current value.
+ */
+ Counter value() const { return data()->value(*params); }
+
+ /**
+ * Return the current value of this statas a result type.
+ * @return The current value.
+ */
+ Result result() const { return data()->result(*params); }
+
+ public:
+ /**
+ * Create and initialize this proxy, do not register it with the database.
+ * @param b The bin to use.
+ * @param p The params to use.
+ * @param i The index to access.
+ */
+ ScalarProxy(bin_t &b, params_t &p, int i, void *s)
+ : bin(&b), params(&p), index(i), stat(s) {}
+ /**
+ * Create a copy of the provided ScalarProxy.
+ * @param sp The proxy to copy.
+ */
+ ScalarProxy(const ScalarProxy &sp)
+ : bin(sp.bin), params(sp.params), index(sp.index), stat(sp.stat) {}
+ /**
+ * Set this proxy equal to the provided one.
+ * @param sp The proxy to copy.
+ * @return A reference to this proxy.
+ */
+ const ScalarProxy &operator=(const ScalarProxy &sp) {
+ bin = sp.bin;
+ params = sp.params;
+ index = sp.index;
+ stat = sp.stat;
+ return *this;
+ }
+
+ public:
+ // Common operators for stats
+ /**
+ * Increment the stat by 1. This calls the associated storage object inc
+ * function.
+ */
+ void operator++() { data()->inc(1, *params); }
+ /**
+ * Decrement the stat by 1. This calls the associated storage object dec
+ * function.
+ */
+ void operator--() { data()->dec(1, *params); }
+
+ /** Increment the stat by 1. */
+ void operator++(int) { ++*this; }
+ /** Decrement the stat by 1. */
+ void operator--(int) { --*this; }
+
+ /**
+ * Set the data value to the given value. This calls the associated storage
+ * object set function.
+ * @param v The new value.
+ */
+ template <typename U>
+ void operator=(const U &v) { data()->set(v, *params); }
+
+ /**
+ * Increment the stat by the given value. This calls the associated
+ * storage object inc function.
+ * @param v The value to add.
+ */
+ template <typename U>
+ void operator+=(const U &v) { data()->inc(v, *params); }
+
+ /**
+ * Decrement the stat by the given value. This calls the associated
+ * storage object dec function.
+ * @param v The value to substract.
+ */
+ template <typename U>
+ void operator-=(const U &v) { data()->dec(v, *params); }
+
+ /**
+ * Return the number of elements, always 1 for a scalar.
+ * @return 1.
+ */
+ size_t size() const { return 1; }
+
+ /**
+ * Return true if stat is binned.
+ *@return false since Proxies aren't printed/binned
+ */
+ bool binned() const { return false; }
+
+ /**
+ * This stat has no state. Nothing to reset
+ */
+ void reset() { }
+
+ public:
+ const StatData *statData() const { return getStatData(stat); }
+ std::string str() const
+ {
+ return csprintf("%s[%d]", this->statData()->name, index);
+
+ }
+};
+
+template <class Storage, class Bin>
+inline ScalarProxy<Storage, Bin>
+VectorBase<Storage, Bin>::operator[](int index)
+{
+ assert (index >= 0 && index < size());
+ return ScalarProxy<Storage, Bin>(bin, params, index, this);
+}
+
+template <class Storage, class Bin>
+class VectorProxy;
+
+template <class Storage, class Bin>
+class Vector2dBase : public DataAccess
+{
+ public:
+ typedef typename Storage::Params params_t;
+ typedef typename Bin::template VectorBin<Storage> bin_t;
+
+ protected:
+ size_t x;
+ size_t y;
+ bin_t bin;
+ params_t params;
+
+ protected:
+ Storage *data(int index) { return bin.data(index, params); }
+ const Storage *data(int index) const
+ {
+ bin_t *_bin = const_cast<bin_t *>(&bin);
+ params_t *_params = const_cast<params_t *>(&params);
+ return _bin->data(index, *_params);
+ }
+
+ public:
+ Vector2dBase() {}
+
+ void update(Vector2dData *data)
+ {
+ int size = this->size();
+ data->cvec.resize(size);
+ for (int i = 0; i < size; ++i)
+ data->cvec[i] = this->data(i)->value(params);
+ }
+
+ std::string ysubname(int i) const { return (*this->y_subnames)[i]; }
+
+ friend class VectorProxy<Storage, Bin>;
+ VectorProxy<Storage, Bin> operator[](int index);
+
+ size_t size() const { return bin.size(); }
+ bool zero() const { return data(0)->value(params) == 0.0; }
+
+ /**
+ * Reset stat value to default
+ */
+ void reset() { bin.reset(); }
+
+ bool check() { return bin.initialized(); }
+};
+
+template <class Storage, class Bin>
+class VectorProxy
+{
+ public:
+ typedef typename Storage::Params params_t;
+ typedef typename Bin::template VectorBin<Storage> bin_t;
+
+ private:
+ bin_t *bin;
+ params_t *params;
+ int offset;
+ int len;
+ void *stat;
+
+ private:
+ mutable VResult *vec;
+
+ Storage *data(int index) {
+ assert(index < len);
+ return bin->data(offset + index, *params);
+ }
+
+ const Storage *data(int index) const {
+ bin_t *_bin = const_cast<bin_t *>(bin);
+ params_t *_params = const_cast<params_t *>(params);
+ return _bin->data(offset + index, *_params);
+ }
+
+ public:
+ const VResult &result() const {
+ if (vec)
+ vec->resize(size());
+ else
+ vec = new VResult(size());
+
+ for (int i = 0; i < size(); ++i)
+ (*vec)[i] = data(i)->result(*params);
+
+ return *vec;
+ }
+
+ Result total() const {
+ Result total = 0.0;
+ for (int i = 0; i < size(); ++i)
+ total += data(i)->result(*params);
+ return total;
+ }
+
+ public:
+ VectorProxy(bin_t &b, params_t &p, int o, int l, void *s)
+ : bin(&b), params(&p), offset(o), len(l), stat(s), vec(NULL)
+ {
+ }
+
+ VectorProxy(const VectorProxy &sp)
+ : bin(sp.bin), params(sp.params), offset(sp.offset), len(sp.len),
+ stat(sp.stat), vec(NULL)
+ {
+ }
+
+ ~VectorProxy()
+ {
+ if (vec)
+ delete vec;
+ }
+
+ const VectorProxy &operator=(const VectorProxy &sp)
+ {
+ bin = sp.bin;
+ params = sp.params;
+ offset = sp.offset;
+ len = sp.len;
+ stat = sp.stat;
+ if (vec)
+ delete vec;
+ vec = NULL;
+ return *this;
+ }
+
+ ScalarProxy<Storage, Bin> operator[](int index)
+ {
+ assert (index >= 0 && index < size());
+ return ScalarProxy<Storage, Bin>(*bin, *params, offset + index, stat);
+ }
+
+ size_t size() const { return len; }
+
+ /**
+ * Return true if stat is binned.
+ *@return false since Proxies aren't printed/binned
+ */
+ bool binned() const { return false; }
+
+ /**
+ * This stat has no state. Nothing to reset.
+ */
+ void reset() { }
+};
+
+template <class Storage, class Bin>
+inline VectorProxy<Storage, Bin>
+Vector2dBase<Storage, Bin>::operator[](int index)
+{
+ int offset = index * y;
+ assert (index >= 0 && offset < size());
+ return VectorProxy<Storage, Bin>(bin, params, offset, y, this);
+}
+
+//////////////////////////////////////////////////////////////////////
+//
+// Non formula statistics
+//
+//////////////////////////////////////////////////////////////////////
+
+/**
+ * Templatized storage and interface for a distrbution stat.
+ */
+struct DistStor
+{
+ public:
+ /** The parameters for a distribution stat. */
+ struct Params
+ {
+ /** The minimum value to track. */
+ Counter min;
+ /** The maximum value to track. */
+ Counter max;
+ /** The number of entries in each bucket. */
+ Counter bucket_size;
+ /** The number of buckets. Equal to (max-min)/bucket_size. */
+ int size;
+ };
+ enum { fancy = false };
+
+ private:
+ /** The smallest value sampled. */
+ Counter min_val;
+ /** The largest value sampled. */
+ Counter max_val;
+ /** The number of values sampled less than min. */
+ Counter underflow;
+ /** The number of values sampled more than max. */
+ Counter overflow;
+ /** The current sum. */
+ Counter sum;
+ /** The sum of squares. */
+ Counter squares;
+ /** The number of samples. */
+ Counter samples;
+ /** Counter for each bucket. */
+ VCounter cvec;
+
+ public:
+ /**
+ * Construct this storage with the supplied params.
+ * @param params The parameters.
+ */
+ DistStor(const Params &params)
+ : min_val(INT_MAX), max_val(INT_MIN), underflow(Counter()),
+ overflow(Counter()), sum(Counter()), squares(Counter()),
+ samples(Counter()), cvec(params.size)
+ {
+ reset();
+ }
+
+ /**
+ * Add a value to the distribution for the given number of times.
+ * @param val The value to add.
+ * @param number The number of times to add the value.
+ * @param params The paramters of the distribution.
+ */
+ void sample(Counter val, int number, const Params &params)
+ {
+ if (val < params.min)
+ underflow += number;
+ else if (val > params.max)
+ overflow += number;
+ else {
+ int index = (int)floor((val - params.min) / params.bucket_size);
+ assert(index < size(params));
+ cvec[index] += number;
+ }
+
+ if (val < min_val)
+ min_val = val;
+
+ if (val > max_val)
+ max_val = val;
+
+ Counter sample = val * number;
+ sum += sample;
+ squares += sample * sample;
+ samples += number;
+ }
+
+ /**
+ * Return the number of buckets in this distribution.
+ * @return the number of buckets.
+ * @todo Is it faster to return the size from the parameters?
+ */
+ size_t size(const Params &) const { return cvec.size(); }
+
+ /**
+ * Returns true if any calls to sample have been made.
+ * @param params The paramters of the distribution.
+ * @return True if any values have been sampled.
+ */
+ bool zero(const Params &params) const
+ {
+ return samples == Counter();
+ }
+
+ void update(DistDataData *data, const Params &params)
+ {
+ data->min = params.min;
+ data->max = params.max;
+ data->bucket_size = params.bucket_size;
+ data->size = params.size;
+
+ data->min_val = (min_val == INT_MAX) ? 0 : min_val;
+ data->max_val = (max_val == INT_MIN) ? 0 : max_val;
+ data->underflow = underflow;
+ data->overflow = overflow;
+ data->cvec.resize(params.size);
+ for (int i = 0; i < params.size; ++i)
+ data->cvec[i] = cvec[i];
+
+ data->sum = sum;
+ data->squares = squares;
+ data->samples = samples;
+ }
+
+ /**
+ * Reset stat value to default
+ */
+ void reset()
+ {
+ min_val = INT_MAX;
+ max_val = INT_MIN;
+ underflow = 0;
+ overflow = 0;
+
+ int size = cvec.size();
+ for (int i = 0; i < size; ++i)
+ cvec[i] = Counter();
+
+ sum = Counter();
+ squares = Counter();
+ samples = Counter();
+ }
+};
+
+/**
+ * Templatized storage and interface for a distribution that calculates mean
+ * and variance.
+ */
+struct FancyStor
+{
+ public:
+ /**
+ * No paramters for this storage.
+ */
+ struct Params {};
+ enum { fancy = true };
+
+ private:
+ /** The current sum. */
+ Counter sum;
+ /** The sum of squares. */
+ Counter squares;
+ /** The number of samples. */
+ Counter samples;
+
+ public:
+ /**
+ * Create and initialize this storage.
+ */
+ FancyStor(const Params &)
+ : sum(Counter()), squares(Counter()), samples(Counter())
+ { }
+
+ /**
+ * Add a value the given number of times to this running average.
+ * Update the running sum and sum of squares, increment the number of
+ * values seen by the given number.
+ * @param val The value to add.
+ * @param number The number of times to add the value.
+ * @param p The parameters of this stat.
+ */
+ void sample(Counter val, int number, const Params &p)
+ {
+ Counter value = val * number;
+ sum += value;
+ squares += value * value;
+ samples += number;
+ }
+
+ void update(DistDataData *data, const Params &params)
+ {
+ data->sum = sum;
+ data->squares = squares;
+ data->samples = samples;
+ }
+
+ /**
+ * Return the number of entries in this stat, 1
+ * @return 1.
+ */
+ size_t size(const Params &) const { return 1; }
+
+ /**
+ * Return true if no samples have been added.
+ * @return True if no samples have been added.
+ */
+ bool zero(const Params &) const { return samples == Counter(); }
+
+ /**
+ * Reset stat value to default
+ */
+ void reset()
+ {
+ sum = Counter();
+ squares = Counter();
+ samples = Counter();
+ }
+};
+
+/**
+ * Templatized storage for distribution that calculates per cycle mean and
+ * variance.
+ */
+struct AvgFancy
+{
+ public:
+ /** No parameters for this storage. */
+ struct Params {};
+ enum { fancy = true };
+
+ private:
+ /** Current total. */
+ Counter sum;
+ /** Current sum of squares. */
+ Counter squares;
+
+ public:
+ /**
+ * Create and initialize this storage.
+ */
+ AvgFancy(const Params &) : sum(Counter()), squares(Counter()) {}
+
+ /**
+ * Add a value to the distribution for the given number of times.
+ * Update the running sum and sum of squares.
+ * @param val The value to add.
+ * @param number The number of times to add the value.
+ * @param p The paramters of the distribution.
+ */
+ void sample(Counter val, int number, const Params &p)
+ {
+ Counter value = val * number;
+ sum += value;
+ squares += value * value;
+ }
+
+ void update(DistDataData *data, const Params &params)
+ {
+ data->sum = sum;
+ data->squares = squares;
+ data->samples = curTick;
+ }
+
+ /**
+ * Return the number of entries, in this case 1.
+ * @return 1.
+ */
+ size_t size(const Params &params) const { return 1; }
+ /**
+ * Return true if no samples have been added.
+ * @return True if the sum is zero.
+ */
+ bool zero(const Params &params) const { return sum == Counter(); }
+ /**
+ * Reset stat value to default
+ */
+ void reset()
+ {
+ sum = Counter();
+ squares = Counter();
+ }
+};
+
+/**
+ * Implementation of a distribution stat. The type of distribution is
+ * determined by the Storage template. @sa ScalarBase
+ */
+template <class Storage, class Bin>
+class DistBase : public DataAccess
+{
+ public:
+ /** Define the params of the storage class. */
+ typedef typename Storage::Params params_t;
+ /** Define the bin type. */
+ typedef typename Bin::template Bin<Storage> bin_t;
+
+ protected:
+ /** The bin of this stat. */
+ bin_t bin;
+ /** The parameters for this stat. */
+ params_t params;
+
+ protected:
+ /**
+ * Retrieve the storage from the bin.
+ * @return The storage object for this stat.
+ */
+ Storage *data() { return bin.data(params); }
+ /**
+ * Retrieve a const pointer to the storage from the bin.
+ * @return A const pointer to the storage object for this stat.
+ */
+ const Storage *data() const
+ {
+ bin_t *_bin = const_cast<bin_t *>(&bin);
+ params_t *_params = const_cast<params_t *>(&params);
+ return _bin->data(*_params);
+ }
+
+ public:
+ DistBase() { }
+
+ /**
+ * Add a value to the distribtion n times. Calls sample on the storage
+ * class.
+ * @param v The value to add.
+ * @param n The number of times to add it, defaults to 1.
+ */
+ template <typename U>
+ void sample(const U &v, int n = 1) { data()->sample(v, n, params); }
+
+ /**
+ * Return the number of entries in this stat.
+ * @return The number of entries.
+ */
+ size_t size() const { return data()->size(params); }
+ /**
+ * Return true if no samples have been added.
+ * @return True if there haven't been any samples.
+ */
+ bool zero() const { return data()->zero(params); }
+
+ void update(DistData *base)
+ {
+ base->data.fancy = Storage::fancy;
+ data()->update(&(base->data), params);
+ }
+ /**
+ * @return True is stat is binned.
+ */
+ bool binned() const { return bin_t::binned; }
+ /**
+ * Reset stat value to default
+ */
+ void reset()
+ {
+ bin.reset();
+ }
+
+ bool check() { return bin.initialized(); }
+};
+
+template <class Storage, class Bin>
+class DistProxy;
+
+template <class Storage, class Bin>
+class VectorDistBase : public DataAccess
+{
+ public:
+ typedef typename Storage::Params params_t;
+ typedef typename Bin::template VectorBin<Storage> bin_t;
+
+ protected:
+ bin_t bin;
+ params_t params;
+
+ protected:
+ Storage *data(int index) { return bin.data(index, params); }
+ const Storage *data(int index) const
+ {
+ bin_t *_bin = const_cast<bin_t *>(&bin);
+ params_t *_params = const_cast<params_t *>(&params);
+ return _bin->data(index, *_params);
+ }
+
+ public:
+ VectorDistBase() {}
+
+ friend class DistProxy<Storage, Bin>;
+ DistProxy<Storage, Bin> operator[](int index);
+ const DistProxy<Storage, Bin> operator[](int index) const;
+
+ size_t size() const { return bin.size(); }
+ bool zero() const { return false; }
+ /**
+ * Return true if stat is binned.
+ *@return True is stat is binned.
+ */
+ bool binned() const { return bin_t::binned; }
+ /**
+ * Reset stat value to default
+ */
+ void reset() { bin.reset(); }
+
+ bool check() { return bin.initialized(); }
+ void update(VectorDistData *base)
+ {
+ int size = this->size();
+ base->data.resize(size);
+ for (int i = 0; i < size; ++i) {
+ base->data[i].fancy = Storage::fancy;
+ data(i)->update(&(base->data[i]), params);
+ }
+ }
+};
+
+template <class Storage, class Bin>
+class DistProxy
+{
+ public:
+ typedef typename Storage::Params params_t;
+ typedef typename Bin::template Bin<Storage> bin_t;
+ typedef VectorDistBase<Storage, Bin> base_t;
+
+ private:
+ union {
+ base_t *stat;
+ const base_t *cstat;
+ };
+ int index;
+
+ protected:
+ Storage *data() { return stat->data(index); }
+ const Storage *data() const { return cstat->data(index); }
+
+ public:
+ DistProxy(const VectorDistBase<Storage, Bin> &s, int i)
+ : cstat(&s), index(i) {}
+ DistProxy(const DistProxy &sp)
+ : cstat(sp.cstat), index(sp.index) {}
+ const DistProxy &operator=(const DistProxy &sp) {
+ cstat = sp.cstat; index = sp.index; return *this;
+ }
+
+ public:
+ template <typename U>
+ void sample(const U &v, int n = 1) { data()->sample(v, n, cstat->params); }
+
+ size_t size() const { return 1; }
+ bool zero() const { return data()->zero(cstat->params); }
+ /**
+ * Return true if stat is binned.
+ *@return false since Proxies are not binned/printed.
+ */
+ bool binned() const { return false; }
+ /**
+ * Proxy has no state. Nothing to reset.
+ */
+ void reset() { }
+};
+
+template <class Storage, class Bin>
+inline DistProxy<Storage, Bin>
+VectorDistBase<Storage, Bin>::operator[](int index)
+{
+ assert (index >= 0 && index < size());
+ return DistProxy<Storage, Bin>(*this, index);
+}
+
+template <class Storage, class Bin>
+inline const DistProxy<Storage, Bin>
+VectorDistBase<Storage, Bin>::operator[](int index) const
+{
+ assert (index >= 0 && index < size());
+ return DistProxy<Storage, Bin>(*this, index);
+}
+
+#if 0
+template <class Storage, class Bin>
+Result
+VectorDistBase<Storage, Bin>::total(int index) const
+{
+ int total = 0;
+ for (int i=0; i < x_size(); ++i) {
+ total += data(i)->result(*params);
+ }
+}
+#endif
+
+//////////////////////////////////////////////////////////////////////
+//
+// Formula Details
+//
+//////////////////////////////////////////////////////////////////////
+
+/**
+ * Base class for formula statistic node. These nodes are used to build a tree
+ * that represents the formula.
+ */
+class Node : public RefCounted
+{
+ public:
+ /**
+ * Return the number of nodes in the subtree starting at this node.
+ * @return the number of nodes in this subtree.
+ */
+ virtual size_t size() const = 0;
+ /**
+ * Return the result vector of this subtree.
+ * @return The result vector of this subtree.
+ */
+ virtual const VResult &result() const = 0;
+ /**
+ * Return the total of the result vector.
+ * @return The total of the result vector.
+ */
+ virtual Result total() const = 0;
+ /**
+ * Return true if stat is binned.
+ *@return True is stat is binned.
+ */
+ virtual bool binned() const = 0;
+
+ /**
+ *
+ */
+ virtual std::string str() const = 0;
+};
+
+/** Reference counting pointer to a function Node. */
+typedef RefCountingPtr<Node> NodePtr;
+
+class ScalarStatNode : public Node
+{
+ private:
+ const ScalarData *data;
+ mutable VResult vresult;
+
+ public:
+ ScalarStatNode(const ScalarData *d) : data(d), vresult(1) {}
+ virtual const VResult &result() const
+ {
+ vresult[0] = data->result();
+ return vresult;
+ }
+ virtual Result total() const { return data->result(); };
+
+ virtual size_t size() const { return 1; }
+ /**
+ * Return true if stat is binned.
+ *@return True is stat is binned.
+ */
+ virtual bool binned() const { return data->binned(); }
+
+ /**
+ *
+ */
+ virtual std::string str() const { return data->name; }
+};
+
+template <class Storage, class Bin>
+class ScalarProxyNode : public Node
+{
+ private:
+ const ScalarProxy<Storage, Bin> proxy;
+ mutable VResult vresult;
+
+ public:
+ ScalarProxyNode(const ScalarProxy<Storage, Bin> &p)
+ : proxy(p), vresult(1) { }
+ virtual const VResult &result() const
+ {
+ vresult[0] = proxy.result();
+ return vresult;
+ }
+ virtual Result total() const { return proxy.result(); };
+
+ virtual size_t size() const { return 1; }
+ /**
+ * Return true if stat is binned.
+ *@return True is stat is binned.
+ */
+ virtual bool binned() const { return proxy.binned(); }
+
+ /**
+ *
+ */
+ virtual std::string str() const { return proxy.str(); }
+};
+
+class VectorStatNode : public Node
+{
+ private:
+ const VectorData *data;
+
+ public:
+ VectorStatNode(const VectorData *d) : data(d) { }
+ virtual const VResult &result() const { return data->result(); }
+ virtual Result total() const { return data->total(); };
+
+ virtual size_t size() const { return data->size(); }
+ /**
+ * Return true if stat is binned.
+ *@return True is stat is binned.
+ */
+ virtual bool binned() const { return data->binned(); }
+
+ virtual std::string str() const { return data->name; }
+};
+
+template <class T>
+class ConstNode : public Node
+{
+ private:
+ VResult vresult;
+
+ public:
+ ConstNode(T s) : vresult(1, (Result)s) {}
+ const VResult &result() const { return vresult; }
+ virtual Result total() const { return vresult[0]; };
+ virtual size_t size() const { return 1; }
+
+ /**
+ * Return true if stat is binned.
+ *@return False since constants aren't binned.
+ */
+ virtual bool binned() const { return false; }
+
+ virtual std::string str() const { return to_string(vresult[0]); }
+};
+
+template <class Op>
+struct OpString;
+
+template<>
+struct OpString<std::plus<Result> >
+{
+ static std::string str() { return "+"; }
+};
+
+template<>
+struct OpString<std::minus<Result> >
+{
+ static std::string str() { return "-"; }
+};
+
+template<>
+struct OpString<std::multiplies<Result> >
+{
+ static std::string str() { return "*"; }
+};
+
+template<>
+struct OpString<std::divides<Result> >
+{
+ static std::string str() { return "/"; }
+};
+
+template<>
+struct OpString<std::modulus<Result> >
+{
+ static std::string str() { return "%"; }
+};
+
+template<>
+struct OpString<std::negate<Result> >
+{
+ static std::string str() { return "-"; }
+};
+
+template <class Op>
+class UnaryNode : public Node
+{
+ public:
+ NodePtr l;
+ mutable VResult vresult;
+
+ public:
+ UnaryNode(NodePtr &p) : l(p) {}
+
+ const VResult &result() const
+ {
+ const VResult &lvec = l->result();
+ int size = lvec.size();
+
+ assert(size > 0);
+
+ vresult.resize(size);
+ Op op;
+ for (int i = 0; i < size; ++i)
+ vresult[i] = op(lvec[i]);
+
+ return vresult;
+ }
+
+ Result total() const {
+ Op op;
+ return op(l->total());
+ }
+
+ virtual size_t size() const { return l->size(); }
+ /**
+ * Return true if child of node is binned.
+ *@return True if child of node is binned.
+ */
+ virtual bool binned() const { return l->binned(); }
+
+ virtual std::string str() const
+ {
+ return OpString<Op>::str() + l->str();
+ }
+};
+
+template <class Op>
+class BinaryNode : public Node
+{
+ public:
+ NodePtr l;
+ NodePtr r;
+ mutable VResult vresult;
+
+ public:
+ BinaryNode(NodePtr &a, NodePtr &b) : l(a), r(b) {}
+
+ const VResult &result() const
+ {
+ Op op;
+ const VResult &lvec = l->result();
+ const VResult &rvec = r->result();
+
+ assert(lvec.size() > 0 && rvec.size() > 0);
+
+ if (lvec.size() == 1 && rvec.size() == 1) {
+ vresult.resize(1);
+ vresult[0] = op(lvec[0], rvec[0]);
+ } else if (lvec.size() == 1) {
+ int size = rvec.size();
+ vresult.resize(size);
+ for (int i = 0; i < size; ++i)
+ vresult[i] = op(lvec[0], rvec[i]);
+ } else if (rvec.size() == 1) {
+ int size = lvec.size();
+ vresult.resize(size);
+ for (int i = 0; i < size; ++i)
+ vresult[i] = op(lvec[i], rvec[0]);
+ } else if (rvec.size() == lvec.size()) {
+ int size = rvec.size();
+ vresult.resize(size);
+ for (int i = 0; i < size; ++i)
+ vresult[i] = op(lvec[i], rvec[i]);
+ }
+
+ return vresult;
+ }
+
+ Result total() const {
+ Op op;
+ return op(l->total(), r->total());
+ }
+
+ virtual size_t size() const {
+ int ls = l->size();
+ int rs = r->size();
+ if (ls == 1)
+ return rs;
+ else if (rs == 1)
+ return ls;
+ else {
+ assert(ls == rs && "Node vector sizes are not equal");
+ return ls;
+ }
+ }
+ /**
+ * Return true if any children of node are binned
+ *@return True if either child of node is binned.
+ */
+ virtual bool binned() const { return (l->binned() || r->binned()); }
+
+ virtual std::string str() const
+ {
+ return csprintf("(%s %s %s)", l->str(), OpString<Op>::str(), r->str());
+ }
+};
+
+template <class Op>
+class SumNode : public Node
+{
+ public:
+ NodePtr l;
+ mutable VResult vresult;
+
+ public:
+ SumNode(NodePtr &p) : l(p), vresult(1) {}
+
+ const VResult &result() const
+ {
+ const VResult &lvec = l->result();
+ int size = lvec.size();
+ assert(size > 0);
+
+ vresult[0] = 0.0;
+
+ Op op;
+ for (int i = 0; i < size; ++i)
+ vresult[0] = op(vresult[0], lvec[i]);
+
+ return vresult;
+ }
+
+ Result total() const
+ {
+ const VResult &lvec = l->result();
+ int size = lvec.size();
+ assert(size > 0);
+
+ Result vresult = 0.0;
+
+ Op op;
+ for (int i = 0; i < size; ++i)
+ vresult = op(vresult, lvec[i]);
+
+ return vresult;
+ }
+
+ virtual size_t size() const { return 1; }
+ /**
+ * Return true if child of node is binned.
+ *@return True if child of node is binned.
+ */
+ virtual bool binned() const { return l->binned(); }
+
+ virtual std::string str() const
+ {
+ return csprintf("total(%s)", l->str());
+ }
+};
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Visible Statistics Types
+//
+//////////////////////////////////////////////////////////////////////
+/**
+ * @defgroup VisibleStats "Statistic Types"
+ * These are the statistics that are used in the simulator. By default these
+ * store counters and don't use binning, but are templatized to accept any type
+ * and any Bin class.
+ * @{
+ */
+
+/**
+ * This is an easy way to assign all your stats to be binned or not
+ * binned. If the typedef is NoBin, nothing is binned. If it is
+ * MainBin, then all stats are binned under that Bin.
+ */
+#if STATS_BINNING
+typedef MainBin DefaultBin;
+#else
+typedef NoBin DefaultBin;
+#endif
+
+/**
+ * This is a simple scalar statistic, like a counter.
+ * @sa Stat, ScalarBase, StatStor
+ */
+template <class Bin = DefaultBin>
+class Scalar
+ : public Wrap<Scalar<Bin>,
+ ScalarBase<StatStor, Bin>,
+ ScalarStatData>
+{
+ public:
+ /** The base implementation. */
+ typedef ScalarBase<StatStor, Bin> Base;
+
+ Scalar()
+ {
+ this->setInit();
+ }
+
+ /**
+ * Sets the stat equal to the given value. Calls the base implementation
+ * of operator=
+ * @param v The new value.
+ */
+ template <typename U>
+ void operator=(const U &v) { Base::operator=(v); }
+};
+
+class Value
+ : public Wrap<Value,
+ ValueBase,
+ ScalarStatData>
+{
+ public:
+ /** The base implementation. */
+ typedef ValueBase Base;
+
+ template <class T>
+ Value &scalar(T &value)
+ {
+ Base::scalar(value);
+ return *this;
+ }
+
+ template <class T>
+ Value &functor(T &func)
+ {
+ Base::functor(func);
+ return *this;
+ }
+};
+
+/**
+ * A stat that calculates the per cycle average of a value.
+ * @sa Stat, ScalarBase, AvgStor
+ */
+template <class Bin = DefaultBin>
+class Average
+ : public Wrap<Average<Bin>,
+ ScalarBase<AvgStor, Bin>,
+ ScalarStatData>
+{
+ public:
+ /** The base implementation. */
+ typedef ScalarBase<AvgStor, Bin> Base;
+
+ Average()
+ {
+ this->setInit();
+ }
+
+ /**
+ * Sets the stat equal to the given value. Calls the base implementation
+ * of operator=
+ * @param v The new value.
+ */
+ template <typename U>
+ void operator=(const U &v) { Base::operator=(v); }
+};
+
+/**
+ * A vector of scalar stats.
+ * @sa Stat, VectorBase, StatStor
+ */
+template <class Bin = DefaultBin>
+class Vector
+ : public WrapVec<Vector<Bin>,
+ VectorBase<StatStor, Bin>,
+ VectorStatData>
+{
+ public:
+ /** The base implementation. */
+ typedef ScalarBase<StatStor, Bin> Base;
+
+ /**
+ * Set this vector to have the given size.
+ * @param size The new size.
+ * @return A reference to this stat.
+ */
+ Vector &init(size_t size) {
+ this->bin.init(size, this->params);
+ this->setInit();
+
+ return *this;
+ }
+};
+
+/**
+ * A vector of Average stats.
+ * @sa Stat, VectorBase, AvgStor
+ */
+template <class Bin = DefaultBin>
+class AverageVector
+ : public WrapVec<AverageVector<Bin>,
+ VectorBase<AvgStor, Bin>,
+ VectorStatData>
+{
+ public:
+ /**
+ * Set this vector to have the given size.
+ * @param size The new size.
+ * @return A reference to this stat.
+ */
+ AverageVector &init(size_t size) {
+ this->bin.init(size, this->params);
+ this->setInit();
+
+ return *this;
+ }
+};
+
+/**
+ * A 2-Dimensional vecto of scalar stats.
+ * @sa Stat, Vector2dBase, StatStor
+ */
+template <class Bin = DefaultBin>
+class Vector2d
+ : public WrapVec2d<Vector2d<Bin>,
+ Vector2dBase<StatStor, Bin>,
+ Vector2dStatData>
+{
+ public:
+ Vector2d &init(size_t _x, size_t _y) {
+ this->statData()->x = this->x = _x;
+ this->statData()->y = this->y = _y;
+ this->bin.init(this->x * this->y, this->params);
+ this->setInit();
+
+ return *this;
+ }
+};
+
+/**
+ * A simple distribution stat.
+ * @sa Stat, DistBase, DistStor
+ */
+template <class Bin = DefaultBin>
+class Distribution
+ : public Wrap<Distribution<Bin>,
+ DistBase<DistStor, Bin>,
+ DistStatData>
+{
+ public:
+ /** Base implementation. */
+ typedef DistBase<DistStor, Bin> Base;
+ /** The Parameter type. */
+ typedef typename DistStor::Params Params;
+
+ public:
+ /**
+ * Set the parameters of this distribution. @sa DistStor::Params
+ * @param min The minimum value of the distribution.
+ * @param max The maximum value of the distribution.
+ * @param bkt The number of values in each bucket.
+ * @return A reference to this distribution.
+ */
+ Distribution &init(Counter min, Counter max, Counter bkt) {
+ this->params.min = min;
+ this->params.max = max;
+ this->params.bucket_size = bkt;
+ this->params.size = (int)rint((max - min) / bkt + 1.0);
+ this->bin.init(this->params);
+ this->setInit();
+
+ return *this;
+ }
+};
+
+/**
+ * Calculates the mean and variance of all the samples.
+ * @sa Stat, DistBase, FancyStor
+ */
+template <class Bin = DefaultBin>
+class StandardDeviation
+ : public Wrap<StandardDeviation<Bin>,
+ DistBase<FancyStor, Bin>,
+ DistStatData>
+{
+ public:
+ /** The base implementation */
+ typedef DistBase<DistStor, Bin> Base;
+ /** The parameter type. */
+ typedef typename DistStor::Params Params;
+
+ public:
+ /**
+ * Construct and initialize this distribution.
+ */
+ StandardDeviation() {
+ this->bin.init(this->params);
+ this->setInit();
+ }
+};
+
+/**
+ * Calculates the per cycle mean and variance of the samples.
+ * @sa Stat, DistBase, AvgFancy
+ */
+template <class Bin = DefaultBin>
+class AverageDeviation
+ : public Wrap<AverageDeviation<Bin>,
+ DistBase<AvgFancy, Bin>,
+ DistStatData>
+{
+ public:
+ /** The base implementation */
+ typedef DistBase<DistStor, Bin> Base;
+ /** The parameter type. */
+ typedef typename DistStor::Params Params;
+
+ public:
+ /**
+ * Construct and initialize this distribution.
+ */
+ AverageDeviation()
+ {
+ this->bin.init(this->params);
+ this->setInit();
+ }
+};
+
+/**
+ * A vector of distributions.
+ * @sa Stat, VectorDistBase, DistStor
+ */
+template <class Bin = DefaultBin>
+class VectorDistribution
+ : public WrapVec<VectorDistribution<Bin>,
+ VectorDistBase<DistStor, Bin>,
+ VectorDistStatData>
+{
+ public:
+ /** The base implementation */
+ typedef VectorDistBase<DistStor, Bin> Base;
+ /** The parameter type. */
+ typedef typename DistStor::Params Params;
+
+ public:
+ /**
+ * Initialize storage and parameters for this distribution.
+ * @param size The size of the vector (the number of distributions).
+ * @param min The minimum value of the distribution.
+ * @param max The maximum value of the distribution.
+ * @param bkt The number of values in each bucket.
+ * @return A reference to this distribution.
+ */
+ VectorDistribution &init(int size, Counter min, Counter max, Counter bkt) {
+ this->params.min = min;
+ this->params.max = max;
+ this->params.bucket_size = bkt;
+ this->params.size = (int)rint((max - min) / bkt + 1.0);
+ this->bin.init(size, this->params);
+ this->setInit();
+
+ return *this;
+ }
+};
+
+/**
+ * This is a vector of StandardDeviation stats.
+ * @sa Stat, VectorDistBase, FancyStor
+ */
+template <class Bin = DefaultBin>
+class VectorStandardDeviation
+ : public WrapVec<VectorStandardDeviation<Bin>,
+ VectorDistBase<FancyStor, Bin>,
+ VectorDistStatData>
+{
+ public:
+ /** The base implementation */
+ typedef VectorDistBase<FancyStor, Bin> Base;
+ /** The parameter type. */
+ typedef typename DistStor::Params Params;
+
+ public:
+ /**
+ * Initialize storage for this distribution.
+ * @param size The size of the vector.
+ * @return A reference to this distribution.
+ */
+ VectorStandardDeviation &init(int size) {
+ this->bin.init(size, this->params);
+ this->setInit();
+
+ return *this;
+ }
+};
+
+/**
+ * This is a vector of AverageDeviation stats.
+ * @sa Stat, VectorDistBase, AvgFancy
+ */
+template <class Bin = DefaultBin>
+class VectorAverageDeviation
+ : public WrapVec<VectorAverageDeviation<Bin>,
+ VectorDistBase<AvgFancy, Bin>,
+ VectorDistStatData>
+{
+ public:
+ /** The base implementation */
+ typedef VectorDistBase<AvgFancy, Bin> Base;
+ /** The parameter type. */
+ typedef typename DistStor::Params Params;
+
+ public:
+ /**
+ * Initialize storage for this distribution.
+ * @param size The size of the vector.
+ * @return A reference to this distribution.
+ */
+ VectorAverageDeviation &init(int size) {
+ this->bin.init(size, this->params);
+ this->setInit();
+
+ return *this;
+ }
+};
+
+/**
+ * A formula for statistics that is calculated when printed. A formula is
+ * stored as a tree of Nodes that represent the equation to calculate.
+ * @sa Stat, ScalarStat, VectorStat, Node, Temp
+ */
+class FormulaBase : public DataAccess
+{
+ protected:
+ /** The root of the tree which represents the Formula */
+ NodePtr root;
+ friend class Temp;
+
+ public:
+ /**
+ * Return the result of the Fomula in a vector. If there were no Vector
+ * components to the Formula, then the vector is size 1. If there were,
+ * like x/y with x being a vector of size 3, then the result returned will
+ * be x[0]/y, x[1]/y, x[2]/y, respectively.
+ * @return The result vector.
+ */
+ void result(VResult &vec) const;
+
+ /**
+ * Return the total Formula result. If there is a Vector
+ * component to this Formula, then this is the result of the
+ * Formula if the formula is applied after summing all the
+ * components of the Vector. For example, if Formula is x/y where
+ * x is size 3, then total() will return (x[1]+x[2]+x[3])/y. If
+ * there is no Vector component, total() returns the same value as
+ * the first entry in the VResult val() returns.
+ * @return The total of the result vector.
+ */
+ Result total() const;
+
+ /**
+ * Return the number of elements in the tree.
+ */
+ size_t size() const;
+
+ /**
+ * Return true if Formula is binned. i.e. any of its children
+ * nodes are binned
+ * @return True if Formula is binned.
+ */
+ bool binned() const;
+
+ bool check() const { return true; }
+
+ /**
+ * Formulas don't need to be reset
+ */
+ void reset();
+
+ /**
+ *
+ */
+ bool zero() const;
+
+ /**
+ *
+ */
+ void update(StatData *);
+
+ std::string str() const;
+};
+
+class FormulaData : public VectorData
+{
+ public:
+ virtual std::string str() const = 0;
+ virtual bool check() const { return true; }
+};
+
+template <class Stat>
+class FormulaStatData : public FormulaData
+{
+ protected:
+ Stat &s;
+ mutable VResult vec;
+ mutable VCounter cvec;
+
+ public:
+ FormulaStatData(Stat &stat) : s(stat) {}
+
+ virtual bool binned() const { return s.binned(); }
+ virtual bool zero() const { return s.zero(); }
+ virtual void reset() { s.reset(); }
+
+ virtual size_t size() const { return s.size(); }
+ virtual const VResult &result() const
+ {
+ s.result(vec);
+ return vec;
+ }
+ virtual Result total() const { return s.total(); }
+ virtual VCounter &value() const { return cvec; }
+ virtual void visit(Visit &visitor)
+ {
+ update();
+ s.update(this);
+ visitor.visit(*this);
+ }
+ virtual std::string str() const { return s.str(); }
+};
+
+class Temp;
+class Formula
+ : public WrapVec<Formula,
+ FormulaBase,
+ FormulaStatData>
+{
+ public:
+ /**
+ * Create and initialize thie formula, and register it with the database.
+ */
+ Formula();
+
+ /**
+ * Create a formula with the given root node, register it with the
+ * database.
+ * @param r The root of the expression tree.
+ */
+ Formula(Temp r);
+
+ /**
+ * Set an unitialized Formula to the given root.
+ * @param r The root of the expression tree.
+ * @return a reference to this formula.
+ */
+ const Formula &operator=(Temp r);
+
+ /**
+ * Add the given tree to the existing one.
+ * @param r The root of the expression tree.
+ * @return a reference to this formula.
+ */
+ const Formula &operator+=(Temp r);
+};
+
+class FormulaNode : public Node
+{
+ private:
+ const Formula &formula;
+ mutable VResult vec;
+
+ public:
+ FormulaNode(const Formula &f) : formula(f) {}
+
+ virtual size_t size() const { return formula.size(); }
+ virtual const VResult &result() const { formula.result(vec); return vec; }
+ virtual Result total() const { return formula.total(); }
+ virtual bool binned() const { return formula.binned(); }
+
+ virtual std::string str() const { return formula.str(); }
+};
+
+/**
+ * Helper class to construct formula node trees.
+ */
+class Temp
+{
+ protected:
+ /**
+ * Pointer to a Node object.
+ */
+ NodePtr node;
+
+ public:
+ /**
+ * Copy the given pointer to this class.
+ * @param n A pointer to a Node object to copy.
+ */
+ Temp(NodePtr n) : node(n) { }
+
+ /**
+ * Return the node pointer.
+ * @return the node pointer.
+ */
+ operator NodePtr&() { return node;}
+
+ public:
+ /**
+ * Create a new ScalarStatNode.
+ * @param s The ScalarStat to place in a node.
+ */
+ template <class Bin>
+ Temp(const Scalar<Bin> &s)
+ : node(new ScalarStatNode(s.statData())) { }
+
+ /**
+ * Create a new ScalarStatNode.
+ * @param s The ScalarStat to place in a node.
+ */
+ Temp(const Value &s)
+ : node(new ScalarStatNode(s.statData())) { }
+
+ /**
+ * Create a new ScalarStatNode.
+ * @param s The ScalarStat to place in a node.
+ */
+ template <class Bin>
+ Temp(const Average<Bin> &s)
+ : node(new ScalarStatNode(s.statData())) { }
+
+ /**
+ * Create a new VectorStatNode.
+ * @param s The VectorStat to place in a node.
+ */
+ template <class Bin>
+ Temp(const Vector<Bin> &s)
+ : node(new VectorStatNode(s.statData())) { }
+
+ /**
+ *
+ */
+ Temp(const Formula &f)
+ : node(new FormulaNode(f)) { }
+
+ /**
+ * Create a new ScalarProxyNode.
+ * @param p The ScalarProxy to place in a node.
+ */
+ template <class Storage, class Bin>
+ Temp(const ScalarProxy<Storage, Bin> &p)
+ : node(new ScalarProxyNode<Storage, Bin>(p)) { }
+
+ /**
+ * Create a ConstNode
+ * @param value The value of the const node.
+ */
+ Temp(signed char value)
+ : node(new ConstNode<signed char>(value)) {}
+
+ /**
+ * Create a ConstNode
+ * @param value The value of the const node.
+ */
+ Temp(unsigned char value)
+ : node(new ConstNode<unsigned char>(value)) {}
+
+ /**
+ * Create a ConstNode
+ * @param value The value of the const node.
+ */
+ Temp(signed short value)
+ : node(new ConstNode<signed short>(value)) {}
+
+ /**
+ * Create a ConstNode
+ * @param value The value of the const node.
+ */
+ Temp(unsigned short value)
+ : node(new ConstNode<unsigned short>(value)) {}
+
+ /**
+ * Create a ConstNode
+ * @param value The value of the const node.
+ */
+ Temp(signed int value)
+ : node(new ConstNode<signed int>(value)) {}
+
+ /**
+ * Create a ConstNode
+ * @param value The value of the const node.
+ */
+ Temp(unsigned int value)
+ : node(new ConstNode<unsigned int>(value)) {}
+
+ /**
+ * Create a ConstNode
+ * @param value The value of the const node.
+ */
+ Temp(signed long value)
+ : node(new ConstNode<signed long>(value)) {}
+
+ /**
+ * Create a ConstNode
+ * @param value The value of the const node.
+ */
+ Temp(unsigned long value)
+ : node(new ConstNode<unsigned long>(value)) {}
+
+ /**
+ * Create a ConstNode
+ * @param value The value of the const node.
+ */
+ Temp(signed long long value)
+ : node(new ConstNode<signed long long>(value)) {}
+
+ /**
+ * Create a ConstNode
+ * @param value The value of the const node.
+ */
+ Temp(unsigned long long value)
+ : node(new ConstNode<unsigned long long>(value)) {}
+
+ /**
+ * Create a ConstNode
+ * @param value The value of the const node.
+ */
+ Temp(float value)
+ : node(new ConstNode<float>(value)) {}
+
+ /**
+ * Create a ConstNode
+ * @param value The value of the const node.
+ */
+ Temp(double value)
+ : node(new ConstNode<double>(value)) {}
+};
+
+
+/**
+ * @}
+ */
+
+void check();
+void reset();
+void registerResetCallback(Callback *cb);
+
+inline Temp
+operator+(Temp l, Temp r)
+{
+ return NodePtr(new BinaryNode<std::plus<Result> >(l, r));
+}
+
+inline Temp
+operator-(Temp l, Temp r)
+{
+ return NodePtr(new BinaryNode<std::minus<Result> >(l, r));
+}
+
+inline Temp
+operator*(Temp l, Temp r)
+{
+ return NodePtr(new BinaryNode<std::multiplies<Result> >(l, r));
+}
+
+inline Temp
+operator/(Temp l, Temp r)
+{
+ return NodePtr(new BinaryNode<std::divides<Result> >(l, r));
+}
+
+inline Temp
+operator-(Temp l)
+{
+ return NodePtr(new UnaryNode<std::negate<Result> >(l));
+}
+
+template <typename T>
+inline Temp
+constant(T val)
+{
+ return NodePtr(new ConstNode<T>(val));
+}
+
+inline Temp
+sum(Temp val)
+{
+ return NodePtr(new SumNode<std::plus<Result> >(val));
+}
+
+/* namespace Stats */ }
+
+#endif // __BASE_STATISTICS_HH__
diff --git a/src/base/stats/events.cc b/src/base/stats/events.cc
new file mode 100644
index 000000000..3191aec13
--- /dev/null
+++ b/src/base/stats/events.cc
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <vector>
+
+#include "base/stats/events.hh"
+
+#if USE_MYSQL
+#include "base/cprintf.hh"
+#include "base/misc.hh"
+#include "base/mysql.hh"
+#include "base/stats/mysql.hh"
+#include "base/stats/mysql_run.hh"
+#include "base/str.hh"
+#endif
+
+#include "base/match.hh"
+#include "sim/host.hh"
+#include "sim/sim_object.hh"
+#include "sim/root.hh"
+
+using namespace std;
+
+namespace Stats {
+
+Tick EventStart = ULL(0x7fffffffffffffff);
+
+ObjectMatch event_ignore;
+
+#if USE_MYSQL
+class InsertEvent
+{
+ private:
+ char *query;
+ int size;
+ bool first;
+ static const int maxsize = 1024*1024;
+
+ typedef map<string, uint32_t> event_map_t;
+ event_map_t events;
+
+ MySQL::Connection &mysql;
+ uint16_t run;
+
+ public:
+ InsertEvent()
+ : mysql(MySqlDB.conn()), run(MySqlDB.run())
+ {
+ query = new char[maxsize + 1];
+ size = 0;
+ first = true;
+ flush();
+ }
+ ~InsertEvent()
+ {
+ flush();
+ }
+
+ void flush();
+ void insert(const string &stat);
+};
+
+void
+InsertEvent::insert(const string &stat)
+{
+ assert(mysql.connected());
+
+ event_map_t::iterator i = events.find(stat);
+ uint32_t event;
+ if (i == events.end()) {
+ mysql.query(
+ csprintf("SELECT en_id "
+ "from event_names "
+ "where en_name=\"%s\"",
+ stat));
+
+ MySQL::Result result = mysql.store_result();
+ if (!result)
+ panic("could not get a run\n%s\n", mysql.error);
+
+ assert(result.num_fields() == 1);
+ MySQL::Row row = result.fetch_row();
+ if (row) {
+ if (!to_number(row[0], event))
+ panic("invalid event id: %s\n", row[0]);
+ } else {
+ mysql.query(
+ csprintf("INSERT INTO "
+ "event_names(en_name)"
+ "values(\"%s\")",
+ stat));
+
+ if (mysql.error)
+ panic("could not get a run\n%s\n", mysql.error);
+
+ event = mysql.insert_id();
+ }
+ } else {
+ event = (*i).second;
+ }
+
+ if (size + 1024 > maxsize)
+ flush();
+
+ if (!first) {
+ query[size++] = ',';
+ query[size] = '\0';
+ }
+
+ first = false;
+
+ size += sprintf(query + size, "(%u,%u,%llu)",
+ event, run, (unsigned long long)curTick);
+}
+
+void
+InsertEvent::flush()
+{
+ static const char query_header[] = "INSERT INTO "
+ "events(ev_event, ev_run, ev_tick)"
+ "values";
+
+ if (size) {
+ MySQL::Connection &mysql = MySqlDB.conn();
+ assert(mysql.connected());
+ mysql.query(query);
+ }
+
+ query[0] = '\0';
+ size = sizeof(query_header);
+ first = true;
+ memcpy(query, query_header, size);
+}
+
+void
+__event(const string &stat)
+{
+ static InsertEvent event;
+ event.insert(stat);
+}
+
+#endif
+
+/* namespace Stats */ }
diff --git a/src/base/stats/events.hh b/src/base/stats/events.hh
new file mode 100644
index 000000000..2a23240b4
--- /dev/null
+++ b/src/base/stats/events.hh
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_STATS_EVENTS_HH__
+#define __BASE_STATS_EVENTS_HH__
+
+#include <string>
+
+#include "base/trace.hh"
+#include "config/use_mysql.hh"
+
+namespace Stats {
+
+extern Tick EventStart;
+
+#if USE_MYSQL
+void __event(const std::string &stat);
+bool MySqlConnected();
+#endif
+
+bool ignoreEvent(const std::string &name);
+
+inline void
+recordEvent(const std::string &stat)
+{
+ if (EventStart > curTick)
+ return;
+
+ DPRINTF(StatEvents, "Statistics Event: %s\n", stat);
+
+#if USE_MYSQL
+ if (!MySqlConnected())
+ return;
+
+ __event(stat);
+#endif
+}
+
+/* namespace Stats */ }
+
+#endif // __BASE_STATS_EVENTS_HH__
diff --git a/src/base/stats/flags.hh b/src/base/stats/flags.hh
new file mode 100644
index 000000000..00db95bc1
--- /dev/null
+++ b/src/base/stats/flags.hh
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_STATS_FLAGS_HH__
+#define __BASE_STATS_FLAGS_HH__
+namespace Stats {
+
+/**
+ * Define the storage for format flags.
+ * @todo Can probably shrink this.
+ */
+typedef u_int32_t StatFlags;
+
+/** Nothing extra to print. */
+const StatFlags none = 0x00000000;
+/** This Stat is Initialized */
+const StatFlags init = 0x00000001;
+/** Print this stat. */
+const StatFlags print = 0x00000002;
+/** Print the total. */
+const StatFlags total = 0x00000010;
+/** Print the percent of the total that this entry represents. */
+const StatFlags pdf = 0x00000020;
+/** Print the cumulative percentage of total upto this entry. */
+const StatFlags cdf = 0x00000040;
+/** Print the distribution. */
+const StatFlags dist = 0x00000080;
+/** Don't print if this is zero. */
+const StatFlags nozero = 0x00000100;
+/** Don't print if this is NAN */
+const StatFlags nonan = 0x00000200;
+/** Used for SS compatability. */
+const StatFlags __substat = 0x80000000;
+
+/** Mask of flags that can't be set directly */
+const StatFlags __reserved = init | print | __substat;
+
+enum DisplayMode
+{
+ mode_m5,
+ mode_simplescalar
+};
+
+extern DisplayMode DefaultMode;
+
+/* namespace Stats */ }
+
+#endif // __BASE_STATS_FLAGS_HH__
diff --git a/src/base/stats/mysql.cc b/src/base/stats/mysql.cc
new file mode 100644
index 000000000..6d12b4fc1
--- /dev/null
+++ b/src/base/stats/mysql.cc
@@ -0,0 +1,900 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <cassert>
+#include <map>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "base/misc.hh"
+#include "base/mysql.hh"
+#include "base/statistics.hh"
+#include "base/stats/flags.hh"
+#include "base/stats/mysql.hh"
+#include "base/stats/mysql_run.hh"
+#include "base/stats/statdb.hh"
+#include "base/stats/types.hh"
+#include "base/str.hh"
+#include "sim/host.hh"
+
+using namespace std;
+
+namespace Stats {
+
+MySqlRun MySqlDB;
+
+bool
+MySqlConnected()
+{
+ return MySqlDB.connected();
+}
+
+void
+MySqlRun::connect(const string &host, const string &user, const string &passwd,
+ const string &db, const string &name, const string &sample,
+ const string &project)
+{
+ if (connected())
+ panic("can only get one database connection at this time!");
+
+ mysql.connect(host, user, passwd, db);
+ if (mysql.error)
+ panic("could not connect to database server\n%s\n", mysql.error);
+
+ if (mysql.autocommit(false))
+ panic("could not set autocommit\n%s\n", mysql.error);
+
+ remove(name);
+ //cleanup();
+ setup(name, sample, user, project);
+}
+
+void
+MySqlRun::setup(const string &name, const string &sample, const string &user,
+ const string &project)
+{
+ assert(mysql.connected());
+
+ stringstream insert;
+ ccprintf(insert,
+ "INSERT INTO "
+ "runs(rn_name,rn_sample,rn_user,rn_project,rn_date,rn_expire)"
+ "values(\"%s\", \"%s\", \"%s\", \"%s\", NOW(),"
+ "DATE_ADD(CURDATE(), INTERVAL 31 DAY))",
+ name, sample, user, project);
+
+ mysql.query(insert);
+ if (mysql.error)
+ panic("could not get a run\n%s\n", mysql.error);
+
+ run_id = mysql.insert_id();
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+}
+
+void
+MySqlRun::remove(const string &name)
+{
+ assert(mysql.connected());
+ stringstream sql;
+ ccprintf(sql, "DELETE FROM runs WHERE rn_name=\"%s\"", name);
+ mysql.query(sql);
+ if (mysql.error)
+ panic("could not delete run\n%s\n", mysql.error);
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+}
+
+void
+MySqlRun::cleanup()
+{
+ assert(mysql.connected());
+
+ mysql.query("DELETE data "
+ "FROM data "
+ "LEFT JOIN runs ON dt_run=rn_id "
+ "WHERE rn_id IS NULL");
+
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+
+ mysql.query("DELETE formula_ref "
+ "FROM formula_ref "
+ "LEFT JOIN runs ON fr_run=rn_id "
+ "WHERE rn_id IS NULL");
+
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+
+ mysql.query("DELETE formulas "
+ "FROM formulas "
+ "LEFT JOIN formula_ref ON fm_stat=fr_stat "
+ "WHERE fr_stat IS NULL");
+
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+
+ mysql.query("DELETE stats "
+ "FROM stats "
+ "LEFT JOIN data ON st_id=dt_stat "
+ "WHERE dt_stat IS NULL");
+
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+
+ mysql.query("DELETE subdata "
+ "FROM subdata "
+ "LEFT JOIN data ON sd_stat=dt_stat "
+ "WHERE dt_stat IS NULL");
+
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+
+ mysql.query("DELETE bins "
+ "FROM bins "
+ "LEFT JOIN data ON bn_id=dt_bin "
+ "WHERE dt_bin IS NULL");
+
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+
+ mysql.query("DELETE events"
+ "FROM events"
+ "LEFT JOIN runs ON ev_run=rn_id"
+ "WHERE rn_id IS NULL");
+
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+
+ mysql.query("DELETE event_names"
+ "FROM event_names"
+ "LEFT JOIN events ON en_id=ev_event"
+ "WHERE ev_event IS NULL");
+
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+}
+
+void
+SetupStat::init()
+{
+ name = "";
+ descr = "";
+ type = "";
+ print = false;
+ prereq = 0;
+ prec = -1;
+ nozero = false;
+ nonan = false;
+ total = false;
+ pdf = false;
+ cdf = false;
+ min = 0;
+ max = 0;
+ bktsize = 0;
+ size = 0;
+}
+
+unsigned
+SetupStat::setup()
+{
+ MySQL::Connection &mysql = MySqlDB.conn();
+
+ stringstream insert;
+ ccprintf(insert,
+ "INSERT INTO "
+ "stats(st_name, st_descr, st_type, st_print, st_prereq, "
+ "st_prec, st_nozero, st_nonan, st_total, st_pdf, st_cdf, "
+ "st_min, st_max, st_bktsize, st_size)"
+ "values(\"%s\",\"%s\",\"%s\","
+ " %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)",
+ name, descr, type, print, prereq, (int)prec, nozero, nonan,
+ total, pdf, cdf,
+ min, max, bktsize, size);
+
+ mysql.query(insert);
+ if (!mysql.error) {
+ int id = mysql.insert_id();
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+ return id;
+ }
+
+ stringstream select;
+ ccprintf(select, "SELECT * FROM stats WHERE st_name=\"%s\"", name);
+
+ mysql.query(select);
+ MySQL::Result result = mysql.store_result();
+ if (!result)
+ panic("could not find stat\n%s\n", mysql.error);
+
+ assert(result.num_fields() == 16);
+ MySQL::Row row = result.fetch_row();
+ if (!row)
+ panic("could not get stat row\n%s\n", mysql.error);
+
+ bool tb;
+ int8_t ti8;
+ uint16_t tu16;
+ int64_t ti64;
+ uint64_t tu64;
+
+ if (name != (char *)row[1])
+ panic("failed stat check on %s:name. %s != %s\n",
+ name, name, row[1]);
+
+ if (descr != (char *)row[2])
+ panic("failed stat check on %s:descr. %s != %s\n",
+ name, descr, row[2]);
+
+ if (type != (char *)row[3])
+ panic("failed stat check on %s:type. %s != %s\n",
+ name, type, row[3]);
+
+ if (!to_number(row[4], tb) || print != tb)
+ panic("failed stat check on %s:print. %d != %d\n",
+ name, print, tb);
+
+ if (!to_number(row[6], ti8) || prec != ti8)
+ panic("failed stat check on %s:prec. %d != %d\n",
+ name, prec, ti8);
+
+ if (!to_number(row[7], tb) || nozero != tb)
+ panic("failed stat check on %s:nozero. %d != %d\n",
+ name, nozero, tb);
+
+ if (!to_number(row[8], tb) || nonan != tb)
+ panic("failed stat check on %s:nonan. %d != %d\n",
+ name, nonan, tb);
+
+ if (!to_number(row[9], tb) || total != tb)
+ panic("failed stat check on %s:total. %d != %d\n",
+ name, total, tb);
+
+ if (!to_number(row[10], tb) || pdf != tb)
+ panic("failed stat check on %s:pdf. %d != %d\n",
+ name, pdf, tb);
+
+ if (!to_number(row[11], tb) || cdf != tb)
+ panic("failed stat check on %s:cdf. %d != %d\n",
+ name, cdf, tb);
+
+ if (!to_number(row[12], ti64) || min != ti64)
+ panic("failed stat check on %s:min. %d != %d\n",
+ name, min, ti64);
+
+ if (!to_number(row[13], ti64) || max != ti64)
+ panic("failed stat check on %s:max. %d != %d\n",
+ name, max, ti64);
+
+ if (!to_number(row[14], tu64) || bktsize != tu64)
+ panic("failed stat check on %s:bktsize. %d != %d\n",
+ name, bktsize, tu64);
+
+ if (!to_number(row[15], tu16) || size != tu16)
+ panic("failed stat check on %s:size. %d != %d\n",
+ name, size, tu16);
+
+ to_number(row[5], prereq);
+ uint16_t statid;
+ to_number(row[0], statid);
+ return statid;
+}
+
+unsigned
+SetupBin(const string &bin)
+{
+ static map<string, int> binmap;
+
+ using namespace MySQL;
+ map<string,int>::const_iterator i = binmap.find(bin);
+ if (i != binmap.end())
+ return (*i).second;
+
+ Connection &mysql = MySqlDB.conn();
+ assert(mysql.connected());
+
+ uint16_t bin_id;
+
+ stringstream select;
+ stringstream insert;
+ ccprintf(select, "SELECT bn_id FROM bins WHERE bn_name=\"%s\"", bin);
+
+ mysql.query(select);
+ MySQL::Result result = mysql.store_result();
+ if (result) {
+ assert(result.num_fields() == 1);
+ MySQL::Row row = result.fetch_row();
+ if (row) {
+ to_number(row[0], bin_id);
+ goto exit;
+ }
+ }
+
+ ccprintf(insert, "INSERT INTO bins(bn_name) values(\"%s\")", bin);
+
+ mysql.query(insert);
+ if (mysql.error)
+ panic("could not get a bin\n%s\n", mysql.error);
+
+ bin_id = mysql.insert_id();
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+
+ binmap.insert(make_pair(bin, bin_id));
+
+ exit:
+ return bin_id;
+}
+
+InsertData::InsertData()
+{
+ query = new char[maxsize + 1];
+ size = 0;
+ flush();
+}
+
+InsertData::~InsertData()
+{
+ delete [] query;
+}
+
+void
+InsertData::flush()
+{
+ if (size) {
+ MySQL::Connection &mysql = MySqlDB.conn();
+ assert(mysql.connected());
+ mysql.query(query);
+ if (mysql.error)
+ panic("could not insert data\n%s\n", mysql.error);
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+ }
+
+ query[0] = '\0';
+ size = 0;
+ first = true;
+ strcpy(query, "INSERT INTO "
+ "data(dt_stat,dt_x,dt_y,dt_run,dt_tick,dt_bin,dt_data) "
+ "values");
+ size = strlen(query);
+}
+
+void
+InsertData::insert()
+{
+ if (size + 1024 > maxsize)
+ flush();
+
+ if (!first) {
+ query[size++] = ',';
+ query[size] = '\0';
+ }
+
+ first = false;
+
+ size += sprintf(query + size, "(%u,%d,%d,%u,%llu,%u,\"%f\")",
+ stat, x, y, MySqlDB.run(), (unsigned long long)tick,
+ bin, data);
+}
+
+struct InsertSubData
+{
+ uint16_t stat;
+ int16_t x;
+ int16_t y;
+ string name;
+ string descr;
+
+ void setup();
+};
+
+void
+InsertSubData::setup()
+{
+ MySQL::Connection &mysql = MySqlDB.conn();
+ assert(mysql.connected());
+ stringstream insert;
+ ccprintf(insert,
+ "INSERT INTO subdata(sd_stat,sd_x,sd_y,sd_name,sd_descr) "
+ "values(%d,%d,%d,\"%s\",\"%s\")",
+ stat, x, y, name, descr);
+
+ mysql.query(insert);
+// if (mysql.error)
+// panic("could not insert subdata\n%s\n", mysql.error);
+
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+}
+
+void
+InsertFormula(uint16_t stat, const string &formula)
+{
+ MySQL::Connection &mysql = MySqlDB.conn();
+ assert(mysql.connected());
+ stringstream insert_formula;
+ ccprintf(insert_formula,
+ "INSERT INTO formulas(fm_stat,fm_formula) values(%d, \"%s\")",
+ stat, formula);
+
+ mysql.query(insert_formula);
+// if (mysql.error)
+// panic("could not insert formula\n%s\n", mysql.error);
+
+ stringstream insert_ref;
+ ccprintf(insert_ref,
+ "INSERT INTO formula_ref(fr_stat,fr_run) values(%d, %d)",
+ stat, MySqlDB.run());
+
+ mysql.query(insert_ref);
+// if (mysql.error)
+// panic("could not insert formula reference\n%s\n", mysql.error);
+
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+}
+
+void
+UpdatePrereq(uint16_t stat, uint16_t prereq)
+{
+ MySQL::Connection &mysql = MySqlDB.conn();
+ assert(mysql.connected());
+ stringstream update;
+ ccprintf(update, "UPDATE stats SET st_prereq=%d WHERE st_id=%d",
+ prereq, stat);
+ mysql.query(update);
+ if (mysql.error)
+ panic("could not update prereq\n%s\n", mysql.error);
+
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+}
+
+void
+MySql::configure()
+{
+ /*
+ * set up all stats!
+ */
+ using namespace Database;
+
+ MySQL::Connection &mysql = MySqlDB.conn();
+
+ stat_list_t::const_iterator i, end = stats().end();
+ for (i = stats().begin(); i != end; ++i) {
+ (*i)->visit(*this);
+ }
+
+ for (i = stats().begin(); i != end; ++i) {
+ StatData *data = *i;
+ if (data->prereq) {
+ uint16_t stat_id = find(data->id);
+ uint16_t prereq_id = find(data->prereq->id);
+ assert(stat_id && prereq_id);
+
+ UpdatePrereq(stat_id, prereq_id);
+ }
+ }
+
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+
+ configured = true;
+}
+
+
+bool
+MySql::configure(const StatData &data, string type)
+{
+ stat.init();
+ stat.name = data.name;
+ stat.descr = data.desc;
+ stat.type = type;
+ stat.print = data.flags & print;
+ stat.prec = data.precision;
+ stat.nozero = data.flags & nozero;
+ stat.nonan = data.flags & nonan;
+ stat.total = data.flags & total;
+ stat.pdf = data.flags & pdf;
+ stat.cdf = data.flags & cdf;
+
+ return stat.print;
+}
+
+void
+MySql::configure(const ScalarData &data)
+{
+ if (!configure(data, "SCALAR"))
+ return;
+
+ insert(data.id, stat.setup());
+}
+
+void
+MySql::configure(const VectorData &data)
+{
+ if (!configure(data, "VECTOR"))
+ return;
+
+ uint16_t statid = stat.setup();
+
+ if (!data.subnames.empty()) {
+ InsertSubData subdata;
+ subdata.stat = statid;
+ subdata.y = 0;
+ for (int i = 0; i < data.subnames.size(); ++i) {
+ subdata.x = i;
+ subdata.name = data.subnames[i];
+ subdata.descr = data.subdescs.empty() ? "" : data.subdescs[i];
+
+ if (!subdata.name.empty() || !subdata.descr.empty())
+ subdata.setup();
+ }
+ }
+
+ insert(data.id, statid);
+}
+
+void
+MySql::configure(const DistData &data)
+{
+ if (!configure(data, "DIST"))
+ return;
+
+ if (!data.data.fancy) {
+ stat.size = data.data.size;
+ stat.min = data.data.min;
+ stat.max = data.data.max;
+ stat.bktsize = data.data.bucket_size;
+ }
+ insert(data.id, stat.setup());
+}
+
+void
+MySql::configure(const VectorDistData &data)
+{
+ if (!configure(data, "VECTORDIST"))
+ return;
+
+ if (!data.data[0].fancy) {
+ stat.size = data.data[0].size;
+ stat.min = data.data[0].min;
+ stat.max = data.data[0].max;
+ stat.bktsize = data.data[0].bucket_size;
+ }
+
+ uint16_t statid = stat.setup();
+
+ if (!data.subnames.empty()) {
+ InsertSubData subdata;
+ subdata.stat = statid;
+ subdata.y = 0;
+ for (int i = 0; i < data.subnames.size(); ++i) {
+ subdata.x = i;
+ subdata.name = data.subnames[i];
+ subdata.descr = data.subdescs.empty() ? "" : data.subdescs[i];
+ if (!subdata.name.empty() || !subdata.descr.empty())
+ subdata.setup();
+ }
+ }
+
+ insert(data.id, statid);
+}
+
+void
+MySql::configure(const Vector2dData &data)
+{
+ if (!configure(data, "VECTOR2D"))
+ return;
+
+ uint16_t statid = stat.setup();
+
+ if (!data.subnames.empty()) {
+ InsertSubData subdata;
+ subdata.stat = statid;
+ subdata.y = -1;
+ for (int i = 0; i < data.subnames.size(); ++i) {
+ subdata.x = i;
+ subdata.name = data.subnames[i];
+ subdata.descr = data.subdescs.empty() ? "" : data.subdescs[i];
+ if (!subdata.name.empty() || !subdata.descr.empty())
+ subdata.setup();
+ }
+ }
+
+ if (!data.y_subnames.empty()) {
+ InsertSubData subdata;
+ subdata.stat = statid;
+ subdata.x = -1;
+ subdata.descr = "";
+ for (int i = 0; i < data.y_subnames.size(); ++i) {
+ subdata.y = i;
+ subdata.name = data.y_subnames[i];
+ if (!subdata.name.empty())
+ subdata.setup();
+ }
+ }
+
+ insert(data.id, statid);
+}
+
+void
+MySql::configure(const FormulaData &data)
+{
+ configure(data, "FORMULA");
+ insert(data.id, stat.setup());
+ InsertFormula(find(data.id), data.str());
+}
+
+void
+MySql::output(MainBin *bin)
+{
+ MySQL::Connection &mysql = MySqlDB.conn();
+
+ if (bin) {
+ bin->activate();
+ newdata.bin = SetupBin(bin->name());
+ } else {
+ newdata.bin = 0;
+ }
+
+ Database::stat_list_t::const_iterator i, end = Database::stats().end();
+ for (i = Database::stats().begin(); i != end; ++i) {
+ StatData *stat = *i;
+ if (bin && stat->binned() || !bin && !stat->binned()) {
+ stat->visit(*this);
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
+ }
+ }
+}
+
+bool
+MySql::valid() const
+{
+ return MySqlDB.connected();
+}
+
+void
+MySql::output()
+{
+ using namespace Database;
+ assert(valid());
+
+ if (!configured)
+ configure();
+
+ // store sample #
+ newdata.tick = curTick;
+
+ output(NULL);
+ if (!bins().empty()) {
+ bin_list_t::iterator i, end = bins().end();
+ for (i = bins().begin(); i != end; ++i)
+ output(*i);
+ }
+
+ newdata.flush();
+}
+
+void
+MySql::output(const ScalarData &data)
+{
+ if (!(data.flags & print))
+ return;
+
+ newdata.stat = find(data.id);
+ newdata.x = 0;
+ newdata.y = 0;
+ newdata.data = data.value();
+
+ newdata.insert();
+}
+
+void
+MySql::output(const VectorData &data)
+{
+ if (!(data.flags & print))
+ return;
+
+ newdata.stat = find(data.id);
+ newdata.y = 0;
+
+ const VCounter &cvec = data.value();
+ int size = data.size();
+ for (int x = 0; x < size; x++) {
+ newdata.x = x;
+ newdata.data = cvec[x];
+ newdata.insert();
+ }
+}
+
+void
+MySql::output(const DistDataData &data)
+{
+ const int db_sum = -1;
+ const int db_squares = -2;
+ const int db_samples = -3;
+ const int db_min_val = -4;
+ const int db_max_val = -5;
+ const int db_underflow = -6;
+ const int db_overflow = -7;
+
+ newdata.x = db_sum;
+ newdata.data = data.sum;
+ newdata.insert();
+
+ newdata.x = db_squares;
+ newdata.data = data.squares;
+ newdata.insert();
+
+ newdata.x = db_samples;
+ newdata.data = data.samples;
+ newdata.insert();
+
+ if (data.samples && !data.fancy) {
+ newdata.x = db_min_val;
+ newdata.data = data.min_val;
+ newdata.insert();
+
+ newdata.x = db_max_val;
+ newdata.data = data.max_val;
+ newdata.insert();
+
+ newdata.x = db_underflow;
+ newdata.data = data.underflow;
+ newdata.insert();
+
+ newdata.x = db_overflow;
+ newdata.data = data.overflow;
+ newdata.insert();
+
+ int size = data.cvec.size();
+ for (int x = 0; x < size; x++) {
+ newdata.x = x;
+ newdata.data = data.cvec[x];
+ newdata.insert();
+ }
+ }
+}
+
+
+void
+MySql::output(const DistData &data)
+{
+ if (!(data.flags & print))
+ return;
+
+ newdata.stat = find(data.id);
+ newdata.y = 0;
+ output(data.data);
+}
+
+void
+MySql::output(const VectorDistData &data)
+{
+ if (!(data.flags & print))
+ return;
+
+ newdata.stat = find(data.id);
+
+ int size = data.data.size();
+ for (int y = 0; y < size; ++y) {
+ newdata.y = y;
+ output(data.data[y]);
+ }
+}
+
+void
+MySql::output(const Vector2dData &data)
+{
+ if (!(data.flags & print))
+ return;
+
+ newdata.stat = find(data.id);
+
+ int index = 0;
+ for (int x = 0; x < data.x; x++) {
+ newdata.x = x;
+ for (int y = 0; y < data.y; y++) {
+ newdata.y = y;
+ newdata.data = data.cvec[index++];
+ newdata.insert();
+ }
+ }
+}
+
+void
+MySql::output(const FormulaData &data)
+{
+}
+
+/*
+ * Implement the visitor
+ */
+void
+MySql::visit(const ScalarData &data)
+{
+ if (!configured)
+ configure(data);
+ else
+ output(data);
+}
+
+void
+MySql::visit(const VectorData &data)
+{
+ if (!configured)
+ configure(data);
+ else
+ output(data);
+}
+
+void
+MySql::visit(const DistData &data)
+{
+ return;
+ if (!configured)
+ configure(data);
+ else
+ output(data);
+}
+
+void
+MySql::visit(const VectorDistData &data)
+{
+ return;
+ if (!configured)
+ configure(data);
+ else
+ output(data);
+}
+
+void
+MySql::visit(const Vector2dData &data)
+{
+ return;
+ if (!configured)
+ configure(data);
+ else
+ output(data);
+}
+
+void
+MySql::visit(const FormulaData &data)
+{
+ if (!configured)
+ configure(data);
+ else
+ output(data);
+}
+
+/* namespace Stats */ }
diff --git a/src/base/stats/mysql.hh b/src/base/stats/mysql.hh
new file mode 100644
index 000000000..25ea22b97
--- /dev/null
+++ b/src/base/stats/mysql.hh
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_STATS_MYSQL_HH__
+#define __BASE_STATS_MYSQL_HH__
+
+#include <map>
+#include <string>
+
+#include "base/stats/output.hh"
+
+namespace MySQL { class Connection; }
+namespace Stats {
+
+class MainBin;
+class DistDataData;
+class MySqlRun;
+bool MySqlConnected();
+extern MySqlRun MySqlDB;
+
+struct SetupStat
+{
+ std::string name;
+ std::string descr;
+ std::string type;
+ bool print;
+ uint16_t prereq;
+ int8_t prec;
+ bool nozero;
+ bool nonan;
+ bool total;
+ bool pdf;
+ bool cdf;
+ double min;
+ double max;
+ double bktsize;
+ uint16_t size;
+
+ void init();
+ unsigned setup();
+};
+
+class InsertData
+{
+ private:
+ char *query;
+ int size;
+ bool first;
+ static const int maxsize = 1024*1024;
+
+ public:
+ MySqlRun *run;
+
+ public:
+ uint64_t tick;
+ double data;
+ uint16_t stat;
+ uint16_t bin;
+ int16_t x;
+ int16_t y;
+
+ public:
+ InsertData();
+ ~InsertData();
+
+ void flush();
+ void insert();
+};
+
+class MySql : public Output
+{
+ protected:
+ SetupStat stat;
+ InsertData newdata;
+ std::list<FormulaData *> formulas;
+ bool configured;
+
+ protected:
+ std::map<int, int> idmap;
+
+ void insert(int sim_id, int db_id)
+ {
+ using namespace std;
+ idmap.insert(make_pair(sim_id, db_id));
+ }
+
+ int find(int sim_id)
+ {
+ using namespace std;
+ map<int,int>::const_iterator i = idmap.find(sim_id);
+ assert(i != idmap.end());
+ return (*i).second;
+ }
+ public:
+ // Implement Visit
+ virtual void visit(const ScalarData &data);
+ virtual void visit(const VectorData &data);
+ virtual void visit(const DistData &data);
+ virtual void visit(const VectorDistData &data);
+ virtual void visit(const Vector2dData &data);
+ virtual void visit(const FormulaData &data);
+
+ // Implement Output
+ virtual bool valid() const;
+ virtual void output();
+
+ protected:
+ // Output helper
+ void output(MainBin *bin);
+ void output(const DistDataData &data);
+ void output(const ScalarData &data);
+ void output(const VectorData &data);
+ void output(const DistData &data);
+ void output(const VectorDistData &data);
+ void output(const Vector2dData &data);
+ void output(const FormulaData &data);
+
+ void configure();
+ bool configure(const StatData &data, std::string type);
+ void configure(const ScalarData &data);
+ void configure(const VectorData &data);
+ void configure(const DistData &data);
+ void configure(const VectorDistData &data);
+ void configure(const Vector2dData &data);
+ void configure(const FormulaData &data);
+};
+
+/* namespace Stats */ }
+
+#endif // __BASE_STATS_MYSQL_HH__
diff --git a/src/base/stats/mysql_run.hh b/src/base/stats/mysql_run.hh
new file mode 100644
index 000000000..d8dcb7594
--- /dev/null
+++ b/src/base/stats/mysql_run.hh
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_STATS_MYSQL_RUN_HH__
+#define __BASE_STATS_MYSQL_RUN_HH__
+
+#include <string>
+
+#include "base/mysql.hh"
+#include "sim/host.hh"
+
+namespace Stats {
+
+struct MySqlRun
+{
+ private:
+ MySQL::Connection mysql;
+ uint16_t run_id;
+
+ protected:
+ void setup(const std::string &name, const std::string &sample,
+ const std::string &user, const std::string &project);
+
+ void remove(const std::string &name);
+ void cleanup();
+
+ public:
+ bool connected() const { return mysql.connected(); }
+ void connect(const std::string &host, const std::string &user,
+ const std::string &passwd, const std::string &db,
+ const std::string &name, const std::string &sample,
+ const std::string &project);
+
+ MySQL::Connection &conn() { return mysql; }
+ uint16_t run() const { return run_id; }
+};
+
+/* namespace Stats */ }
+
+#endif // __BASE_STATS_MYSQL_RUN_HH__
diff --git a/src/base/stats/output.hh b/src/base/stats/output.hh
new file mode 100644
index 000000000..ee6b38d63
--- /dev/null
+++ b/src/base/stats/output.hh
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_STATS_OUTPUT_HH__
+#define __BASE_STATS_OUTPUT_HH__
+
+#include <string>
+
+#include "base/stats/visit.hh"
+
+namespace Stats {
+
+struct Output : public Visit
+{
+ inline void operator()() { output(); }
+ virtual void output() = 0;
+ virtual bool valid() const = 0;
+};
+
+/* namespace Stats */ }
+
+#endif // __BASE_STATS_OUTPUT_HH__
diff --git a/src/base/stats/statdb.cc b/src/base/stats/statdb.cc
new file mode 100644
index 000000000..a6b00ab8a
--- /dev/null
+++ b/src/base/stats/statdb.cc
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "base/misc.hh"
+#include "base/trace.hh"
+#include "base/statistics.hh"
+#include "base/stats/bin.hh"
+#include "base/stats/statdb.hh"
+
+using namespace std;
+
+namespace Stats {
+namespace Database {
+
+StatData *
+find(void *stat)
+{
+ stat_map_t::const_iterator i = map().find(stat);
+
+ if (i == map().end())
+ return NULL;
+
+ return (*i).second;
+}
+
+void
+regBin(MainBin *bin, const std::string &_name)
+{
+ bin_list_t::iterator i, end = bins().end();
+ for (i = bins().begin(); i != end; ++i)
+ if ((*i)->name() == _name)
+ panic("re-registering bin %s", _name);
+ bins().push_back(bin);
+ DPRINTF(Stats, "registering %s\n", _name);
+}
+
+void
+regStat(void *stat, StatData *data)
+{
+ if (map().find(stat) != map().end())
+ panic("shouldn't register stat twice!");
+
+ stats().push_back(data);
+
+#ifndef NDEBUG
+ pair<stat_map_t::iterator, bool> result =
+#endif
+ map().insert(make_pair(stat, data));
+ assert(result.second && "this should never fail");
+ assert(map().find(stat) != map().end());
+}
+
+void
+regPrint(void *stat)
+{
+ StatData *data = find(stat);
+ assert(data);
+ data->flags |= print;
+}
+
+TheDatabase &db()
+{
+ static TheDatabase db;
+ return db;
+}
+
+/* namespace Database */ }
+/* namespace Stats */ }
diff --git a/src/base/stats/statdb.hh b/src/base/stats/statdb.hh
new file mode 100644
index 000000000..eb56d8fac
--- /dev/null
+++ b/src/base/stats/statdb.hh
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_STATS_STATDB_HH__
+#define __BASE_STATS_STATDB_HH__
+
+#include <iosfwd>
+#include <list>
+#include <map>
+#include <string>
+
+class Python;
+
+namespace Stats {
+
+class MainBin;
+class StatData;
+
+namespace Database {
+
+typedef std::map<void *, StatData *> stat_map_t;
+typedef std::list<StatData *> stat_list_t;
+typedef std::list<MainBin *> bin_list_t;
+
+// We wrap the database in a struct to make sure it is built in time.
+struct TheDatabase
+{
+ stat_map_t map;
+ stat_list_t stats;
+ bin_list_t bins;
+
+};
+
+TheDatabase &db();
+inline stat_map_t &map() { return db().map; }
+inline stat_list_t &stats() { return db().stats; }
+inline bin_list_t &bins() { return db().bins; }
+
+StatData *find(void *stat);
+void regBin(MainBin *bin, const std::string &name);
+void regStat(void *stat, StatData *data);
+void regPrint(void *stat);
+
+inline std::string name() { return "Statistics Database"; }
+
+/* namespace Database */ }
+/* namespace Stats */ }
+
+#endif // __BASE_STATS_STATDB_HH__
diff --git a/src/base/stats/text.cc b/src/base/stats/text.cc
new file mode 100644
index 000000000..300737c60
--- /dev/null
+++ b/src/base/stats/text.cc
@@ -0,0 +1,736 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(__APPLE__)
+#define _GLIBCPP_USE_C99 1
+#endif
+
+#include <iostream>
+#include <sstream>
+#include <fstream>
+#include <string>
+
+#include "base/misc.hh"
+#include "base/statistics.hh"
+#include "base/stats/statdb.hh"
+#include "base/stats/text.hh"
+#include "base/stats/visit.hh"
+
+using namespace std;
+
+#ifndef NAN
+float __nan();
+/** Define Not a number. */
+#define NAN (__nan())
+/** Need to define __nan() */
+#define __M5_NAN
+#endif
+
+#ifdef __M5_NAN
+float
+__nan()
+{
+ union {
+ uint32_t ui;
+ float f;
+ } nan;
+
+ nan.ui = 0x7fc00000;
+ return nan.f;
+}
+#endif
+
+namespace Stats {
+
+Text::Text()
+ : mystream(false), stream(NULL), compat(false), descriptions(false)
+{
+}
+
+Text::Text(std::ostream &stream)
+ : mystream(false), stream(NULL), compat(false), descriptions(false)
+{
+ open(stream);
+}
+
+Text::Text(const std::string &file)
+ : mystream(false), stream(NULL), compat(false), descriptions(false)
+{
+ open(file);
+}
+
+
+Text::~Text()
+{
+ if (mystream) {
+ assert(stream);
+ delete stream;
+ }
+}
+
+void
+Text::open(std::ostream &_stream)
+{
+ if (stream)
+ panic("stream already set!");
+
+ mystream = false;
+ stream = &_stream;
+ assert(valid());
+}
+
+void
+Text::open(const std::string &file)
+{
+ if (stream)
+ panic("stream already set!");
+
+ mystream = true;
+ stream = new ofstream(file.c_str(), ios::trunc);
+ assert(valid());
+}
+
+bool
+Text::valid() const
+{
+ return stream != NULL;
+}
+
+void
+Text::output()
+{
+ using namespace Database;
+
+ ccprintf(*stream, "\n---------- Begin Simulation Statistics ----------\n");
+ if (bins().empty() || bins().size() == 1) {
+ stat_list_t::const_iterator i, end = stats().end();
+ for (i = stats().begin(); i != end; ++i)
+ (*i)->visit(*this);
+ } else {
+ ccprintf(*stream, "PRINTING BINNED STATS\n");
+ bin_list_t::iterator i, end = bins().end();
+ for (i = bins().begin(); i != end; ++i) {
+ MainBin *bin = *i;
+ bin->activate();
+ ccprintf(*stream,"---%s Bin------------\n", bin->name());
+ stat_list_t::const_iterator i, end = stats().end();
+ for (i = stats().begin(); i != end; ++i)
+ (*i)->visit(*this);
+ ccprintf(*stream, "---------------------------------\n");
+ }
+ }
+ ccprintf(*stream, "\n---------- End Simulation Statistics ----------\n");
+ stream->flush();
+}
+
+bool
+Text::noOutput(const StatData &data)
+{
+ if (!(data.flags & print))
+ return true;
+
+ if (data.prereq && data.prereq->zero())
+ return true;
+
+ return false;
+}
+
+string
+ValueToString(Result value, int precision, bool compat)
+{
+ stringstream val;
+
+ if (!isnan(value)) {
+ if (precision != -1)
+ val.precision(precision);
+ else if (value == rint(value))
+ val.precision(0);
+
+ val.unsetf(ios::showpoint);
+ val.setf(ios::fixed);
+ val << value;
+ } else {
+ val << (compat ? "<err: div-0>" : "no value");
+ }
+
+ return val.str();
+}
+
+struct ScalarPrint
+{
+ Result value;
+ string name;
+ string desc;
+ StatFlags flags;
+ bool compat;
+ bool descriptions;
+ int precision;
+ Result pdf;
+ Result cdf;
+
+ void operator()(ostream &stream) const;
+};
+
+void
+ScalarPrint::operator()(ostream &stream) const
+{
+ if (flags & nozero && value == 0.0 ||
+ flags & nonan && isnan(value))
+ return;
+
+ stringstream pdfstr, cdfstr;
+
+ if (!isnan(pdf))
+ ccprintf(pdfstr, "%.2f%%", pdf * 100.0);
+
+ if (!isnan(cdf))
+ ccprintf(cdfstr, "%.2f%%", cdf * 100.0);
+
+ if (compat && flags & __substat) {
+ ccprintf(stream, "%32s %12s %10s %10s", name,
+ ValueToString(value, precision, compat), pdfstr, cdfstr);
+ } else {
+ ccprintf(stream, "%-40s %12s %10s %10s", name,
+ ValueToString(value, precision, compat), pdfstr, cdfstr);
+ }
+
+ if (descriptions) {
+ if (!desc.empty())
+ ccprintf(stream, " # %s", desc);
+ }
+ stream << endl;
+}
+
+struct VectorPrint
+{
+ string name;
+ string desc;
+ vector<string> subnames;
+ vector<string> subdescs;
+ StatFlags flags;
+ bool compat;
+ bool descriptions;
+ int precision;
+ VResult vec;
+ Result total;
+
+ void operator()(ostream &stream) const;
+};
+
+void
+VectorPrint::operator()(std::ostream &stream) const
+{
+ int _size = vec.size();
+ Result _total = 0.0;
+
+ if (flags & (pdf | cdf)) {
+ for (int i = 0; i < _size; ++i) {
+ _total += vec[i];
+ }
+ }
+
+ string base = name + (compat ? "_" : "::");
+
+ ScalarPrint print;
+ print.name = name;
+ print.desc = desc;
+ print.precision = precision;
+ print.descriptions = descriptions;
+ print.flags = flags;
+ print.pdf = NAN;
+ print.cdf = NAN;
+
+ bool havesub = !subnames.empty();
+
+ if (_size == 1) {
+ print.value = vec[0];
+ print(stream);
+ } else if (!compat) {
+ for (int i = 0; i < _size; ++i) {
+ if (havesub && (i >= subnames.size() || subnames[i].empty()))
+ continue;
+
+ print.name = base + (havesub ? subnames[i] : to_string(i));
+ print.desc = subdescs.empty() ? desc : subdescs[i];
+ print.value = vec[i];
+
+ if (_total && (flags & pdf)) {
+ print.pdf = vec[i] / _total;
+ print.cdf += print.pdf;
+ }
+
+ print(stream);
+ }
+
+ if (flags & ::Stats::total) {
+ print.name = base + "total";
+ print.desc = desc;
+ print.value = total;
+ print(stream);
+ }
+ } else {
+ if (flags & ::Stats::total) {
+ print.value = total;
+ print(stream);
+ }
+
+ Result _pdf = 0.0;
+ Result _cdf = 0.0;
+ if (flags & dist) {
+ ccprintf(stream, "%s.start_dist\n", name);
+ for (int i = 0; i < _size; ++i) {
+ print.name = havesub ? subnames[i] : to_string(i);
+ print.desc = subdescs.empty() ? desc : subdescs[i];
+ print.flags |= __substat;
+ print.value = vec[i];
+
+ if (_total) {
+ _pdf = vec[i] / _total;
+ _cdf += _pdf;
+ }
+
+ if (flags & pdf)
+ print.pdf = _pdf;
+ if (flags & cdf)
+ print.cdf = _cdf;
+
+ print(stream);
+ }
+ ccprintf(stream, "%s.end_dist\n", name);
+ } else {
+ for (int i = 0; i < _size; ++i) {
+ if (havesub && subnames[i].empty())
+ continue;
+
+ print.name = base;
+ print.name += havesub ? subnames[i] : to_string(i);
+ print.desc = subdescs.empty() ? desc : subdescs[i];
+ print.value = vec[i];
+
+ if (_total) {
+ _pdf = vec[i] / _total;
+ _cdf += _pdf;
+ } else {
+ _pdf = _cdf = NAN;
+ }
+
+ if (flags & pdf) {
+ print.pdf = _pdf;
+ print.cdf = _cdf;
+ }
+
+ print(stream);
+ }
+ }
+ }
+}
+
+struct DistPrint
+{
+ string name;
+ string desc;
+ StatFlags flags;
+ bool compat;
+ bool descriptions;
+ int precision;
+
+ Result min_val;
+ Result max_val;
+ Result underflow;
+ Result overflow;
+ VResult vec;
+ Result sum;
+ Result squares;
+ Result samples;
+
+ Counter min;
+ Counter max;
+ Counter bucket_size;
+ int size;
+ bool fancy;
+
+ void operator()(ostream &stream) const;
+};
+
+void
+DistPrint::operator()(ostream &stream) const
+{
+ if (fancy) {
+ ScalarPrint print;
+ string base = name + (compat ? "_" : "::");
+
+ print.precision = precision;
+ print.flags = flags;
+ print.compat = compat;
+ print.descriptions = descriptions;
+ print.desc = desc;
+ print.pdf = NAN;
+ print.cdf = NAN;
+
+ print.name = base + "mean";
+ print.value = samples ? sum / samples : NAN;
+ print(stream);
+
+ print.name = base + "stdev";
+ print.value = samples ? sqrt((samples * squares - sum * sum) /
+ (samples * (samples - 1.0))) : NAN;
+ print(stream);
+
+ print.name = "**Ignore: " + base + "TOT";
+ print.value = samples;
+ print(stream);
+ return;
+ }
+
+ assert(size == vec.size());
+
+ Result total = 0.0;
+
+ total += underflow;
+ for (int i = 0; i < size; ++i)
+ total += vec[i];
+ total += overflow;
+
+ string base = name + (compat ? "." : "::");
+
+ ScalarPrint print;
+ print.desc = compat ? "" : desc;
+ print.flags = flags;
+ print.compat = compat;
+ print.descriptions = descriptions;
+ print.precision = precision;
+ print.pdf = NAN;
+ print.cdf = NAN;
+
+ if (compat) {
+ ccprintf(stream, "%-42s", base + "start_dist");
+ if (descriptions && !desc.empty())
+ ccprintf(stream, " # %s", desc);
+ stream << endl;
+ }
+
+ print.name = base + "samples";
+ print.value = samples;
+ print(stream);
+
+ print.name = base + "min_value";
+ print.value = min_val;
+ print(stream);
+
+ if (!compat || underflow > 0.0) {
+ print.name = base + "underflows";
+ print.value = underflow;
+ if (!compat && total) {
+ print.pdf = underflow / total;
+ print.cdf += print.pdf;
+ }
+ print(stream);
+ }
+
+
+ if (!compat) {
+ for (int i = 0; i < size; ++i) {
+ stringstream namestr;
+ namestr << name;
+
+ Counter low = i * bucket_size + min;
+ Counter high = ::min(low + bucket_size, max);
+ namestr << low;
+ if (low < high)
+ namestr << "-" << high;
+
+ print.name = namestr.str();
+ print.value = vec[i];
+ if (total) {
+ print.pdf = vec[i] / total;
+ print.cdf += print.pdf;
+ }
+ print(stream);
+ }
+
+ } else {
+ Counter _min;
+ Result _pdf;
+ Result _cdf = 0.0;
+
+ print.flags = flags | __substat;
+
+ for (int i = 0; i < size; ++i) {
+ if (flags & nozero && vec[i] == 0.0 ||
+ flags & nonan && isnan(vec[i]))
+ continue;
+
+ _min = i * bucket_size + min;
+ _pdf = vec[i] / total * 100.0;
+ _cdf += _pdf;
+
+
+ print.name = ValueToString(_min, 0, compat);
+ print.value = vec[i];
+ print.pdf = (flags & pdf) ? _pdf : NAN;
+ print.cdf = (flags & cdf) ? _cdf : NAN;
+ print(stream);
+ }
+
+ print.flags = flags;
+ }
+
+ if (!compat || overflow > 0.0) {
+ print.name = base + "overflows";
+ print.value = overflow;
+ if (!compat && total) {
+ print.pdf = overflow / total;
+ print.cdf += print.pdf;
+ } else {
+ print.pdf = NAN;
+ print.cdf = NAN;
+ }
+ print(stream);
+ }
+
+ print.pdf = NAN;
+ print.cdf = NAN;
+
+ if (!compat) {
+ print.name = base + "total";
+ print.value = total;
+ print(stream);
+ }
+
+ print.name = base + "max_value";
+ print.value = max_val;
+ print(stream);
+
+ if (!compat && samples != 0) {
+ print.name = base + "mean";
+ print.value = sum / samples;
+ print(stream);
+
+ print.name = base + "stdev";
+ print.value = sqrt((samples * squares - sum * sum) /
+ (samples * (samples - 1.0)));
+ print(stream);
+ }
+
+ if (compat)
+ ccprintf(stream, "%send_dist\n\n", base);
+}
+
+void
+Text::visit(const ScalarData &data)
+{
+ if (noOutput(data))
+ return;
+
+ ScalarPrint print;
+ print.value = data.result();
+ print.name = data.name;
+ print.desc = data.desc;
+ print.flags = data.flags;
+ print.compat = compat;
+ print.descriptions = descriptions;
+ print.precision = data.precision;
+ print.pdf = NAN;
+ print.cdf = NAN;
+
+ print(*stream);
+}
+
+void
+Text::visit(const VectorData &data)
+{
+ if (noOutput(data))
+ return;
+
+ int size = data.size();
+ VectorPrint print;
+
+ print.name = data.name;
+ print.desc = data.desc;
+ print.flags = data.flags;
+ print.compat = compat;
+ print.descriptions = descriptions;
+ print.precision = data.precision;
+ print.vec = data.result();
+ print.total = data.total();
+
+ if (!data.subnames.empty()) {
+ for (int i = 0; i < size; ++i) {
+ if (!data.subnames[i].empty()) {
+ print.subnames = data.subnames;
+ print.subnames.resize(size);
+ for (int i = 0; i < size; ++i) {
+ if (!data.subnames[i].empty() &&
+ !data.subdescs[i].empty()) {
+ print.subdescs = data.subdescs;
+ print.subdescs.resize(size);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ print(*stream);
+}
+
+void
+Text::visit(const Vector2dData &data)
+{
+ if (noOutput(data))
+ return;
+
+ bool havesub = false;
+ VectorPrint print;
+
+ print.subnames = data.y_subnames;
+ print.flags = data.flags;
+ print.compat = compat;
+ print.descriptions = descriptions;
+ print.precision = data.precision;
+
+ if (!data.subnames.empty()) {
+ for (int i = 0; i < data.x; ++i)
+ if (!data.subnames[i].empty())
+ havesub = true;
+ }
+
+ VResult tot_vec(data.y);
+ Result super_total = 0.0;
+ for (int i = 0; i < data.x; ++i) {
+ if (havesub && (i >= data.subnames.size() || data.subnames[i].empty()))
+ continue;
+
+ int iy = i * data.y;
+ VResult yvec(data.y);
+
+ Result total = 0.0;
+ for (int j = 0; j < data.y; ++j) {
+ yvec[j] = data.cvec[iy + j];
+ tot_vec[j] += yvec[j];
+ total += yvec[j];
+ super_total += yvec[j];
+ }
+
+ print.name = data.name + "_" + (havesub ? data.subnames[i] : to_string(i));
+ print.desc = data.desc;
+ print.vec = yvec;
+ print.total = total;
+ print(*stream);
+ }
+
+ if ((data.flags & ::Stats::total) && (data.x > 1)) {
+ print.name = data.name;
+ print.desc = data.desc;
+ print.vec = tot_vec;
+ print.total = super_total;
+ print(*stream);
+ }
+}
+
+void
+Text::visit(const DistData &data)
+{
+ if (noOutput(data))
+ return;
+
+ DistPrint print;
+
+ print.name = data.name;
+ print.desc = data.desc;
+ print.flags = data.flags;
+ print.compat = compat;
+ print.descriptions = descriptions;
+ print.precision = data.precision;
+
+ print.min_val = data.data.min_val;
+ print.max_val = data.data.max_val;
+ print.underflow = data.data.underflow;
+ print.overflow = data.data.overflow;
+ print.vec.resize(data.data.cvec.size());
+ for (int i = 0; i < print.vec.size(); ++i)
+ print.vec[i] = (Result)data.data.cvec[i];
+ print.sum = data.data.sum;
+ print.squares = data.data.squares;
+ print.samples = data.data.samples;
+
+ print.min = data.data.min;
+ print.max = data.data.max;
+ print.bucket_size = data.data.bucket_size;
+ print.size = data.data.size;
+ print.fancy = data.data.fancy;
+
+ print(*stream);
+}
+
+void
+Text::visit(const VectorDistData &data)
+{
+ if (noOutput(data))
+ return;
+
+ for (int i = 0; i < data.size(); ++i) {
+ DistPrint print;
+
+ print.name = data.name +
+ (data.subnames[i].empty() ? ("_" + to_string(i)) : data.subnames[i]);
+ print.desc = data.subdescs[i].empty() ? data.desc : data.subdescs[i];
+ print.flags = data.flags;
+ print.compat = compat;
+ print.descriptions = descriptions;
+ print.precision = data.precision;
+
+ print.min_val = data.data[i].min_val;
+ print.max_val = data.data[i].max_val;
+ print.underflow = data.data[i].underflow;
+ print.overflow = data.data[i].overflow;
+ print.vec.resize(data.data[i].cvec.size());
+ for (int j = 0; j < print.vec.size(); ++j)
+ print.vec[j] = (Result)data.data[i].cvec[j];
+ print.sum = data.data[i].sum;
+ print.squares = data.data[i].squares;
+ print.samples = data.data[i].samples;
+
+ print.min = data.data[i].min;
+ print.max = data.data[i].max;
+ print.bucket_size = data.data[i].bucket_size;
+ print.size = data.data[i].size;
+ print.fancy = data.data[i].fancy;
+
+ print(*stream);
+ }
+}
+
+void
+Text::visit(const FormulaData &data)
+{
+ visit((const VectorData &)data);
+}
+
+/* namespace Stats */ }
diff --git a/src/base/stats/text.hh b/src/base/stats/text.hh
new file mode 100644
index 000000000..125cb79fa
--- /dev/null
+++ b/src/base/stats/text.hh
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_STATS_TEXT_HH__
+#define __BASE_STATS_TEXT_HH__
+
+#include <iosfwd>
+#include <string>
+
+#include "base/stats/output.hh"
+
+namespace Stats {
+
+class Text : public Output
+{
+ protected:
+ bool mystream;
+ std::ostream *stream;
+
+ protected:
+ bool noOutput(const StatData &data);
+ void binout();
+
+ public:
+ bool compat;
+ bool descriptions;
+
+ public:
+ Text();
+ Text(std::ostream &stream);
+ Text(const std::string &file);
+ ~Text();
+
+ void open(std::ostream &stream);
+ void open(const std::string &file);
+
+ // Implement Visit
+ virtual void visit(const ScalarData &data);
+ virtual void visit(const VectorData &data);
+ virtual void visit(const DistData &data);
+ virtual void visit(const VectorDistData &data);
+ virtual void visit(const Vector2dData &data);
+ virtual void visit(const FormulaData &data);
+
+ // Implement Output
+ virtual bool valid() const;
+ virtual void output();
+};
+
+/* namespace Stats */ }
+
+#endif // __BASE_STATS_TEXT_HH__
diff --git a/src/base/stats/types.hh b/src/base/stats/types.hh
new file mode 100644
index 000000000..57f1564a5
--- /dev/null
+++ b/src/base/stats/types.hh
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_STATS_TYPES_HH__
+#define __BASE_STATS_TYPES_HH__
+
+#include <vector>
+#include "sim/host.hh"
+
+namespace Stats {
+
+/** All counters are of 64-bit values. */
+typedef double Counter;
+/** vector of counters. */
+typedef std::vector<Counter> VCounter;
+
+/** All results are doubles. */
+typedef double Result;
+/** vector of results. */
+typedef std::vector<Result> VResult;
+
+/* namespace Stats */ }
+
+#endif // __BASE_STATS_TYPES_HH__
diff --git a/src/base/stats/visit.cc b/src/base/stats/visit.cc
new file mode 100644
index 000000000..dd4d49502
--- /dev/null
+++ b/src/base/stats/visit.cc
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "base/stats/visit.hh"
+
+namespace Stats {
+namespace Detail {
+
+Visit::Visit()
+{}
+
+Visit::~Visit()
+{}
+
+/* namespace Detail */ }
+/* namespace Stats */ }
diff --git a/src/base/stats/visit.hh b/src/base/stats/visit.hh
new file mode 100644
index 000000000..c0593c670
--- /dev/null
+++ b/src/base/stats/visit.hh
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_STATS_VISIT_HH__
+#define __BASE_STATS_VISIT_HH__
+
+#include <string>
+
+#include "base/time.hh"
+#include "sim/host.hh"
+
+namespace Stats {
+
+class StatData;
+class ScalarData;
+class VectorData;
+class DistDataData;
+class DistData;
+class VectorDistData;
+class Vector2dData;
+class FormulaData;
+
+struct Visit
+{
+ Visit();
+ virtual ~Visit();
+
+ virtual void visit(const ScalarData &data) = 0;
+ virtual void visit(const VectorData &data) = 0;
+ virtual void visit(const DistData &data) = 0;
+ virtual void visit(const VectorDistData &data) = 0;
+ virtual void visit(const Vector2dData &data) = 0;
+ virtual void visit(const FormulaData &data) = 0;
+};
+
+/* namespace Stats */ }
+
+#endif // __BASE_STATS_VISIT_HH__
diff --git a/src/base/str.cc b/src/base/str.cc
new file mode 100644
index 000000000..5f7f50286
--- /dev/null
+++ b/src/base/str.cc
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <ctype.h>
+
+#include <cstring>
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include "base/intmath.hh"
+#include "base/str.hh"
+
+using namespace std;
+
+bool
+split_first(const string &s, string &lhs, string &rhs, char c)
+{
+ string::size_type offset = s.find(c);
+ if (offset == string::npos) {
+ lhs = s;
+ rhs = "";
+ return false;
+ }
+
+ lhs = s.substr(0, offset);
+ rhs = s.substr(offset + 1);
+ return true;
+}
+
+bool
+split_last(const string &s, string &lhs, string &rhs, char c)
+{
+ string::size_type offset = s.rfind(c);
+ if (offset == string::npos) {
+ lhs = s;
+ rhs = "";
+ return false;
+ }
+
+ lhs = s.substr(0, offset);
+ rhs = s.substr(offset + 1);
+ return true;
+}
+
+void
+tokenize(vector<string>& v, const string &s, char token, bool ignore)
+{
+ string::size_type first = 0;
+ string::size_type last = s.find_first_of(token);
+
+ if (s.empty())
+ return;
+
+ if (ignore && last == first) {
+ while (last == first)
+ last = s.find_first_of(token, ++first);
+
+ if (last == string::npos) {
+ if (first != s.size())
+ v.push_back(s.substr(first));
+ return;
+ }
+ }
+
+ while (last != string::npos) {
+ v.push_back(s.substr(first, last - first));
+
+ if (ignore) {
+ first = s.find_first_not_of(token, last + 1);
+
+ if (first == string::npos)
+ return;
+ } else
+ first = last + 1;
+
+ last = s.find_first_of(token, first);
+ }
+
+ v.push_back(s.substr(first));
+}
+
+/**
+ * @todo This function will not handle the smallest negative decimal
+ * value for a signed type
+ */
+
+template <class T>
+inline bool
+__to_number(string value, T &retval)
+{
+ static const T maxnum = ((T)-1);
+ static const bool sign = maxnum < 0;
+ static const int bits = sizeof(T) * 8;
+ static const T hexmax = maxnum & (((T)1 << (bits - 4 - sign)) - 1);
+ static const T octmax = maxnum & (((T)1 << (bits - 3 - sign)) - 1);
+ static const T signmax =
+ (sign) ? maxnum & (((T)1 << (bits - 1)) - 1) : maxnum;
+ static const T decmax = signmax / 10;
+
+#if 0
+ cout << "maxnum = 0x" << hex << (unsigned long long)maxnum << "\n"
+ << "sign = 0x" << hex << (unsigned long long)sign << "\n"
+ << "hexmax = 0x" << hex << (unsigned long long)hexmax << "\n"
+ << "octmax = 0x" << hex << (unsigned long long)octmax << "\n"
+ << "signmax = 0x" << hex << (unsigned long long)signmax << "\n"
+ << "decmax = 0x" << hex << (unsigned long long)decmax << "\n";
+#endif
+
+ eat_white(value);
+
+ bool negative = false;
+ bool hex = false;
+ bool oct = false;
+ int last = value.size() - 1;
+ retval = 0;
+ int i = 0;
+
+ char c = value[i];
+ if (!isDec(c)) {
+ if (c == '-' && sign)
+ negative = true;
+ else
+ return false;
+ }
+ else {
+ retval += c - '0';
+ if (last == 0) return true;
+ }
+
+ if (c == '0')
+ oct = true;
+
+ c = value[++i];
+ if (oct) {
+ if (sign && negative)
+ return false;
+
+ if (!isOct(c)) {
+ if (c == 'X' || c == 'x') {
+ hex = true;
+ oct = false;
+ } else
+ return false;
+ }
+ else
+ retval += c - '0';
+ } else if (!isDec(c))
+ goto multiply;
+ else {
+ if (sign && negative && c == '0')
+ return false;
+
+ retval *= 10;
+ retval += c - '0';
+ if (last == 1) {
+ if (sign && negative) retval = -retval;
+ return true;
+ }
+ }
+
+ if (hex) {
+ if (last == 1)
+ return false;
+
+ for (i = 2; i <= last ; i++) {
+ c = value[i];
+ if (!isHex(c))
+ return false;
+
+ if (retval > hexmax) return false;
+ retval *= 16;
+ retval += hex2Int(c);
+ }
+ return true;
+ } else if (oct) {
+ for (i = 2; i <= last ; i++) {
+ c = value[i];
+ if (!isOct(c))
+ return false;
+
+ if (retval > octmax) return false;
+ retval *= 8;
+ retval += (c - '0');
+ }
+ return true;
+ }
+
+ for (i = 2; i < last ; i++) {
+ c = value[i];
+ if (!isDec(c))
+ goto multiply;
+
+ if (retval > decmax) return false;
+ bool atmax = retval == decmax;
+ retval *= 10;
+ retval += c - '0';
+ if (atmax && retval < decmax) return false;
+ if (sign && (retval & ((T)1 << (sizeof(T) * 8 - 1))))
+ return false;
+ }
+
+ c = value[last];
+ if (isDec(c)) {
+
+ if (retval > decmax) return false;
+ bool atmax = retval == decmax;
+ retval *= 10;
+ retval += c - '0';
+ if (atmax && retval < decmax) return false;
+ if (sign && negative) {
+ if ((retval & ((T)1 << (sizeof(T) * 8 - 1))) &&
+ retval >= (T)-signmax)
+ return false;
+ retval = -retval;
+ }
+ else
+ if (sign && (retval & ((T)1 << ((sizeof(T) * 8) - 1))))
+ return false;
+ return true;
+ }
+
+ multiply:
+ signed long long mult = 1;
+ T val;
+ switch (c) {
+ case 'k':
+ case 'K':
+ if (i != last) return false;
+ mult = 1024;
+ val = signmax / mult;
+ break;
+ case 'm':
+ case 'M':
+ if (i != last) return false;
+ mult = 1024 * 1024;
+ val = signmax / mult;
+ break;
+ case 'g':
+ case 'G':
+ if (i != last) return false;
+ mult = 1024 * 1024 * 1024;
+ val = signmax / mult;
+ break;
+ case 'e':
+ case 'E':
+ if (i >= last) return false;
+
+ mult = 0;
+ for (i++; i <= last; i++) {
+ c = value[i];
+ if (!isDec(c))
+ return false;
+
+ mult *= 10;
+ mult += c - '0';
+ }
+
+ for (i = 0; i < mult; i++) {
+ if (retval > signmax / 10)
+ return false;
+ retval *= 10;
+ if (sign && (retval & ((T)1 << (sizeof(T) * 8 - 1))))
+ return false;
+ }
+ if (sign && negative) {
+ if ((retval & ((T)1 << (sizeof(T) * 8 - 1))) &&
+ retval >= (T)-signmax)
+ return false;
+ retval = -retval;
+ }
+ else
+ if (sign && (retval & ((T)1 << ((sizeof(T) * 8) - 1))))
+ return false;
+
+ return true;
+
+ default:
+ return false;
+ }
+
+ if (sign && negative)
+ return false;
+
+ if (mult > (unsigned long long)signmax)
+ return false;
+
+ if (retval > val)
+ return false;
+
+ retval *= mult;
+
+ return true;
+}
+
+#define STN(type) \
+template<> \
+bool to_number<type>(const string &value, type &retval) \
+{ return __to_number(value, retval); }
+
+STN(unsigned long long);
+STN(signed long long);
+STN(unsigned long);
+STN(signed long);
+STN(unsigned int);
+STN(signed int);
+STN(unsigned short);
+STN(signed short);
+STN(unsigned char);
+STN(signed char);
+
+template<>
+bool to_number<bool>(const string &value, bool &retval)
+{
+ string lowered = to_lower(value);
+
+ if (value == "0") {
+ retval = false;
+ return true;
+ }
+
+ if (value == "1"){
+ retval = true;
+ return true;
+ }
+
+ if (lowered == "false") {
+ retval = false;
+ return true;
+ }
+
+ if (lowered == "true"){
+ retval = true;
+ return true;
+ }
+
+ if (lowered == "no") {
+ retval = false;
+ return true;
+ }
+
+ if (lowered == "yes"){
+ retval = true;
+ return true;
+ }
+
+ return false;
+}
diff --git a/src/base/str.hh b/src/base/str.hh
new file mode 100644
index 000000000..79e33a1be
--- /dev/null
+++ b/src/base/str.hh
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __STR_HH__
+#define __STR_HH__
+
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <ctype.h>
+
+template<class> class Hash;
+template<>
+class Hash<std::string> {
+public:
+ unsigned operator()(const std::string &s) {
+ std::string::const_iterator i = s.begin();
+ std::string::const_iterator end = s.end();
+ unsigned hash = 5381;
+
+ while (i < end)
+ hash = ((hash << 5) + hash) + *i++;
+
+ return hash;
+ }
+};
+
+inline void
+eat_lead_white(std::string &s)
+{
+ std::string::size_type off = s.find_first_not_of(' ');
+ if (off != std::string::npos) {
+ std::string::iterator begin = s.begin();
+ s.erase(begin, begin + off);
+ }
+}
+
+inline void
+eat_end_white(std::string &s)
+{
+ std::string::size_type off = s.find_last_not_of(' ');
+ if (off != std::string::npos)
+ s.erase(s.begin() + off + 1, s.end());
+}
+
+inline void
+eat_white(std::string &s)
+{
+ eat_lead_white(s);
+ eat_end_white(s);
+}
+
+inline std::string
+to_lower(const std::string &s)
+{
+ std::string lower;
+ int len = s.size();
+
+ lower.reserve(len);
+
+ for (int i = 0; i < len; ++i)
+ lower.push_back(tolower(s[i]));
+
+ return lower;
+}
+
+// Split the string s into lhs and rhs on the first occurence of the
+// character c.
+bool
+split_first(const std::string &s, std::string &lhs, std::string &rhs, char c);
+
+// Split the string s into lhs and rhs on the last occurence of the
+// character c.
+bool
+split_last(const std::string &s, std::string &lhs, std::string &rhs, char c);
+
+// Tokenize the string <s> splitting on the character <token>, and
+// place the result in the string vector <vector>. If <ign> is true,
+// then empty result strings (due to trailing tokens, or consecutive
+// tokens) are skipped.
+void
+tokenize(std::vector<std::string> &vector, const std::string &s,
+ char token, bool ign = true);
+
+template <class T> bool
+to_number(const std::string &value, T &retval);
+
+template <class T>
+inline std::string
+to_string(const T &value)
+{
+ std::stringstream str;
+ str << value;
+ return str.str();
+}
+
+// Put quotes around string arg if it contains spaces.
+inline std::string
+quote(const std::string &s)
+{
+ std::string ret;
+ bool quote = s.find(' ') != std::string::npos;
+
+ if (quote)
+ ret = '"';
+
+ ret += s;
+
+ if (quote)
+ ret += '"';
+
+ return ret;
+}
+
+#endif //__STR_HH__
diff --git a/src/base/time.cc b/src/base/time.cc
new file mode 100644
index 000000000..5827c9a85
--- /dev/null
+++ b/src/base/time.cc
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+#include <iostream>
+#include <string>
+
+#include "base/time.hh"
+
+using namespace std;
+
+struct _timeval
+{
+ timeval tv;
+};
+
+double
+convert(const timeval &tv)
+{
+ return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
+}
+
+Time::Time(bool set_now)
+{
+ time = new _timeval;
+ if (set_now)
+ set();
+}
+
+Time::Time(const timeval &val)
+{
+ time = new _timeval;
+ set(val);
+}
+
+Time::Time(const Time &val)
+{
+ time = new _timeval;
+ set(val.get());
+}
+
+Time::~Time()
+{
+ delete time;
+}
+
+const timeval &
+Time::get() const
+{
+ return time->tv;
+}
+
+void
+Time::set()
+{
+ ::gettimeofday(&time->tv, NULL);
+}
+
+void
+Time::set(const timeval &tv)
+{
+ memcpy(&time->tv, &tv, sizeof(timeval));
+}
+
+double
+Time::operator()() const
+{
+ return convert(get());
+}
+
+string
+Time::date(string format) const
+{
+ const timeval &tv = get();
+ time_t sec = tv.tv_sec;
+ char buf[256];
+
+ if (format.empty()) {
+ ctime_r(&sec, buf);
+ buf[24] = '\0';
+ return buf;
+ }
+
+ struct tm *tm = localtime(&sec);
+ strftime(buf, sizeof(buf), format.c_str(), tm);
+ return buf;
+}
+
+ostream &
+operator<<(ostream &out, const Time &start)
+{
+ out << start.date();
+ return out;
+}
+
+Time
+operator-(const Time &l, const Time &r)
+{
+ timeval tv;
+ timersub(&l.get(), &r.get(), &tv);
+ return tv;
+}
+
+const Time Time::start(true);
diff --git a/src/base/time.hh b/src/base/time.hh
new file mode 100644
index 000000000..5731e3029
--- /dev/null
+++ b/src/base/time.hh
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SIM_TIME_HH__
+#define __SIM_TIME_HH__
+
+#include <sys/time.h>
+
+#include <iosfwd>
+#include <string>
+
+struct _timeval;
+
+class Time
+{
+ protected:
+ mutable _timeval *time;
+
+ public:
+ explicit Time(bool set_now = false);
+ Time(const timeval &val);
+ Time(const Time &val);
+ ~Time();
+
+ void set();
+ const timeval &get() const;
+ void set(const timeval &val);
+
+ double operator()() const;
+ std::string date(std::string format = "") const;
+
+ public:
+ static const Time start;
+};
+
+Time operator-(const Time &l, const Time &r);
+
+std::ostream &operator<<(std::ostream &out, const Time &time);
+
+#endif // __SIM_TIME_HH__
diff --git a/src/base/timebuf.hh b/src/base/timebuf.hh
new file mode 100644
index 000000000..f6b5b2781
--- /dev/null
+++ b/src/base/timebuf.hh
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_TIMEBUF_HH__
+#define __BASE_TIMEBUF_HH__
+
+#include <vector>
+
+template <class T>
+class TimeBuffer
+{
+ protected:
+ int past;
+ int future;
+ int size;
+
+ char *data;
+ std::vector<char *> index;
+ int base;
+
+ void valid(int idx)
+ {
+ assert (idx >= -past && idx <= future);
+ }
+
+ public:
+ friend class wire;
+ class wire
+ {
+ friend class TimeBuffer;
+ protected:
+ TimeBuffer<T> *buffer;
+ int index;
+
+ void set(int idx)
+ {
+ buffer->valid(idx);
+ index = idx;
+ }
+
+ wire(TimeBuffer<T> *buf, int i)
+ : buffer(buf), index(i)
+ { }
+
+ public:
+ wire()
+ { }
+
+ wire(const wire &i)
+ : buffer(i.buffer), index(i.index)
+ { }
+
+ const wire &operator=(const wire &i)
+ {
+ buffer = i.buffer;
+ set(i.index);
+ return *this;
+ }
+
+ const wire &operator=(int idx)
+ {
+ set(idx);
+ return *this;
+ }
+
+ const wire &operator+=(int offset)
+ {
+ set(index + offset);
+ return *this;
+ }
+
+ const wire &operator-=(int offset)
+ {
+ set(index - offset);
+ return *this;
+ }
+
+ wire &operator++()
+ {
+ set(index + 1);
+ return *this;
+ }
+
+ wire &operator++(int)
+ {
+ int i = index;
+ set(index + 1);
+ return wire(this, i);
+ }
+
+ wire &operator--()
+ {
+ set(index - 1);
+ return *this;
+ }
+
+ wire &operator--(int)
+ {
+ int i = index;
+ set(index - 1);
+ return wire(this, i);
+ }
+ T &operator*() const { return *buffer->access(index); }
+ T *operator->() const { return buffer->access(index); }
+ };
+
+
+ public:
+ TimeBuffer(int p, int f)
+ : past(p), future(f), size(past + future + 1),
+ data(new char[size * sizeof(T)]), index(size), base(0)
+ {
+ assert(past >= 0 && future >= 0);
+ char *ptr = data;
+ for (int i = 0; i < size; i++) {
+ index[i] = ptr;
+ memset(ptr, 0, sizeof(T));
+ new (ptr) T;
+ ptr += sizeof(T);
+ }
+ }
+
+ TimeBuffer()
+ : data(NULL)
+ {
+ }
+
+ ~TimeBuffer()
+ {
+ for (int i = 0; i < size; ++i)
+ (reinterpret_cast<T *>(index[i]))->~T();
+ delete [] data;
+ }
+
+ void
+ advance()
+ {
+ if (++base >= size)
+ base = 0;
+
+ int ptr = base + future;
+ if (ptr >= size)
+ ptr -= size;
+ (reinterpret_cast<T *>(index[ptr]))->~T();
+ memset(index[ptr], 0, sizeof(T));
+ new (index[ptr]) T;
+ }
+
+ T *access(int idx)
+ {
+ //Need more complex math here to calculate index.
+ valid(idx);
+
+ int vector_index = idx + base;
+ if (vector_index >= size) {
+ vector_index -= size;
+ } else if (vector_index < 0) {
+ vector_index += size;
+ }
+
+ return reinterpret_cast<T *>(index[vector_index]);
+ }
+
+ T &operator[](int idx)
+ {
+ //Need more complex math here to calculate index.
+ valid(idx);
+
+ int vector_index = idx + base;
+ if (vector_index >= size) {
+ vector_index -= size;
+ } else if (vector_index < 0) {
+ vector_index += size;
+ }
+
+ return reinterpret_cast<T &>(*index[vector_index]);
+ }
+
+ wire getWire(int idx)
+ {
+ valid(idx);
+
+ return wire(this, idx);
+ }
+
+ wire zero()
+ {
+ return wire(this, 0);
+ }
+};
+
+#endif // __BASE_TIMEBUF_HH__
+
diff --git a/src/base/trace.cc b/src/base/trace.cc
new file mode 100644
index 000000000..90db7f045
--- /dev/null
+++ b/src/base/trace.cc
@@ -0,0 +1,350 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <ctype.h>
+#include <fstream>
+#include <iostream>
+#include <list>
+#include <string>
+#include <vector>
+
+#include "base/misc.hh"
+#include "base/trace.hh"
+#include "base/str.hh"
+
+using namespace std;
+
+namespace Trace {
+const string DefaultName("global");
+FlagVec flags(NumFlags, false);
+
+//
+// This variable holds the output stream for debug information. Other
+// than setting up/redirecting this stream, do *NOT* reference this
+// directly; use DebugOut() (see below) to access this stream for
+// output.
+//
+ostream *dprintf_stream = &cerr;
+
+ObjectMatch ignore;
+
+Log theLog;
+
+Log::Log()
+{
+ size = 0;
+ buffer = NULL;
+}
+
+
+void
+Log::init(int _size)
+{
+ if (buffer != NULL) {
+ fatal("Trace::Log::init called twice!");
+ }
+
+ size = _size;
+
+ buffer = new Record *[size];
+
+ for (int i = 0; i < size; ++i) {
+ buffer[i] = NULL;
+ }
+
+ nextRecPtr = &buffer[0];
+ wrapRecPtr = &buffer[size];
+}
+
+
+Log::~Log()
+{
+ for (int i = 0; i < size; ++i) {
+ delete buffer[i];
+ }
+
+ delete [] buffer;
+}
+
+
+void
+Log::append(Record *rec)
+{
+ // dump record to output stream if there's one open
+ if (dprintf_stream != NULL) {
+ rec->dump(*dprintf_stream);
+ } else {
+ rec->dump(cout);
+ }
+
+ // no buffering: justget rid of it now
+ if (buffer == NULL) {
+ delete rec;
+ return;
+ }
+
+ Record *oldRec = *nextRecPtr;
+
+ if (oldRec != NULL) {
+ // log has wrapped: overwrite
+ delete oldRec;
+ }
+
+ *nextRecPtr = rec;
+
+ if (++nextRecPtr == wrapRecPtr) {
+ nextRecPtr = &buffer[0];
+ }
+}
+
+
+void
+Log::dump(ostream &os)
+{
+ if (buffer == NULL) {
+ return;
+ }
+
+ Record **bufPtr = nextRecPtr;
+
+ if (*bufPtr == NULL) {
+ // next record slot is empty: log must not be full yet.
+ // start dumping from beginning of buffer
+ bufPtr = buffer;
+ }
+
+ do {
+ Record *rec = *bufPtr;
+
+ rec->dump(os);
+
+ if (++bufPtr == wrapRecPtr) {
+ bufPtr = &buffer[0];
+ }
+ } while (bufPtr != nextRecPtr);
+}
+
+PrintfRecord::~PrintfRecord()
+{
+ delete &args;
+}
+
+void
+PrintfRecord::dump(ostream &os)
+{
+ string fmt = "";
+
+ if (!name.empty()) {
+ fmt = "%s: " + fmt;
+ args.prepend(name);
+ }
+
+ if (cycle != (Tick)-1) {
+ fmt = "%7d: " + fmt;
+ args.prepend(cycle);
+ }
+
+ fmt += format;
+
+ args.dump(os, fmt);
+ os.flush();
+}
+
+DataRecord::DataRecord(Tick _cycle, const string &_name,
+ const void *_data, int _len)
+ : Record(_cycle), name(_name), len(_len)
+{
+ data = new uint8_t[len];
+ memcpy(data, _data, len);
+}
+
+DataRecord::~DataRecord()
+{
+ delete [] data;
+}
+
+void
+DataRecord::dump(ostream &os)
+{
+ int c, i, j;
+
+ for (i = 0; i < len; i += 16) {
+ ccprintf(os, "%d: %s: %08x ", cycle, name, i);
+ c = len - i;
+ if (c > 16) c = 16;
+
+ for (j = 0; j < c; j++) {
+ ccprintf(os, "%02x ", data[i + j] & 0xff);
+ if ((j & 0xf) == 7 && j > 0)
+ ccprintf(os, " ");
+ }
+
+ for (; j < 16; j++)
+ ccprintf(os, " ");
+ ccprintf(os, " ");
+
+ for (j = 0; j < c; j++) {
+ int ch = data[i + j] & 0x7f;
+ ccprintf(os,
+ "%c", (char)(isprint(ch) ? ch : ' '));
+ }
+
+ ccprintf(os, "\n");
+
+ if (c < 16)
+ break;
+ }
+}
+} // namespace Trace
+
+//
+// Returns the current output stream for debug information. As a
+// wrapper around Trace::dprintf_stream, this handles cases where debug
+// information is generated in the process of parsing .ini options,
+// before we process the option that sets up the debug output stream
+// itself.
+//
+std::ostream &
+DebugOut()
+{
+ return *Trace::dprintf_stream;
+}
+
+/////////////////////////////////////////////
+//
+// C-linkage functions for invoking from gdb
+//
+/////////////////////////////////////////////
+
+//
+// Dump trace buffer to specified file (cout if NULL)
+//
+extern "C"
+void
+dumpTrace(const char *filename)
+{
+ if (filename != NULL) {
+ ofstream out(filename);
+ Trace::theLog.dump(out);
+ out.close();
+ }
+ else {
+ Trace::theLog.dump(cout);
+ }
+}
+
+
+//
+// Turn on/off trace output to cerr. Typically used when trace output
+// is only going to circular buffer, but you want to see what's being
+// sent there as you step through some code in gdb. This uses the
+// same facility as the "trace to file" feature, and will print error
+// messages rather than clobbering an existing ostream pointer.
+//
+extern "C"
+void
+echoTrace(bool on)
+{
+ if (on) {
+ if (Trace::dprintf_stream != NULL) {
+ cerr << "Already echoing trace to a file... go do a 'tail -f'"
+ << " on that file instead." << endl;
+ } else {
+ Trace::dprintf_stream = &cerr;
+ }
+ } else {
+ if (Trace::dprintf_stream != &cerr) {
+ cerr << "Not echoing trace to cerr." << endl;
+ } else {
+ Trace::dprintf_stream = NULL;
+ }
+ }
+}
+
+extern "C"
+void
+printTraceFlags()
+{
+ using namespace Trace;
+ for (int i = 0; i < numFlagStrings; ++i)
+ if (flags[i])
+ cprintf("%s\n", flagStrings[i]);
+}
+
+void
+tweakTraceFlag(const char *string, bool value)
+{
+ using namespace Trace;
+ std::string str(string);
+
+ for (int i = 0; i < numFlagStrings; ++i) {
+ if (str != flagStrings[i])
+ continue;
+
+ int idx = i;
+
+ if (idx < NumFlags) {
+ flags[idx] = value;
+ } else {
+ idx -= NumFlags;
+ if (idx >= NumCompoundFlags) {
+ ccprintf(cerr, "Invalid compound flag");
+ return;
+ }
+
+ const Flags *flagVec = compoundFlags[idx];
+
+ for (int j = 0; flagVec[j] != -1; ++j) {
+ if (flagVec[j] >= NumFlags) {
+ ccprintf(cerr, "Invalid compound flag");
+ return;
+ }
+ flags[flagVec[j]] = value;
+ }
+ }
+
+ cprintf("flag %s was %s\n", string, value ? "set" : "cleared");
+ return;
+ }
+
+ cprintf("could not find flag %s\n", string);
+}
+
+extern "C"
+void
+setTraceFlag(const char *string)
+{
+ tweakTraceFlag(string, true);
+}
+
+extern "C"
+void
+clearTraceFlag(const char *string)
+{
+ tweakTraceFlag(string, false);
+}
diff --git a/src/base/trace.hh b/src/base/trace.hh
new file mode 100644
index 000000000..5e14f1bff
--- /dev/null
+++ b/src/base/trace.hh
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_TRACE_HH__
+#define __BASE_TRACE_HH__
+
+#include <vector>
+
+#include "base/cprintf.hh"
+#include "base/match.hh"
+#include "sim/host.hh"
+#include "sim/root.hh"
+
+#ifndef TRACING_ON
+#ifndef NDEBUG
+#define TRACING_ON 1
+#else
+#define TRACING_ON 0
+#endif
+#endif
+
+#include "base/traceflags.hh"
+
+namespace Trace {
+
+ typedef std::vector<bool> FlagVec;
+
+ extern FlagVec flags;
+
+#if TRACING_ON
+ const bool On = true;
+#else
+ const bool On = false;
+#endif
+
+ inline bool
+ IsOn(int t)
+ {
+ return flags[t];
+
+ }
+
+ void dump(const uint8_t *data, int count);
+
+ class Record
+ {
+ protected:
+ Tick cycle;
+
+ Record(Tick _cycle)
+ : cycle(_cycle)
+ {
+ }
+
+ public:
+ virtual ~Record() {}
+
+ virtual void dump(std::ostream &) = 0;
+ };
+
+ class PrintfRecord : public Record
+ {
+ private:
+ const char *format;
+ const std::string &name;
+ cp::ArgList &args;
+
+ public:
+ PrintfRecord(const char *_format, cp::ArgList &_args,
+ Tick cycle, const std::string &_name)
+ : Record(cycle), format(_format), name(_name), args(_args)
+ {
+ }
+
+ virtual ~PrintfRecord();
+
+ virtual void dump(std::ostream &);
+ };
+
+ class DataRecord : public Record
+ {
+ private:
+ const std::string &name;
+ uint8_t *data;
+ int len;
+
+ public:
+ DataRecord(Tick cycle, const std::string &name,
+ const void *_data, int _len);
+ virtual ~DataRecord();
+
+ virtual void dump(std::ostream &);
+ };
+
+ class Log
+ {
+ private:
+ int size; // number of records in log
+ Record **buffer; // array of 'size' Record ptrs (circular buf)
+ Record **nextRecPtr; // next slot to use in buffer
+ Record **wrapRecPtr; // &buffer[size], for quick wrap check
+
+ public:
+
+ Log();
+ ~Log();
+
+ void init(int _size);
+
+ void append(Record *); // append trace record to log
+ void dump(std::ostream &); // dump contents to stream
+ };
+
+ extern Log theLog;
+
+ extern ObjectMatch ignore;
+
+ inline void
+ dprintf(const char *format, cp::ArgList &args, Tick cycle,
+ const std::string &name)
+ {
+ if (name.empty() || !ignore.match(name))
+ theLog.append(new Trace::PrintfRecord(format, args, cycle, name));
+ }
+
+ inline void
+ dataDump(Tick cycle, const std::string &name, const void *data, int len)
+ {
+ theLog.append(new Trace::DataRecord(cycle, name, data, len));
+ }
+
+ extern const std::string DefaultName;
+};
+
+// This silly little class allows us to wrap a string in a functor
+// object so that we can give a name() that DPRINTF will like
+struct StringWrap
+{
+ std::string str;
+ StringWrap(const std::string &s) : str(s) {}
+ const std::string &operator()() const { return str; }
+};
+
+inline const std::string &name() { return Trace::DefaultName; }
+std::ostream &DebugOut();
+
+//
+// DPRINTF is a debugging trace facility that allows one to
+// selectively enable tracing statements. To use DPRINTF, there must
+// be a function or functor called name() that returns a const
+// std::string & in the current scope.
+//
+// If you desire that the automatic printing not occur, use DPRINTFR
+// (R for raw)
+//
+
+#if TRACING_ON
+
+#define DTRACE(x) (Trace::IsOn(Trace::x))
+
+#define DCOUT(x) if (Trace::IsOn(Trace::x)) DebugOut()
+
+#define DDUMP(x, data, count) \
+do { \
+ if (Trace::IsOn(Trace::x)) \
+ Trace::dataDump(curTick, name(), data, count); \
+} while (0)
+
+#define __dprintf(cycle, name, format, args...) \
+ Trace::dprintf(format, (*(new cp::ArgList), args), cycle, name)
+
+#define DPRINTF(x, args...) \
+do { \
+ if (Trace::IsOn(Trace::x)) \
+ __dprintf(curTick, name(), args, cp::ArgListNull()); \
+} while (0)
+
+#define DPRINTFR(x, args...) \
+do { \
+ if (Trace::IsOn(Trace::x)) \
+ __dprintf((Tick)-1, std::string(), args, cp::ArgListNull()); \
+} while (0)
+
+#define DPRINTFN(args...) \
+do { \
+ __dprintf(curTick, name(), args, cp::ArgListNull()); \
+} while (0)
+
+#define DPRINTFNR(args...) \
+do { \
+ __dprintf((Tick)-1, string(), args, cp::ArgListNull()); \
+} while (0)
+
+#else // !TRACING_ON
+
+#define DTRACE(x) (false)
+#define DCOUT(x) if (0) DebugOut()
+#define DPRINTF(x, args...) do {} while (0)
+#define DPRINTFR(args...) do {} while (0)
+#define DPRINTFN(args...) do {} while (0)
+#define DPRINTFNR(args...) do {} while (0)
+#define DDUMP(x, data, count) do {} while (0)
+
+#endif // TRACING_ON
+
+#endif // __BASE_TRACE_HH__
diff --git a/src/base/traceflags.py b/src/base/traceflags.py
new file mode 100644
index 000000000..7dbaac60e
--- /dev/null
+++ b/src/base/traceflags.py
@@ -0,0 +1,316 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2004-2005 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#
+# This file generates the header and source files for the flags
+# that control the tracing facility.
+#
+
+import sys
+
+if len(sys.argv) != 2:
+ print "%s: Need argument (basename of cc/hh files)" % sys.argv[0]
+ sys.exit(1)
+
+hhfilename = sys.argv[1] + '.hh'
+ccfilename = sys.argv[1] + '.cc'
+
+#
+# The list of trace flags that can be used to condition DPRINTFs etc.
+# To define a new flag, simply add it to this list.
+#
+baseFlags = [
+ 'TCPIP',
+ 'Bus',
+ 'ScsiDisk',
+ 'ScsiCtrl',
+ 'ScsiNone',
+ 'DMA',
+ 'DMAReadVerbose',
+ 'DMAWriteVerbose',
+ 'TLB',
+ 'SimpleDisk',
+ 'SimpleDiskData',
+ 'Clock',
+ 'Regs',
+ 'MC146818',
+ 'IPI',
+ 'Timer',
+ 'Mbox',
+ 'PCIA',
+ 'PCIDEV',
+ 'PciConfigAll',
+ 'ISP',
+ 'BADADDR',
+ 'Console',
+ 'ConsolePoll',
+ 'ConsoleVerbose',
+ 'AlphaConsole',
+ 'Flow',
+ 'Interrupt',
+ 'Fault',
+ 'Cycle',
+ 'Loader',
+ 'MMU',
+ 'Ethernet',
+ 'EthernetPIO',
+ 'EthernetDMA',
+ 'EthernetData',
+ 'EthernetDesc',
+ 'EthernetIntr',
+ 'EthernetSM',
+ 'EthernetCksum',
+ 'GDBMisc',
+ 'GDBAcc',
+ 'GDBRead',
+ 'GDBWrite',
+ 'GDBSend',
+ 'GDBRecv',
+ 'GDBExtra',
+ 'VtoPhys',
+ 'Printf',
+ 'DebugPrintf',
+ 'Serialize',
+ 'Event',
+ 'PCEvent',
+ 'Syscall',
+ 'SyscallVerbose',
+ 'DiskImage',
+ 'DiskImageRead',
+ 'DiskImageWrite',
+ 'InstExec',
+ 'BPredRAS',
+ 'Cache',
+ 'IIC',
+ 'IICMore',
+ 'MSHR',
+ 'Chains',
+ 'Pipeline',
+ 'Stats',
+ 'StatEvents',
+ 'Context',
+ 'Config',
+ 'Sampler',
+ 'WriteBarrier',
+ 'IdeCtrl',
+ 'IdeDisk',
+ 'Tsunami',
+ 'Uart',
+ 'Split',
+ 'SQL',
+ 'Thread',
+ 'Fetch',
+ 'Decode',
+ 'Rename',
+ 'IEW',
+ 'Commit',
+ 'IQ',
+ 'ROB',
+ 'FreeList',
+ 'RenameMap',
+ 'LDSTQ',
+ 'StoreSet',
+ 'MemDepUnit',
+ 'DynInst',
+ 'FullCPU',
+ 'CommitRate',
+ 'OoOCPU',
+ 'HWPrefetch',
+ 'Stack',
+ 'SimpleCPU',
+ 'Sparc',
+ ]
+
+#
+# "Compound" flags correspond to a set of base flags. These exist
+# solely for convenience in setting them via the command line: if a
+# compound flag is specified, all of the corresponding base flags are
+# set. Compound flags cannot be used directly in DPRINTFs etc.
+# To define a new compound flag, add a new entry to this hash
+# following the existing examples.
+#
+compoundFlagMap = {
+ 'GDBAll' : [ 'GDBMisc', 'GDBAcc', 'GDBRead', 'GDBWrite', 'GDBSend', 'GDBRecv', 'GDBExtra' ],
+ 'ScsiAll' : [ 'ScsiDisk', 'ScsiCtrl', 'ScsiNone' ],
+ 'DiskImageAll' : [ 'DiskImage', 'DiskImageRead', 'DiskImageWrite' ],
+ 'EthernetAll' : [ 'Ethernet', 'EthernetPIO', 'EthernetDMA', 'EthernetData' , 'EthernetDesc', 'EthernetIntr', 'EthernetSM', 'EthernetCksum' ],
+ 'EthernetNoData' : [ 'Ethernet', 'EthernetPIO', 'EthernetDesc', 'EthernetIntr', 'EthernetSM', 'EthernetCksum' ],
+ 'IdeAll' : [ 'IdeCtrl', 'IdeDisk' ],
+ 'FullCPUAll' : [ 'Fetch', 'Decode', 'Rename', 'IEW', 'Commit', 'IQ', 'ROB', 'FreeList', 'RenameMap', 'LDSTQ', 'StoreSet', 'MemDepUnit', 'DynInst', 'FullCPU']
+}
+
+#############################################################
+#
+# Everything below this point generates the appropriate C++
+# declarations and definitions for the trace flags. If you are simply
+# adding or modifying flag definitions, you should not have to change
+# anything below.
+#
+
+import sys
+
+# extract just the compound flag names into a list
+compoundFlags = []
+compoundFlags.extend(compoundFlagMap.keys())
+compoundFlags.sort()
+
+#
+# First generate the header file. This defines the Flag enum
+# and some extern declarations for the .cc file.
+#
+try:
+ hhfile = file(hhfilename, 'w')
+except IOError, e:
+ sys.exit("can't open %s: %s" % (hhfilename, e))
+
+# file header boilerplate
+print >>hhfile, '''
+/*
+ * DO NOT EDIT THIS FILE!
+ *
+ * Automatically generated from traceflags.py
+ */
+
+#ifndef __BASE_TRACE_FLAGS_HH__
+#define __BASE_TRACE_FLAGS_HH__
+
+namespace Trace {
+
+enum Flags {
+''',
+
+# Generate the enum. Base flags come first, then compound flags.
+idx = 0
+for flag in baseFlags:
+ print >>hhfile, ' %s = %d,' % (flag, idx)
+ idx += 1
+
+numBaseFlags = idx
+print >>hhfile, ' NumFlags = %d,' % idx
+
+# put a comment in here to separate base from compound flags
+print >>hhfile, '''
+ // The remaining enum values are *not* valid indices for Trace::flags.
+ // They are "compound" flags, which correspond to sets of base
+ // flags, and are used only by TraceParamContext::setFlags().
+''',
+
+for flag in compoundFlags:
+ print >>hhfile, ' %s = %d,' % (flag, idx)
+ idx += 1
+
+numCompoundFlags = idx - numBaseFlags
+print >>hhfile, ' NumCompoundFlags = %d' % numCompoundFlags
+
+# trailer boilerplate
+print >>hhfile, '''\
+}; // enum Flags
+
+// Array of strings for SimpleEnumParam
+extern const char *flagStrings[];
+extern const int numFlagStrings;
+
+// Array of arraay pointers: for each compound flag, gives the list of
+// base flags to set. Inidividual flag arrays are terminated by -1.
+extern const Flags *compoundFlags[];
+
+/* namespace Trace */ }
+
+#endif // __BASE_TRACE_FLAGS_HH__
+''',
+
+hhfile.close()
+
+#
+#
+# Print out .cc file with array definitions.
+#
+#
+try:
+ ccfile = file(ccfilename, 'w')
+except OSError, e:
+ sys.exit("can't open %s: %s" % (ccfilename, e))
+
+# file header
+print >>ccfile, '''
+/*
+ * DO NOT EDIT THIS FILE!
+ *
+ * Automatically generated from traceflags.pl.
+ */
+
+#include "base/traceflags.hh"
+
+using namespace Trace;
+
+const char *Trace::flagStrings[] =
+{
+''',
+
+# The string array is used by SimpleEnumParam to map the strings
+# provided by the user to enum values.
+for flag in baseFlags:
+ print >>ccfile, ' "%s",' % flag
+
+for flag in compoundFlags:
+ print >>ccfile, ' "%s",' % flag
+
+print >>ccfile, '};\n'
+
+numFlagStrings = len(baseFlags) + len(compoundFlags);
+
+print >>ccfile, 'const int Trace::numFlagStrings = %d;' % numFlagStrings
+print >>ccfile
+
+#
+# Now define the individual compound flag arrays. There is an array
+# for each compound flag listing the component base flags.
+#
+
+for flag in compoundFlags:
+ flags = compoundFlagMap[flag]
+ flags.append('(Flags)-1')
+ print >>ccfile, 'static const Flags %sMap[] =' % flag
+ print >>ccfile, '{ %s };' % (', '.join(flags))
+ print >>ccfile
+
+#
+# Finally the compoundFlags[] array maps the compound flags
+# to their individual arrays/
+#
+print >>ccfile, 'const Flags *Trace::compoundFlags[] ='
+print >>ccfile, '{'
+
+for flag in compoundFlags:
+ print >>ccfile, ' %sMap,' % flag
+
+# file trailer
+print >>ccfile, '};'
+
+ccfile.close()
+
diff --git a/src/base/userinfo.cc b/src/base/userinfo.cc
new file mode 100644
index 000000000..15bd72224
--- /dev/null
+++ b/src/base/userinfo.cc
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <pwd.h>
+#include <unistd.h>
+
+#include <string>
+
+std::string
+username()
+{
+ struct passwd *pwd = getpwuid(getuid());
+
+ return pwd->pw_name;
+}
diff --git a/src/base/userinfo.hh b/src/base/userinfo.hh
new file mode 100644
index 000000000..d8ebd443c
--- /dev/null
+++ b/src/base/userinfo.hh
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BASE_USERINFO_HH__
+#define __BASE_USERINFO_HH__
+
+#include <string>
+
+std::string username();
+
+#endif // __BASE_USERINFO_HH__
diff --git a/src/cpu/SConscript b/src/cpu/SConscript
new file mode 100644
index 000000000..34fb6df78
--- /dev/null
+++ b/src/cpu/SConscript
@@ -0,0 +1,143 @@
+# -*- mode:python -*-
+
+# Copyright (c) 2006 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import os
+import os.path
+
+# Import build environment variable from SConstruct.
+Import('env')
+
+#################################################################
+#
+# Generate StaticInst execute() method signatures.
+#
+# There must be one signature for each CPU model compiled in.
+# Since the set of compiled-in models is flexible, we generate a
+# header containing the appropriate set of signatures on the fly.
+#
+#################################################################
+
+# CPU model-specific data is contained in cpu_models.py
+# Convert to SCons File node to get path handling
+models_db = File('cpu_models.py')
+# slurp in contents of file
+execfile(models_db.srcnode().abspath)
+
+# Template for execute() signature.
+exec_sig_template = '''
+virtual Fault execute(%s *xc, Trace::InstRecord *traceData) const = 0;
+virtual Fault initiateAcc(%s *xc, Trace::InstRecord *traceData) const
+{ panic("initiateAcc not defined!"); };
+virtual Fault completeAcc(Packet *pkt, %s *xc,
+ Trace::InstRecord *traceData) const
+{ panic("completeAcc not defined!"); };
+'''
+
+# Generate header.
+def gen_cpu_exec_signatures(target, source, env):
+ f = open(str(target[0]), 'w')
+ print >> f, '''
+#ifndef __CPU_STATIC_INST_EXEC_SIGS_HH__
+#define __CPU_STATIC_INST_EXEC_SIGS_HH__
+'''
+ for cpu in env['CPU_MODELS']:
+ xc_type = CpuModel.dict[cpu].strings['CPU_exec_context']
+ print >> f, exec_sig_template % (xc_type, xc_type, xc_type)
+ print >> f, '''
+#endif // __CPU_STATIC_INST_EXEC_SIGS_HH__
+'''
+
+# Generate string that gets printed when header is rebuilt
+def gen_sigs_string(target, source, env):
+ return "Generating static_inst_exec_sigs.hh: " \
+ + ', '.join(env['CPU_MODELS'])
+
+# Add command to generate header to environment.
+env.Command('static_inst_exec_sigs.hh', models_db,
+ Action(gen_cpu_exec_signatures, gen_sigs_string,
+ varlist = ['CPU_MODELS']))
+
+#################################################################
+#
+# Include CPU-model-specific files based on set of models
+# specified in CPU_MODELS build option.
+#
+#################################################################
+
+sources = []
+
+need_simple_base = False
+if 'AtomicSimpleCPU' in env['CPU_MODELS']:
+ need_simple_base = True
+ sources += Split('simple/atomic.cc')
+
+if 'TimingSimpleCPU' in env['CPU_MODELS']:
+ need_simple_base = True
+ sources += Split('simple/timing.cc')
+
+if need_simple_base:
+ sources += Split('simple/base.cc')
+
+if 'FastCPU' in env['CPU_MODELS']:
+ sources += Split('fast/cpu.cc')
+
+if 'AlphaFullCPU' in env['CPU_MODELS']:
+ sources += Split('''
+ o3/2bit_local_pred.cc
+ o3/alpha_dyn_inst.cc
+ o3/alpha_cpu.cc
+ o3/alpha_cpu_builder.cc
+ o3/bpred_unit.cc
+ o3/btb.cc
+ o3/commit.cc
+ o3/decode.cc
+ o3/fetch.cc
+ o3/free_list.cc
+ o3/cpu.cc
+ o3/iew.cc
+ o3/inst_queue.cc
+ o3/ldstq.cc
+ o3/mem_dep_unit.cc
+ o3/ras.cc
+ o3/rename.cc
+ o3/rename_map.cc
+ o3/rob.cc
+ o3/sat_counter.cc
+ o3/store_set.cc
+ o3/tournament_pred.cc
+ ''')
+
+# FullCPU sources are included from m5/SConscript since they're not
+# below this point in the file hierarchy.
+
+# Convert file names to SCons File objects. This takes care of the
+# path relative to the top of the directory tree.
+sources = [File(s) for s in sources]
+
+Return('sources')
+
diff --git a/src/cpu/base.cc b/src/cpu/base.cc
new file mode 100644
index 000000000..9ce458c64
--- /dev/null
+++ b/src/cpu/base.cc
@@ -0,0 +1,398 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <iostream>
+#include <string>
+#include <sstream>
+
+#include "base/cprintf.hh"
+#include "base/loader/symtab.hh"
+#include "base/misc.hh"
+#include "base/output.hh"
+#include "cpu/base.hh"
+#include "cpu/exec_context.hh"
+#include "cpu/profile.hh"
+#include "cpu/sampler/sampler.hh"
+#include "sim/param.hh"
+#include "sim/process.hh"
+#include "sim/sim_events.hh"
+#include "sim/system.hh"
+
+#include "base/trace.hh"
+
+#if FULL_SYSTEM
+#include "kern/kernel_stats.hh"
+#endif
+
+using namespace std;
+
+vector<BaseCPU *> BaseCPU::cpuList;
+
+// This variable reflects the max number of threads in any CPU. Be
+// careful to only use it once all the CPUs that you care about have
+// been initialized
+int maxThreadsPerCPU = 1;
+
+#if FULL_SYSTEM
+BaseCPU::BaseCPU(Params *p)
+ : SimObject(p->name), clock(p->clock), checkInterrupts(true),
+ params(p), number_of_threads(p->numberOfThreads), system(p->system)
+#else
+BaseCPU::BaseCPU(Params *p)
+ : SimObject(p->name), clock(p->clock), params(p),
+ number_of_threads(p->numberOfThreads), system(p->system)
+#endif
+{
+ DPRINTF(FullCPU, "BaseCPU: Creating object, mem address %#x.\n", this);
+
+ // add self to global list of CPUs
+ cpuList.push_back(this);
+
+ DPRINTF(FullCPU, "BaseCPU: CPU added to cpuList, mem address %#x.\n",
+ this);
+
+ if (number_of_threads > maxThreadsPerCPU)
+ maxThreadsPerCPU = number_of_threads;
+
+ // allocate per-thread instruction-based event queues
+ comInstEventQueue = new EventQueue *[number_of_threads];
+ for (int i = 0; i < number_of_threads; ++i)
+ comInstEventQueue[i] = new EventQueue("instruction-based event queue");
+
+ //
+ // set up instruction-count-based termination events, if any
+ //
+ if (p->max_insts_any_thread != 0)
+ for (int i = 0; i < number_of_threads; ++i)
+ new SimExitEvent(comInstEventQueue[i], p->max_insts_any_thread,
+ "a thread reached the max instruction count");
+
+ if (p->max_insts_all_threads != 0) {
+ // allocate & initialize shared downcounter: each event will
+ // decrement this when triggered; simulation will terminate
+ // when counter reaches 0
+ int *counter = new int;
+ *counter = number_of_threads;
+ for (int i = 0; i < number_of_threads; ++i)
+ new CountedExitEvent(comInstEventQueue[i],
+ "all threads reached the max instruction count",
+ p->max_insts_all_threads, *counter);
+ }
+
+ // allocate per-thread load-based event queues
+ comLoadEventQueue = new EventQueue *[number_of_threads];
+ for (int i = 0; i < number_of_threads; ++i)
+ comLoadEventQueue[i] = new EventQueue("load-based event queue");
+
+ //
+ // set up instruction-count-based termination events, if any
+ //
+ if (p->max_loads_any_thread != 0)
+ for (int i = 0; i < number_of_threads; ++i)
+ new SimExitEvent(comLoadEventQueue[i], p->max_loads_any_thread,
+ "a thread reached the max load count");
+
+ if (p->max_loads_all_threads != 0) {
+ // allocate & initialize shared downcounter: each event will
+ // decrement this when triggered; simulation will terminate
+ // when counter reaches 0
+ int *counter = new int;
+ *counter = number_of_threads;
+ for (int i = 0; i < number_of_threads; ++i)
+ new CountedExitEvent(comLoadEventQueue[i],
+ "all threads reached the max load count",
+ p->max_loads_all_threads, *counter);
+ }
+
+#if FULL_SYSTEM
+ memset(interrupts, 0, sizeof(interrupts));
+ intstatus = 0;
+#endif
+
+ functionTracingEnabled = false;
+ if (p->functionTrace) {
+ functionTraceStream = simout.find(csprintf("ftrace.%s", name()));
+ currentFunctionStart = currentFunctionEnd = 0;
+ functionEntryTick = p->functionTraceStart;
+
+ if (p->functionTraceStart == 0) {
+ functionTracingEnabled = true;
+ } else {
+ Event *e =
+ new EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace>(this,
+ true);
+ e->schedule(p->functionTraceStart);
+ }
+ }
+#if FULL_SYSTEM
+ profileEvent = NULL;
+ if (params->profile)
+ profileEvent = new ProfileEvent(this, params->profile);
+
+ kernelStats = new Kernel::Statistics(system);
+#endif
+
+}
+
+BaseCPU::Params::Params()
+{
+#if FULL_SYSTEM
+ profile = false;
+#endif
+}
+
+void
+BaseCPU::enableFunctionTrace()
+{
+ functionTracingEnabled = true;
+}
+
+BaseCPU::~BaseCPU()
+{
+#if FULL_SYSTEM
+ if (kernelStats)
+ delete kernelStats;
+#endif
+}
+
+void
+BaseCPU::init()
+{
+ if (!params->deferRegistration)
+ registerExecContexts();
+}
+
+void
+BaseCPU::startup()
+{
+#if FULL_SYSTEM
+ if (!params->deferRegistration && profileEvent)
+ profileEvent->schedule(curTick);
+#endif
+}
+
+
+void
+BaseCPU::regStats()
+{
+ using namespace Stats;
+
+ numCycles
+ .name(name() + ".numCycles")
+ .desc("number of cpu cycles simulated")
+ ;
+
+ int size = execContexts.size();
+ if (size > 1) {
+ for (int i = 0; i < size; ++i) {
+ stringstream namestr;
+ ccprintf(namestr, "%s.ctx%d", name(), i);
+ execContexts[i]->regStats(namestr.str());
+ }
+ } else if (size == 1)
+ execContexts[0]->regStats(name());
+
+#if FULL_SYSTEM
+ if (kernelStats)
+ kernelStats->regStats(name() + ".kern");
+#endif
+}
+
+
+void
+BaseCPU::registerExecContexts()
+{
+ for (int i = 0; i < execContexts.size(); ++i) {
+ ExecContext *xc = execContexts[i];
+
+#if FULL_SYSTEM
+ int id = params->cpu_id;
+ if (id != -1)
+ id += i;
+
+ xc->setCpuId(system->registerExecContext(xc, id));
+#else
+ xc->setCpuId(xc->getProcessPtr()->registerExecContext(xc));
+#endif
+ }
+}
+
+
+void
+BaseCPU::switchOut(Sampler *sampler)
+{
+ panic("This CPU doesn't support sampling!");
+}
+
+void
+BaseCPU::takeOverFrom(BaseCPU *oldCPU)
+{
+ assert(execContexts.size() == oldCPU->execContexts.size());
+
+ for (int i = 0; i < execContexts.size(); ++i) {
+ ExecContext *newXC = execContexts[i];
+ ExecContext *oldXC = oldCPU->execContexts[i];
+
+ newXC->takeOverFrom(oldXC);
+ assert(newXC->readCpuId() == oldXC->readCpuId());
+#if FULL_SYSTEM
+ system->replaceExecContext(newXC, newXC->readCpuId());
+#else
+ assert(newXC->getProcessPtr() == oldXC->getProcessPtr());
+ newXC->getProcessPtr()->replaceExecContext(newXC, newXC->readCpuId());
+#endif
+ }
+
+#if FULL_SYSTEM
+ for (int i = 0; i < TheISA::NumInterruptLevels; ++i)
+ interrupts[i] = oldCPU->interrupts[i];
+ intstatus = oldCPU->intstatus;
+
+ for (int i = 0; i < execContexts.size(); ++i)
+ execContexts[i]->profileClear();
+
+ if (profileEvent)
+ profileEvent->schedule(curTick);
+#endif
+}
+
+
+#if FULL_SYSTEM
+BaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, int _interval)
+ : Event(&mainEventQueue), cpu(_cpu), interval(_interval)
+{ }
+
+void
+BaseCPU::ProfileEvent::process()
+{
+ for (int i = 0, size = cpu->execContexts.size(); i < size; ++i) {
+ ExecContext *xc = cpu->execContexts[i];
+ xc->profileSample();
+ }
+
+ schedule(curTick + interval);
+}
+
+void
+BaseCPU::post_interrupt(int int_num, int index)
+{
+ DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index);
+
+ if (int_num < 0 || int_num >= TheISA::NumInterruptLevels)
+ panic("int_num out of bounds\n");
+
+ if (index < 0 || index >= sizeof(uint64_t) * 8)
+ panic("int_num out of bounds\n");
+
+ checkInterrupts = true;
+ interrupts[int_num] |= 1 << index;
+ intstatus |= (ULL(1) << int_num);
+}
+
+void
+BaseCPU::clear_interrupt(int int_num, int index)
+{
+ DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index);
+
+ if (int_num < 0 || int_num >= TheISA::NumInterruptLevels)
+ panic("int_num out of bounds\n");
+
+ if (index < 0 || index >= sizeof(uint64_t) * 8)
+ panic("int_num out of bounds\n");
+
+ interrupts[int_num] &= ~(1 << index);
+ if (interrupts[int_num] == 0)
+ intstatus &= ~(ULL(1) << int_num);
+}
+
+void
+BaseCPU::clear_interrupts()
+{
+ DPRINTF(Interrupt, "Interrupts all cleared\n");
+
+ memset(interrupts, 0, sizeof(interrupts));
+ intstatus = 0;
+}
+
+
+void
+BaseCPU::serialize(std::ostream &os)
+{
+ SERIALIZE_ARRAY(interrupts, TheISA::NumInterruptLevels);
+ SERIALIZE_SCALAR(intstatus);
+
+#if FULL_SYSTEM
+ if (kernelStats)
+ kernelStats->serialize(os);
+#endif
+
+}
+
+void
+BaseCPU::unserialize(Checkpoint *cp, const std::string &section)
+{
+ UNSERIALIZE_ARRAY(interrupts, TheISA::NumInterruptLevels);
+ UNSERIALIZE_SCALAR(intstatus);
+
+#if FULL_SYSTEM
+ if (kernelStats)
+ kernelStats->unserialize(cp, section);
+#endif
+}
+
+#endif // FULL_SYSTEM
+
+void
+BaseCPU::traceFunctionsInternal(Addr pc)
+{
+ if (!debugSymbolTable)
+ return;
+
+ // if pc enters different function, print new function symbol and
+ // update saved range. Otherwise do nothing.
+ if (pc < currentFunctionStart || pc >= currentFunctionEnd) {
+ string sym_str;
+ bool found = debugSymbolTable->findNearestSymbol(pc, sym_str,
+ currentFunctionStart,
+ currentFunctionEnd);
+
+ if (!found) {
+ // no symbol found: use addr as label
+ sym_str = csprintf("0x%x", pc);
+ currentFunctionStart = pc;
+ currentFunctionEnd = pc + 1;
+ }
+
+ ccprintf(*functionTraceStream, " (%d)\n%d: %s",
+ curTick - functionEntryTick, curTick, sym_str);
+ functionEntryTick = curTick;
+ }
+}
+
+
+DEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU)
diff --git a/src/cpu/base.hh b/src/cpu/base.hh
new file mode 100644
index 000000000..79700c117
--- /dev/null
+++ b/src/cpu/base.hh
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPU_BASE_HH__
+#define __CPU_BASE_HH__
+
+#include <vector>
+
+#include "base/statistics.hh"
+#include "config/full_system.hh"
+#include "cpu/sampler/sampler.hh"
+#include "sim/eventq.hh"
+#include "sim/sim_object.hh"
+#include "arch/isa_traits.hh"
+
+class System;
+namespace Kernel { class Statistics; }
+class BranchPred;
+class ExecContext;
+
+class BaseCPU : public SimObject
+{
+ protected:
+ // CPU's clock period in terms of the number of ticks of curTime.
+ Tick clock;
+
+ public:
+ inline Tick frequency() const { return Clock::Frequency / clock; }
+ inline Tick cycles(int numCycles) const { return clock * numCycles; }
+ inline Tick curCycle() const { return curTick / clock; }
+
+#if FULL_SYSTEM
+ protected:
+ uint64_t interrupts[TheISA::NumInterruptLevels];
+ uint64_t intstatus;
+
+ public:
+ virtual void post_interrupt(int int_num, int index);
+ virtual void clear_interrupt(int int_num, int index);
+ virtual void clear_interrupts();
+ bool checkInterrupts;
+
+ bool check_interrupt(int int_num) const {
+ if (int_num > TheISA::NumInterruptLevels)
+ panic("int_num out of bounds\n");
+
+ return interrupts[int_num] != 0;
+ }
+
+ bool check_interrupts() const { return intstatus != 0; }
+ uint64_t intr_status() const { return intstatus; }
+
+ class ProfileEvent : public Event
+ {
+ private:
+ BaseCPU *cpu;
+ int interval;
+
+ public:
+ ProfileEvent(BaseCPU *cpu, int interval);
+ void process();
+ };
+ ProfileEvent *profileEvent;
+#endif
+
+ protected:
+ std::vector<ExecContext *> execContexts;
+
+ public:
+
+ /// Notify the CPU that the indicated context is now active. The
+ /// delay parameter indicates the number of ticks to wait before
+ /// executing (typically 0 or 1).
+ virtual void activateContext(int thread_num, int delay) {}
+
+ /// Notify the CPU that the indicated context is now suspended.
+ virtual void suspendContext(int thread_num) {}
+
+ /// Notify the CPU that the indicated context is now deallocated.
+ virtual void deallocateContext(int thread_num) {}
+
+ /// Notify the CPU that the indicated context is now halted.
+ virtual void haltContext(int thread_num) {}
+
+ public:
+ struct Params
+ {
+ std::string name;
+ int numberOfThreads;
+ bool deferRegistration;
+ Counter max_insts_any_thread;
+ Counter max_insts_all_threads;
+ Counter max_loads_any_thread;
+ Counter max_loads_all_threads;
+ Tick clock;
+ bool functionTrace;
+ Tick functionTraceStart;
+ System *system;
+#if FULL_SYSTEM
+ int cpu_id;
+ Tick profile;
+#endif
+
+ Params();
+ };
+
+ const Params *params;
+
+ BaseCPU(Params *params);
+ virtual ~BaseCPU();
+
+ virtual void init();
+ virtual void startup();
+ virtual void regStats();
+
+ virtual void activateWhenReady(int tid) {};
+
+ void registerExecContexts();
+
+ /// Prepare for another CPU to take over execution. When it is
+ /// is ready (drained pipe) it signals the sampler.
+ virtual void switchOut(Sampler *);
+
+ /// Take over execution from the given CPU. Used for warm-up and
+ /// sampling.
+ virtual void takeOverFrom(BaseCPU *);
+
+ /**
+ * Number of threads we're actually simulating (<= SMT_MAX_THREADS).
+ * This is a constant for the duration of the simulation.
+ */
+ int number_of_threads;
+
+ /**
+ * Vector of per-thread instruction-based event queues. Used for
+ * scheduling events based on number of instructions committed by
+ * a particular thread.
+ */
+ EventQueue **comInstEventQueue;
+
+ /**
+ * Vector of per-thread load-based event queues. Used for
+ * scheduling events based on number of loads committed by
+ *a particular thread.
+ */
+ EventQueue **comLoadEventQueue;
+
+ System *system;
+
+#if FULL_SYSTEM
+ /**
+ * Serialize this object to the given output stream.
+ * @param os The stream to serialize to.
+ */
+ virtual void serialize(std::ostream &os);
+
+ /**
+ * Reconstruct the state of this object from a checkpoint.
+ * @param cp The checkpoint use.
+ * @param section The section name of this object
+ */
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+
+#endif
+
+ /**
+ * Return pointer to CPU's branch predictor (NULL if none).
+ * @return Branch predictor pointer.
+ */
+ virtual BranchPred *getBranchPred() { return NULL; };
+
+ virtual Counter totalInstructions() const { return 0; }
+
+ // Function tracing
+ private:
+ bool functionTracingEnabled;
+ std::ostream *functionTraceStream;
+ Addr currentFunctionStart;
+ Addr currentFunctionEnd;
+ Tick functionEntryTick;
+ void enableFunctionTrace();
+ void traceFunctionsInternal(Addr pc);
+
+ protected:
+ void traceFunctions(Addr pc)
+ {
+ if (functionTracingEnabled)
+ traceFunctionsInternal(pc);
+ }
+
+ private:
+ static std::vector<BaseCPU *> cpuList; //!< Static global cpu list
+
+ public:
+ static int numSimulatedCPUs() { return cpuList.size(); }
+ static Counter numSimulatedInstructions()
+ {
+ Counter total = 0;
+
+ int size = cpuList.size();
+ for (int i = 0; i < size; ++i)
+ total += cpuList[i]->totalInstructions();
+
+ return total;
+ }
+
+ public:
+ // Number of CPU cycles simulated
+ Stats::Scalar<> numCycles;
+
+#if FULL_SYSTEM
+ Kernel::Statistics *kernelStats;
+#endif
+};
+
+#endif // __CPU_BASE_HH__
diff --git a/src/cpu/base_dyn_inst.cc b/src/cpu/base_dyn_inst.cc
new file mode 100644
index 000000000..bf7c35cad
--- /dev/null
+++ b/src/cpu/base_dyn_inst.cc
@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPU_BASE_DYN_INST_CC__
+#define __CPU_BASE_DYN_INST_CC__
+
+#include <iostream>
+#include <string>
+#include <sstream>
+
+#include "base/cprintf.hh"
+#include "base/trace.hh"
+
+#include "arch/faults.hh"
+#include "cpu/exetrace.hh"
+#include "mem/mem_req.hh"
+
+#include "cpu/base_dyn_inst.hh"
+#include "cpu/o3/alpha_impl.hh"
+#include "cpu/o3/alpha_cpu.hh"
+
+using namespace std;
+using namespace TheISA;
+
+#define NOHASH
+#ifndef NOHASH
+
+#include "base/hashmap.hh"
+
+unsigned int MyHashFunc(const BaseDynInst *addr)
+{
+ unsigned a = (unsigned)addr;
+ unsigned hash = (((a >> 14) ^ ((a >> 2) & 0xffff))) & 0x7FFFFFFF;
+
+ return hash;
+}
+
+typedef m5::hash_map<const BaseDynInst *, const BaseDynInst *, MyHashFunc> my_hash_t;
+my_hash_t thishash;
+#endif
+
+template <class Impl>
+BaseDynInst<Impl>::BaseDynInst(MachInst machInst, Addr inst_PC,
+ Addr pred_PC, InstSeqNum seq_num,
+ FullCPU *cpu)
+ : staticInst(machInst), traceData(NULL), cpu(cpu), cpuXC(cpu->cpuXCBase())
+{
+ seqNum = seq_num;
+
+ PC = inst_PC;
+ nextPC = PC + sizeof(MachInst);
+ predPC = pred_PC;
+
+ initVars();
+}
+
+template <class Impl>
+BaseDynInst<Impl>::BaseDynInst(StaticInstPtr &_staticInst)
+ : staticInst(_staticInst), traceData(NULL)
+{
+ initVars();
+}
+
+template <class Impl>
+void
+BaseDynInst<Impl>::initVars()
+{
+ effAddr = MemReq::inval_addr;
+ physEffAddr = MemReq::inval_addr;
+
+ readyRegs = 0;
+
+ completed = false;
+ canIssue = false;
+ issued = false;
+ executed = false;
+ canCommit = false;
+ squashed = false;
+ squashedInIQ = false;
+ eaCalcDone = false;
+
+ blockingInst = false;
+ recoverInst = false;
+
+ // Eventually make this a parameter.
+ threadNumber = 0;
+
+ // Also make this a parameter, or perhaps get it from xc or cpu.
+ asid = 0;
+
+ // Initialize the fault to be unimplemented opcode.
+ fault = new UnimplementedOpcodeFault;
+
+ ++instcount;
+
+ DPRINTF(FullCPU, "DynInst: Instruction created. Instcount=%i\n",
+ instcount);
+}
+
+template <class Impl>
+BaseDynInst<Impl>::~BaseDynInst()
+{
+ --instcount;
+ DPRINTF(FullCPU, "DynInst: Instruction destroyed. Instcount=%i\n",
+ instcount);
+}
+
+template <class Impl>
+void
+BaseDynInst<Impl>::prefetch(Addr addr, unsigned flags)
+{
+ // This is the "functional" implementation of prefetch. Not much
+ // happens here since prefetches don't affect the architectural
+ // state.
+
+ // Generate a MemReq so we can translate the effective address.
+ MemReqPtr req = new MemReq(addr, cpuXC->getProxy(), 1, flags);
+ req->asid = asid;
+
+ // Prefetches never cause faults.
+ fault = NoFault;
+
+ // note this is a local, not BaseDynInst::fault
+ Fault trans_fault = cpuXC->translateDataReadReq(req);
+
+ if (trans_fault == NoFault && !(req->flags & UNCACHEABLE)) {
+ // It's a valid address to cacheable space. Record key MemReq
+ // parameters so we can generate another one just like it for
+ // the timing access without calling translate() again (which
+ // might mess up the TLB).
+ effAddr = req->vaddr;
+ physEffAddr = req->paddr;
+ memReqFlags = req->flags;
+ } else {
+ // Bogus address (invalid or uncacheable space). Mark it by
+ // setting the eff_addr to InvalidAddr.
+ effAddr = physEffAddr = MemReq::inval_addr;
+ }
+
+ /**
+ * @todo
+ * Replace the disjoint functional memory with a unified one and remove
+ * this hack.
+ */
+#if !FULL_SYSTEM
+ req->paddr = req->vaddr;
+#endif
+
+ if (traceData) {
+ traceData->setAddr(addr);
+ }
+}
+
+template <class Impl>
+void
+BaseDynInst<Impl>::writeHint(Addr addr, int size, unsigned flags)
+{
+ // Need to create a MemReq here so we can do a translation. This
+ // will casue a TLB miss trap if necessary... not sure whether
+ // that's the best thing to do or not. We don't really need the
+ // MemReq otherwise, since wh64 has no functional effect.
+ MemReqPtr req = new MemReq(addr, cpuXC->getProxy(), size, flags);
+ req->asid = asid;
+
+ fault = cpuXC->translateDataWriteReq(req);
+
+ if (fault == NoFault && !(req->flags & UNCACHEABLE)) {
+ // Record key MemReq parameters so we can generate another one
+ // just like it for the timing access without calling translate()
+ // again (which might mess up the TLB).
+ effAddr = req->vaddr;
+ physEffAddr = req->paddr;
+ memReqFlags = req->flags;
+ } else {
+ // ignore faults & accesses to uncacheable space... treat as no-op
+ effAddr = physEffAddr = MemReq::inval_addr;
+ }
+
+ storeSize = size;
+ storeData = 0;
+}
+
+/**
+ * @todo Need to find a way to get the cache block size here.
+ */
+template <class Impl>
+Fault
+BaseDynInst<Impl>::copySrcTranslate(Addr src)
+{
+ MemReqPtr req = new MemReq(src, cpuXC->getProxy(), 64);
+ req->asid = asid;
+
+ // translate to physical address
+ Fault fault = cpuXC->translateDataReadReq(req);
+
+ if (fault == NoFault) {
+ cpuXC->copySrcAddr = src;
+ cpuXC->copySrcPhysAddr = req->paddr;
+ } else {
+ cpuXC->copySrcAddr = 0;
+ cpuXC->copySrcPhysAddr = 0;
+ }
+ return fault;
+}
+
+/**
+ * @todo Need to find a way to get the cache block size here.
+ */
+template <class Impl>
+Fault
+BaseDynInst<Impl>::copy(Addr dest)
+{
+ uint8_t data[64];
+ FunctionalMemory *mem = cpuXC->mem;
+ assert(cpuXC->copySrcPhysAddr || cpuXC->misspeculating());
+ MemReqPtr req = new MemReq(dest, cpuXC->getProxy(), 64);
+ req->asid = asid;
+
+ // translate to physical address
+ Fault fault = cpuXC->translateDataWriteReq(req);
+
+ if (fault == NoFault) {
+ Addr dest_addr = req->paddr;
+ // Need to read straight from memory since we have more than 8 bytes.
+ req->paddr = cpuXC->copySrcPhysAddr;
+ mem->read(req, data);
+ req->paddr = dest_addr;
+ mem->write(req, data);
+ }
+ return fault;
+}
+
+template <class Impl>
+void
+BaseDynInst<Impl>::dump()
+{
+ cprintf("T%d : %#08d `", threadNumber, PC);
+ cout << staticInst->disassemble(PC);
+ cprintf("'\n");
+}
+
+template <class Impl>
+void
+BaseDynInst<Impl>::dump(std::string &outstring)
+{
+ std::ostringstream s;
+ s << "T" << threadNumber << " : 0x" << PC << " "
+ << staticInst->disassemble(PC);
+
+ outstring = s.str();
+}
+
+
+#if 0
+template <class Impl>
+Fault
+BaseDynInst<Impl>::mem_access(mem_cmd cmd, Addr addr, void *p, int nbytes)
+{
+ Fault fault;
+
+ // check alignments, even speculative this test should always pass
+ if ((nbytes & nbytes - 1) != 0 || (addr & nbytes - 1) != 0) {
+ for (int i = 0; i < nbytes; i++)
+ ((char *) p)[i] = 0;
+
+ // I added the following because according to the comment above,
+ // we should never get here. The comment lies
+#if 0
+ panic("unaligned access. Cycle = %n", curTick);
+#endif
+ return NoFault;
+ }
+
+ MemReqPtr req = new MemReq(addr, thread, nbytes);
+ switch(cmd) {
+ case Read:
+ fault = spec_mem->read(req, (uint8_t *)p);
+ break;
+
+ case Write:
+ fault = spec_mem->write(req, (uint8_t *)p);
+ if (fault != NoFault)
+ break;
+
+ specMemWrite = true;
+ storeSize = nbytes;
+ switch(nbytes) {
+ case sizeof(uint8_t):
+ *(uint8_t)&storeData = (uint8_t *)p;
+ break;
+ case sizeof(uint16_t):
+ *(uint16_t)&storeData = (uint16_t *)p;
+ break;
+ case sizeof(uint32_t):
+ *(uint32_t)&storeData = (uint32_t *)p;
+ break;
+ case sizeof(uint64_t):
+ *(uint64_t)&storeData = (uint64_t *)p;
+ break;
+ }
+ break;
+
+ default:
+ fault = genMachineCheckFault();
+ break;
+ }
+
+ trace_mem(fault, cmd, addr, p, nbytes);
+
+ return fault;
+}
+
+#endif
+
+template <class Impl>
+bool
+BaseDynInst<Impl>::eaSrcsReady()
+{
+ // For now I am assuming that src registers 1..n-1 are the ones that the
+ // EA calc depends on. (i.e. src reg 0 is the source of the data to be
+ // stored)
+
+ for (int i = 1; i < numSrcRegs(); ++i)
+ {
+ if (!_readySrcRegIdx[i])
+ return false;
+ }
+
+ return true;
+}
+
+// Forward declaration
+template class BaseDynInst<AlphaSimpleImpl>;
+
+template <>
+int
+BaseDynInst<AlphaSimpleImpl>::instcount = 0;
+
+#endif // __CPU_BASE_DYN_INST_CC__
diff --git a/src/cpu/base_dyn_inst.hh b/src/cpu/base_dyn_inst.hh
new file mode 100644
index 000000000..3a7852f79
--- /dev/null
+++ b/src/cpu/base_dyn_inst.hh
@@ -0,0 +1,530 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPU_BASE_DYN_INST_HH__
+#define __CPU_BASE_DYN_INST_HH__
+
+#include <string>
+#include <vector>
+
+#include "base/fast_alloc.hh"
+#include "base/trace.hh"
+#include "config/full_system.hh"
+#include "cpu/exetrace.hh"
+#include "cpu/inst_seq.hh"
+#include "cpu/o3/comm.hh"
+#include "cpu/static_inst.hh"
+#include "encumbered/cpu/full/bpred_update.hh"
+#include "encumbered/cpu/full/op_class.hh"
+#include "encumbered/cpu/full/spec_memory.hh"
+#include "encumbered/cpu/full/spec_state.hh"
+#include "encumbered/mem/functional/main.hh"
+
+/**
+ * @file
+ * Defines a dynamic instruction context.
+ */
+
+// Forward declaration.
+class StaticInstPtr;
+
+template <class Impl>
+class BaseDynInst : public FastAlloc, public RefCounted
+{
+ public:
+ // Typedef for the CPU.
+ typedef typename Impl::FullCPU FullCPU;
+
+ /// Binary machine instruction type.
+ typedef TheISA::MachInst MachInst;
+ /// Logical register index type.
+ typedef TheISA::RegIndex RegIndex;
+ /// Integer register index type.
+ typedef TheISA::IntReg IntReg;
+
+ enum {
+ MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs
+ MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs
+ };
+
+ /** The static inst used by this dyn inst. */
+ StaticInstPtr staticInst;
+
+ ////////////////////////////////////////////
+ //
+ // INSTRUCTION EXECUTION
+ //
+ ////////////////////////////////////////////
+ Trace::InstRecord *traceData;
+
+ template <class T>
+ Fault read(Addr addr, T &data, unsigned flags);
+
+ template <class T>
+ Fault write(T data, Addr addr, unsigned flags,
+ uint64_t *res);
+
+ void prefetch(Addr addr, unsigned flags);
+ void writeHint(Addr addr, int size, unsigned flags);
+ Fault copySrcTranslate(Addr src);
+ Fault copy(Addr dest);
+
+ /** @todo: Consider making this private. */
+ public:
+ /** Is this instruction valid. */
+ bool valid;
+
+ /** The sequence number of the instruction. */
+ InstSeqNum seqNum;
+
+ /** How many source registers are ready. */
+ unsigned readyRegs;
+
+ /** Is the instruction completed. */
+ bool completed;
+
+ /** Can this instruction issue. */
+ bool canIssue;
+
+ /** Has this instruction issued. */
+ bool issued;
+
+ /** Has this instruction executed (or made it through execute) yet. */
+ bool executed;
+
+ /** Can this instruction commit. */
+ bool canCommit;
+
+ /** Is this instruction squashed. */
+ bool squashed;
+
+ /** Is this instruction squashed in the instruction queue. */
+ bool squashedInIQ;
+
+ /** Is this a recover instruction. */
+ bool recoverInst;
+
+ /** Is this a thread blocking instruction. */
+ bool blockingInst; /* this inst has called thread_block() */
+
+ /** Is this a thread syncrhonization instruction. */
+ bool threadsyncWait;
+
+ /** The thread this instruction is from. */
+ short threadNumber;
+
+ /** data address space ID, for loads & stores. */
+ short asid;
+
+ /** Pointer to the FullCPU object. */
+ FullCPU *cpu;
+
+ /** Pointer to the exec context. Will not exist in the final version. */
+ CPUExecContext *cpuXC;
+
+ /** The kind of fault this instruction has generated. */
+ Fault fault;
+
+ /** The effective virtual address (lds & stores only). */
+ Addr effAddr;
+
+ /** The effective physical address. */
+ Addr physEffAddr;
+
+ /** Effective virtual address for a copy source. */
+ Addr copySrcEffAddr;
+
+ /** Effective physical address for a copy source. */
+ Addr copySrcPhysEffAddr;
+
+ /** The memory request flags (from translation). */
+ unsigned memReqFlags;
+
+ /** The size of the data to be stored. */
+ int storeSize;
+
+ /** The data to be stored. */
+ IntReg storeData;
+
+ union Result {
+ uint64_t integer;
+ float fp;
+ double dbl;
+ };
+
+ /** The result of the instruction; assumes for now that there's only one
+ * destination register.
+ */
+ Result instResult;
+
+ /** PC of this instruction. */
+ Addr PC;
+
+ /** Next non-speculative PC. It is not filled in at fetch, but rather
+ * once the target of the branch is truly known (either decode or
+ * execute).
+ */
+ Addr nextPC;
+
+ /** Predicted next PC. */
+ Addr predPC;
+
+ /** Count of total number of dynamic instructions. */
+ static int instcount;
+
+ /** Whether or not the source register is ready. Not sure this should be
+ * here vs. the derived class.
+ */
+ bool _readySrcRegIdx[MaxInstSrcRegs];
+
+ public:
+ /** BaseDynInst constructor given a binary instruction. */
+ BaseDynInst(MachInst inst, Addr PC, Addr Pred_PC, InstSeqNum seq_num,
+ FullCPU *cpu);
+
+ /** BaseDynInst constructor given a static inst pointer. */
+ BaseDynInst(StaticInstPtr &_staticInst);
+
+ /** BaseDynInst destructor. */
+ ~BaseDynInst();
+
+ private:
+ /** Function to initialize variables in the constructors. */
+ void initVars();
+
+ public:
+ void
+ trace_mem(Fault fault, // last fault
+ MemCmd cmd, // last command
+ Addr addr, // virtual address of access
+ void *p, // memory accessed
+ int nbytes); // access size
+
+ /** Dumps out contents of this BaseDynInst. */
+ void dump();
+
+ /** Dumps out contents of this BaseDynInst into given string. */
+ void dump(std::string &outstring);
+
+ /** Returns the fault type. */
+ Fault getFault() { return fault; }
+
+ /** Checks whether or not this instruction has had its branch target
+ * calculated yet. For now it is not utilized and is hacked to be
+ * always false.
+ */
+ bool doneTargCalc() { return false; }
+
+ /** Returns the next PC. This could be the speculative next PC if it is
+ * called prior to the actual branch target being calculated.
+ */
+ Addr readNextPC() { return nextPC; }
+
+ /** Set the predicted target of this current instruction. */
+ void setPredTarg(Addr predicted_PC) { predPC = predicted_PC; }
+
+ /** Returns the predicted target of the branch. */
+ Addr readPredTarg() { return predPC; }
+
+ /** Returns whether the instruction was predicted taken or not. */
+ bool predTaken() {
+ return( predPC != (PC + sizeof(MachInst) ) );
+ }
+
+ /** Returns whether the instruction mispredicted. */
+ bool mispredicted() { return (predPC != nextPC); }
+
+ //
+ // Instruction types. Forward checks to StaticInst object.
+ //
+ bool isNop() const { return staticInst->isNop(); }
+ bool isMemRef() const { return staticInst->isMemRef(); }
+ bool isLoad() const { return staticInst->isLoad(); }
+ bool isStore() const { return staticInst->isStore(); }
+ bool isInstPrefetch() const { return staticInst->isInstPrefetch(); }
+ bool isDataPrefetch() const { return staticInst->isDataPrefetch(); }
+ bool isCopy() const { return staticInst->isCopy(); }
+ bool isInteger() const { return staticInst->isInteger(); }
+ bool isFloating() const { return staticInst->isFloating(); }
+ bool isControl() const { return staticInst->isControl(); }
+ bool isCall() const { return staticInst->isCall(); }
+ bool isReturn() const { return staticInst->isReturn(); }
+ bool isDirectCtrl() const { return staticInst->isDirectCtrl(); }
+ bool isIndirectCtrl() const { return staticInst->isIndirectCtrl(); }
+ bool isCondCtrl() const { return staticInst->isCondCtrl(); }
+ bool isUncondCtrl() const { return staticInst->isUncondCtrl(); }
+ bool isThreadSync() const { return staticInst->isThreadSync(); }
+ bool isSerializing() const { return staticInst->isSerializing(); }
+ bool isMemBarrier() const { return staticInst->isMemBarrier(); }
+ bool isWriteBarrier() const { return staticInst->isWriteBarrier(); }
+ bool isNonSpeculative() const { return staticInst->isNonSpeculative(); }
+
+ /** Returns the opclass of this instruction. */
+ OpClass opClass() const { return staticInst->opClass(); }
+
+ /** Returns the branch target address. */
+ Addr branchTarget() const { return staticInst->branchTarget(PC); }
+
+ /** Number of source registers. */
+ int8_t numSrcRegs() const { return staticInst->numSrcRegs(); }
+
+ /** Number of destination registers. */
+ int8_t numDestRegs() const { return staticInst->numDestRegs(); }
+
+ // the following are used to track physical register usage
+ // for machines with separate int & FP reg files
+ int8_t numFPDestRegs() const { return staticInst->numFPDestRegs(); }
+ int8_t numIntDestRegs() const { return staticInst->numIntDestRegs(); }
+
+ /** Returns the logical register index of the i'th destination register. */
+ RegIndex destRegIdx(int i) const
+ {
+ return staticInst->destRegIdx(i);
+ }
+
+ /** Returns the logical register index of the i'th source register. */
+ RegIndex srcRegIdx(int i) const
+ {
+ return staticInst->srcRegIdx(i);
+ }
+
+ /** Returns the result of an integer instruction. */
+ uint64_t readIntResult() { return instResult.integer; }
+
+ /** Returns the result of a floating point instruction. */
+ float readFloatResult() { return instResult.fp; }
+
+ /** Returns the result of a floating point (double) instruction. */
+ double readDoubleResult() { return instResult.dbl; }
+
+ //Push to .cc file.
+ /** Records that one of the source registers is ready. */
+ void markSrcRegReady()
+ {
+ ++readyRegs;
+ if(readyRegs == numSrcRegs()) {
+ canIssue = true;
+ }
+ }
+
+ /** Marks a specific register as ready.
+ * @todo: Move this to .cc file.
+ */
+ void markSrcRegReady(RegIndex src_idx)
+ {
+ ++readyRegs;
+
+ _readySrcRegIdx[src_idx] = 1;
+
+ if(readyRegs == numSrcRegs()) {
+ canIssue = true;
+ }
+ }
+
+ /** Returns if a source register is ready. */
+ bool isReadySrcRegIdx(int idx) const
+ {
+ return this->_readySrcRegIdx[idx];
+ }
+
+ /** Sets this instruction as completed. */
+ void setCompleted() { completed = true; }
+
+ /** Returns whethe or not this instruction is completed. */
+ bool isCompleted() const { return completed; }
+
+ /** Sets this instruction as ready to issue. */
+ void setCanIssue() { canIssue = true; }
+
+ /** Returns whether or not this instruction is ready to issue. */
+ bool readyToIssue() const { return canIssue; }
+
+ /** Sets this instruction as issued from the IQ. */
+ void setIssued() { issued = true; }
+
+ /** Returns whether or not this instruction has issued. */
+ bool isIssued() const { return issued; }
+
+ /** Sets this instruction as executed. */
+ void setExecuted() { executed = true; }
+
+ /** Returns whether or not this instruction has executed. */
+ bool isExecuted() const { return executed; }
+
+ /** Sets this instruction as ready to commit. */
+ void setCanCommit() { canCommit = true; }
+
+ /** Clears this instruction as being ready to commit. */
+ void clearCanCommit() { canCommit = false; }
+
+ /** Returns whether or not this instruction is ready to commit. */
+ bool readyToCommit() const { return canCommit; }
+
+ /** Sets this instruction as squashed. */
+ void setSquashed() { squashed = true; }
+
+ /** Returns whether or not this instruction is squashed. */
+ bool isSquashed() const { return squashed; }
+
+ /** Sets this instruction as squashed in the IQ. */
+ void setSquashedInIQ() { squashedInIQ = true; }
+
+ /** Returns whether or not this instruction is squashed in the IQ. */
+ bool isSquashedInIQ() const { return squashedInIQ; }
+
+ /** Read the PC of this instruction. */
+ const Addr readPC() const { return PC; }
+
+ /** Set the next PC of this instruction (its actual target). */
+ void setNextPC(uint64_t val) { nextPC = val; }
+
+ /** Returns the exec context.
+ * @todo: Remove this once the ExecContext is no longer used.
+ */
+ ExecContext *xcBase() { return cpuXC->getProxy(); }
+
+ private:
+ /** Instruction effective address.
+ * @todo: Consider if this is necessary or not.
+ */
+ Addr instEffAddr;
+ /** Whether or not the effective address calculation is completed.
+ * @todo: Consider if this is necessary or not.
+ */
+ bool eaCalcDone;
+
+ public:
+ /** Sets the effective address. */
+ void setEA(Addr &ea) { instEffAddr = ea; eaCalcDone = true; }
+
+ /** Returns the effective address. */
+ const Addr &getEA() const { return instEffAddr; }
+
+ /** Returns whether or not the eff. addr. calculation has been completed. */
+ bool doneEACalc() { return eaCalcDone; }
+
+ /** Returns whether or not the eff. addr. source registers are ready. */
+ bool eaSrcsReady();
+
+ public:
+ /** Load queue index. */
+ int16_t lqIdx;
+
+ /** Store queue index. */
+ int16_t sqIdx;
+};
+
+template<class Impl>
+template<class T>
+inline Fault
+BaseDynInst<Impl>::read(Addr addr, T &data, unsigned flags)
+{
+ MemReqPtr req = new MemReq(addr, cpuXC->getProxy(), sizeof(T), flags);
+ req->asid = asid;
+
+ fault = cpu->translateDataReadReq(req);
+
+ // Record key MemReq parameters so we can generate another one
+ // just like it for the timing access without calling translate()
+ // again (which might mess up the TLB).
+ // Do I ever really need this? -KTL 3/05
+ effAddr = req->vaddr;
+ physEffAddr = req->paddr;
+ memReqFlags = req->flags;
+
+ /**
+ * @todo
+ * Replace the disjoint functional memory with a unified one and remove
+ * this hack.
+ */
+#if !FULL_SYSTEM
+ req->paddr = req->vaddr;
+#endif
+
+ if (fault == NoFault) {
+ fault = cpu->read(req, data, lqIdx);
+ } else {
+ // Return a fixed value to keep simulation deterministic even
+ // along misspeculated paths.
+ data = (T)-1;
+ }
+
+ if (traceData) {
+ traceData->setAddr(addr);
+ traceData->setData(data);
+ }
+
+ return fault;
+}
+
+template<class Impl>
+template<class T>
+inline Fault
+BaseDynInst<Impl>::write(T data, Addr addr, unsigned flags, uint64_t *res)
+{
+ if (traceData) {
+ traceData->setAddr(addr);
+ traceData->setData(data);
+ }
+
+ MemReqPtr req = new MemReq(addr, cpuXC->getProxy(), sizeof(T), flags);
+
+ req->asid = asid;
+
+ fault = cpu->translateDataWriteReq(req);
+
+ // Record key MemReq parameters so we can generate another one
+ // just like it for the timing access without calling translate()
+ // again (which might mess up the TLB).
+ effAddr = req->vaddr;
+ physEffAddr = req->paddr;
+ memReqFlags = req->flags;
+
+ /**
+ * @todo
+ * Replace the disjoint functional memory with a unified one and remove
+ * this hack.
+ */
+#if !FULL_SYSTEM
+ req->paddr = req->vaddr;
+#endif
+
+ if (fault == NoFault) {
+ fault = cpu->write(req, data, sqIdx);
+ }
+
+ if (res) {
+ // always return some result to keep misspeculated paths
+ // (which will ignore faults) deterministic
+ *res = (fault == NoFault) ? req->result : 0;
+ }
+
+ return fault;
+}
+
+#endif // __CPU_BASE_DYN_INST_HH__
diff --git a/src/cpu/cpu_exec_context.cc b/src/cpu/cpu_exec_context.cc
new file mode 100644
index 000000000..ec1e94561
--- /dev/null
+++ b/src/cpu/cpu_exec_context.cc
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2001-2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string>
+
+#include "arch/isa_traits.hh"
+#include "cpu/base.hh"
+#include "cpu/cpu_exec_context.hh"
+#include "cpu/exec_context.hh"
+
+#if FULL_SYSTEM
+#include "base/callback.hh"
+#include "base/cprintf.hh"
+#include "base/output.hh"
+#include "base/trace.hh"
+#include "cpu/profile.hh"
+#include "kern/kernel_stats.hh"
+#include "sim/serialize.hh"
+#include "sim/sim_exit.hh"
+#include "arch/stacktrace.hh"
+#else
+#include "sim/process.hh"
+#include "sim/system.hh"
+#include "mem/translating_port.hh"
+#endif
+
+using namespace std;
+
+// constructor
+#if FULL_SYSTEM
+CPUExecContext::CPUExecContext(BaseCPU *_cpu, int _thread_num, System *_sys,
+ AlphaITB *_itb, AlphaDTB *_dtb)
+ : _status(ExecContext::Unallocated), cpu(_cpu), thread_num(_thread_num),
+ cpu_id(-1), lastActivate(0), lastSuspend(0), system(_sys), itb(_itb),
+ dtb(_dtb), profile(NULL), quiesceEvent(this), func_exe_inst(0),
+ storeCondFailures(0)
+
+{
+ proxy = new ProxyExecContext<CPUExecContext>(this);
+
+ regs.clear();
+
+ if (cpu->params->profile) {
+ profile = new FunctionProfile(system->kernelSymtab);
+ Callback *cb =
+ new MakeCallback<CPUExecContext,
+ &CPUExecContext::dumpFuncProfile>(this);
+ registerExitCallback(cb);
+ }
+
+ // let's fill with a dummy node for now so we don't get a segfault
+ // on the first cycle when there's no node available.
+ static ProfileNode dummyNode;
+ profileNode = &dummyNode;
+ profilePC = 3;
+
+ Port *mem_port;
+ physPort = new FunctionalPort();
+ mem_port = system->physmem->getPort("functional");
+ mem_port->setPeer(physPort);
+ physPort->setPeer(mem_port);
+
+ virtPort = new VirtualPort();
+ mem_port = system->physmem->getPort("functional");
+ mem_port->setPeer(virtPort);
+ virtPort->setPeer(mem_port);
+}
+#else
+CPUExecContext::CPUExecContext(BaseCPU *_cpu, int _thread_num,
+ Process *_process, int _asid, MemObject* memobj)
+ : _status(ExecContext::Unallocated),
+ cpu(_cpu), thread_num(_thread_num), cpu_id(-1), lastActivate(0),
+ lastSuspend(0), process(_process), asid(_asid),
+ func_exe_inst(0), storeCondFailures(0)
+{
+ /* Use this port to for syscall emulation writes to memory. */
+ Port *mem_port;
+ port = new TranslatingPort(process->pTable, false);
+ mem_port = memobj->getPort("functional");
+ mem_port->setPeer(port);
+ port->setPeer(mem_port);
+
+ regs.clear();
+ proxy = new ProxyExecContext<CPUExecContext>(this);
+}
+
+CPUExecContext::CPUExecContext(RegFile *regFile)
+ : cpu(NULL), thread_num(-1), process(NULL), asid(-1),
+ func_exe_inst(0), storeCondFailures(0)
+{
+ regs = *regFile;
+ proxy = new ProxyExecContext<CPUExecContext>(this);
+}
+
+#endif
+
+CPUExecContext::~CPUExecContext()
+{
+ delete proxy;
+}
+
+#if FULL_SYSTEM
+void
+CPUExecContext::dumpFuncProfile()
+{
+ std::ostream *os = simout.create(csprintf("profile.%s.dat", cpu->name()));
+ profile->dump(proxy, *os);
+}
+
+CPUExecContext::EndQuiesceEvent::EndQuiesceEvent(CPUExecContext *_cpuXC)
+ : Event(&mainEventQueue), cpuXC(_cpuXC)
+{
+}
+
+void
+CPUExecContext::EndQuiesceEvent::process()
+{
+ cpuXC->activate();
+}
+
+const char*
+CPUExecContext::EndQuiesceEvent::description()
+{
+ return "End Quiesce Event.";
+}
+
+void
+CPUExecContext::profileClear()
+{
+ if (profile)
+ profile->clear();
+}
+
+void
+CPUExecContext::profileSample()
+{
+ if (profile)
+ profile->sample(profileNode, profilePC);
+}
+
+#endif
+
+void
+CPUExecContext::takeOverFrom(ExecContext *oldContext)
+{
+ // some things should already be set up
+#if FULL_SYSTEM
+ assert(system == oldContext->getSystemPtr());
+#else
+ assert(process == oldContext->getProcessPtr());
+#endif
+
+ // copy over functional state
+ _status = oldContext->status();
+ copyArchRegs(oldContext);
+ cpu_id = oldContext->readCpuId();
+#if !FULL_SYSTEM
+ func_exe_inst = oldContext->readFuncExeInst();
+#endif
+
+ storeCondFailures = 0;
+
+ oldContext->setStatus(ExecContext::Unallocated);
+}
+
+void
+CPUExecContext::serialize(ostream &os)
+{
+ SERIALIZE_ENUM(_status);
+ regs.serialize(os);
+ // thread_num and cpu_id are deterministic from the config
+ SERIALIZE_SCALAR(func_exe_inst);
+ SERIALIZE_SCALAR(inst);
+
+#if FULL_SYSTEM
+ Tick quiesceEndTick = 0;
+ if (quiesceEvent.scheduled())
+ quiesceEndTick = quiesceEvent.when();
+ SERIALIZE_SCALAR(quiesceEndTick);
+
+#endif
+}
+
+
+void
+CPUExecContext::unserialize(Checkpoint *cp, const std::string &section)
+{
+ UNSERIALIZE_ENUM(_status);
+ regs.unserialize(cp, section);
+ // thread_num and cpu_id are deterministic from the config
+ UNSERIALIZE_SCALAR(func_exe_inst);
+ UNSERIALIZE_SCALAR(inst);
+
+#if FULL_SYSTEM
+ Tick quiesceEndTick;
+ UNSERIALIZE_SCALAR(quiesceEndTick);
+ if (quiesceEndTick)
+ quiesceEvent.schedule(quiesceEndTick);
+#endif
+}
+
+
+void
+CPUExecContext::activate(int delay)
+{
+ if (status() == ExecContext::Active)
+ return;
+
+ lastActivate = curTick;
+
+ _status = ExecContext::Active;
+ cpu->activateContext(thread_num, delay);
+}
+
+void
+CPUExecContext::suspend()
+{
+ if (status() == ExecContext::Suspended)
+ return;
+
+ lastActivate = curTick;
+ lastSuspend = curTick;
+/*
+#if FULL_SYSTEM
+ // Don't change the status from active if there are pending interrupts
+ if (cpu->check_interrupts()) {
+ assert(status() == ExecContext::Active);
+ return;
+ }
+#endif
+*/
+ _status = ExecContext::Suspended;
+ cpu->suspendContext(thread_num);
+}
+
+void
+CPUExecContext::deallocate()
+{
+ if (status() == ExecContext::Unallocated)
+ return;
+
+ _status = ExecContext::Unallocated;
+ cpu->deallocateContext(thread_num);
+}
+
+void
+CPUExecContext::halt()
+{
+ if (status() == ExecContext::Halted)
+ return;
+
+ _status = ExecContext::Halted;
+ cpu->haltContext(thread_num);
+}
+
+
+void
+CPUExecContext::regStats(const string &name)
+{
+}
+
+void
+CPUExecContext::copyArchRegs(ExecContext *xc)
+{
+ TheISA::copyRegs(xc, proxy);
+}
+
+#if FULL_SYSTEM
+VirtualPort*
+CPUExecContext::getVirtPort(ExecContext *xc)
+{
+ if (!xc)
+ return virtPort;
+
+ VirtualPort *vp;
+ Port *mem_port;
+
+ vp = new VirtualPort(xc);
+ mem_port = system->physmem->getPort("functional");
+ mem_port->setPeer(vp);
+ vp->setPeer(mem_port);
+ return vp;
+}
+
+void
+CPUExecContext::delVirtPort(VirtualPort *vp)
+{
+// assert(!vp->nullExecContext());
+ delete vp->getPeer();
+ delete vp;
+}
+
+
+#endif
+
diff --git a/src/cpu/cpu_exec_context.hh b/src/cpu/cpu_exec_context.hh
new file mode 100644
index 000000000..2c06a7b3b
--- /dev/null
+++ b/src/cpu/cpu_exec_context.hh
@@ -0,0 +1,546 @@
+/*
+ * Copyright (c) 2001-2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPU_CPU_EXEC_CONTEXT_HH__
+#define __CPU_CPU_EXEC_CONTEXT_HH__
+
+#include "arch/isa_traits.hh"
+#include "config/full_system.hh"
+#include "cpu/exec_context.hh"
+#include "mem/physical.hh"
+#include "mem/request.hh"
+#include "sim/byteswap.hh"
+#include "sim/eventq.hh"
+#include "sim/host.hh"
+#include "sim/serialize.hh"
+
+class BaseCPU;
+
+#if FULL_SYSTEM
+
+#include "sim/system.hh"
+#include "arch/tlb.hh"
+
+class FunctionProfile;
+class ProfileNode;
+class FunctionalPort;
+class PhysicalPort;
+
+
+#else // !FULL_SYSTEM
+
+#include "sim/process.hh"
+#include "mem/page_table.hh"
+class TranslatingPort;
+
+
+#endif // FULL_SYSTEM
+
+//
+// The CPUExecContext object represents a functional context for
+// instruction execution. It incorporates everything required for
+// architecture-level functional simulation of a single thread.
+//
+
+class CPUExecContext
+{
+ protected:
+ typedef TheISA::RegFile RegFile;
+ typedef TheISA::MachInst MachInst;
+ typedef TheISA::MiscRegFile MiscRegFile;
+ typedef TheISA::MiscReg MiscReg;
+ typedef TheISA::FloatReg FloatReg;
+ typedef TheISA::FloatRegBits FloatRegBits;
+ public:
+ typedef ExecContext::Status Status;
+
+ private:
+ Status _status;
+
+ public:
+ Status status() const { return _status; }
+
+ void setStatus(Status newStatus) { _status = newStatus; }
+
+ /// Set the status to Active. Optional delay indicates number of
+ /// cycles to wait before beginning execution.
+ void activate(int delay = 1);
+
+ /// Set the status to Suspended.
+ void suspend();
+
+ /// Set the status to Unallocated.
+ void deallocate();
+
+ /// Set the status to Halted.
+ void halt();
+
+ protected:
+ RegFile regs; // correct-path register context
+
+ public:
+ // pointer to CPU associated with this context
+ BaseCPU *cpu;
+
+ ProxyExecContext<CPUExecContext> *proxy;
+
+ // Current instruction
+ MachInst inst;
+
+ // Index of hardware thread context on the CPU that this represents.
+ int thread_num;
+
+ // ID of this context w.r.t. the System or Process object to which
+ // it belongs. For full-system mode, this is the system CPU ID.
+ int cpu_id;
+
+ Tick lastActivate;
+ Tick lastSuspend;
+
+ System *system;
+
+
+#if FULL_SYSTEM
+ AlphaITB *itb;
+ AlphaDTB *dtb;
+
+ /** A functional port outgoing only for functional accesses to physical
+ * addresses.*/
+ FunctionalPort *physPort;
+
+ /** A functional port, outgoing only, for functional accesse to virtual
+ * addresses. That doen't require execution context information */
+ VirtualPort *virtPort;
+
+ FunctionProfile *profile;
+ ProfileNode *profileNode;
+ Addr profilePC;
+ void dumpFuncProfile();
+
+ /** Event for timing out quiesce instruction */
+ struct EndQuiesceEvent : public Event
+ {
+ /** A pointer to the execution context that is quiesced */
+ CPUExecContext *cpuXC;
+
+ EndQuiesceEvent(CPUExecContext *_cpuXC);
+
+ /** Event process to occur at interrupt*/
+ virtual void process();
+
+ /** Event description */
+ virtual const char *description();
+ };
+ EndQuiesceEvent quiesceEvent;
+
+ Event *getQuiesceEvent() { return &quiesceEvent; }
+
+ Tick readLastActivate() { return lastActivate; }
+
+ Tick readLastSuspend() { return lastSuspend; }
+
+ void profileClear();
+
+ void profileSample();
+
+#else
+ /// Port that syscalls can use to access memory (provides translation step).
+ TranslatingPort *port;
+
+ Process *process;
+
+ // Address space ID. Note that this is used for TIMING cache
+ // simulation only; all functional memory accesses should use
+ // one of the FunctionalMemory pointers above.
+ short asid;
+
+#endif
+
+ /**
+ * Temporary storage to pass the source address from copy_load to
+ * copy_store.
+ * @todo Remove this temporary when we have a better way to do it.
+ */
+ Addr copySrcAddr;
+ /**
+ * Temp storage for the physical source address of a copy.
+ * @todo Remove this temporary when we have a better way to do it.
+ */
+ Addr copySrcPhysAddr;
+
+
+ /*
+ * number of executed instructions, for matching with syscall trace
+ * points in EIO files.
+ */
+ Counter func_exe_inst;
+
+ //
+ // Count failed store conditionals so we can warn of apparent
+ // application deadlock situations.
+ unsigned storeCondFailures;
+
+ // constructor: initialize context from given process structure
+#if FULL_SYSTEM
+ CPUExecContext(BaseCPU *_cpu, int _thread_num, System *_system,
+ AlphaITB *_itb, AlphaDTB *_dtb);
+#else
+ CPUExecContext(BaseCPU *_cpu, int _thread_num, Process *_process, int _asid,
+ MemObject *memobj);
+ // Constructor to use XC to pass reg file around. Not used for anything
+ // else.
+ CPUExecContext(RegFile *regFile);
+#endif
+ virtual ~CPUExecContext();
+
+ virtual void takeOverFrom(ExecContext *oldContext);
+
+ void regStats(const std::string &name);
+
+ void serialize(std::ostream &os);
+ void unserialize(Checkpoint *cp, const std::string &section);
+
+ BaseCPU *getCpuPtr() { return cpu; }
+
+ ExecContext *getProxy() { return proxy; }
+
+ int getThreadNum() { return thread_num; }
+
+#if FULL_SYSTEM
+ System *getSystemPtr() { return system; }
+
+ AlphaITB *getITBPtr() { return itb; }
+
+ AlphaDTB *getDTBPtr() { return dtb; }
+
+ int getInstAsid() { return regs.instAsid(); }
+ int getDataAsid() { return regs.dataAsid(); }
+
+ Fault translateInstReq(RequestPtr &req)
+ {
+ return itb->translate(req, proxy);
+ }
+
+ Fault translateDataReadReq(RequestPtr &req)
+ {
+ return dtb->translate(req, proxy, false);
+ }
+
+ Fault translateDataWriteReq(RequestPtr &req)
+ {
+ return dtb->translate(req, proxy, true);
+ }
+
+ FunctionalPort *getPhysPort() { return physPort; }
+
+ /** Return a virtual port. If no exec context is specified then a static
+ * port is returned. Otherwise a port is created and returned. It must be
+ * deleted by deleteVirtPort(). */
+ VirtualPort *getVirtPort(ExecContext *xc);
+
+ void delVirtPort(VirtualPort *vp);
+
+#else
+ TranslatingPort *getMemPort() { return port; }
+
+ Process *getProcessPtr() { return process; }
+
+ int getInstAsid() { return asid; }
+ int getDataAsid() { return asid; }
+
+ Fault translateInstReq(RequestPtr &req)
+ {
+ return process->pTable->translate(req);
+ }
+
+ Fault translateDataReadReq(RequestPtr &req)
+ {
+ return process->pTable->translate(req);
+ }
+
+ Fault translateDataWriteReq(RequestPtr &req)
+ {
+ return process->pTable->translate(req);
+ }
+
+#endif
+
+/*
+ template <class T>
+ Fault read(RequestPtr &req, T &data)
+ {
+#if FULL_SYSTEM && THE_ISA == ALPHA_ISA
+ if (req->flags & LOCKED) {
+ req->xc->setMiscReg(TheISA::Lock_Addr_DepTag, req->paddr);
+ req->xc->setMiscReg(TheISA::Lock_Flag_DepTag, true);
+ }
+#endif
+
+ Fault error;
+ error = mem->prot_read(req->paddr, data, req->size);
+ data = LittleEndianGuest::gtoh(data);
+ return error;
+ }
+
+ template <class T>
+ Fault write(RequestPtr &req, T &data)
+ {
+#if FULL_SYSTEM && THE_ISA == ALPHA_ISA
+ ExecContext *xc;
+
+ // If this is a store conditional, act appropriately
+ if (req->flags & LOCKED) {
+ xc = req->xc;
+
+ if (req->flags & UNCACHEABLE) {
+ // Don't update result register (see stq_c in isa_desc)
+ req->result = 2;
+ xc->setStCondFailures(0);//Needed? [RGD]
+ } else {
+ bool lock_flag = xc->readMiscReg(TheISA::Lock_Flag_DepTag);
+ Addr lock_addr = xc->readMiscReg(TheISA::Lock_Addr_DepTag);
+ req->result = lock_flag;
+ if (!lock_flag ||
+ ((lock_addr & ~0xf) != (req->paddr & ~0xf))) {
+ xc->setMiscReg(TheISA::Lock_Flag_DepTag, false);
+ xc->setStCondFailures(xc->readStCondFailures() + 1);
+ if (((xc->readStCondFailures()) % 100000) == 0) {
+ std::cerr << "Warning: "
+ << xc->readStCondFailures()
+ << " consecutive store conditional failures "
+ << "on cpu " << req->xc->readCpuId()
+ << std::endl;
+ }
+ return NoFault;
+ }
+ else xc->setStCondFailures(0);
+ }
+ }
+
+ // Need to clear any locked flags on other proccessors for
+ // this address. Only do this for succsful Store Conditionals
+ // and all other stores (WH64?). Unsuccessful Store
+ // Conditionals would have returned above, and wouldn't fall
+ // through.
+ for (int i = 0; i < system->execContexts.size(); i++){
+ xc = system->execContexts[i];
+ if ((xc->readMiscReg(TheISA::Lock_Addr_DepTag) & ~0xf) ==
+ (req->paddr & ~0xf)) {
+ xc->setMiscReg(TheISA::Lock_Flag_DepTag, false);
+ }
+ }
+
+#endif
+ return mem->prot_write(req->paddr, (T)htog(data), req->size);
+ }
+*/
+ virtual bool misspeculating();
+
+
+ MachInst getInst() { return inst; }
+
+ void setInst(MachInst new_inst)
+ {
+ inst = new_inst;
+ }
+
+ Fault instRead(RequestPtr &req)
+ {
+ panic("instRead not implemented");
+ // return funcPhysMem->read(req, inst);
+ return NoFault;
+ }
+
+ void setCpuId(int id) { cpu_id = id; }
+
+ int readCpuId() { return cpu_id; }
+
+ void copyArchRegs(ExecContext *xc);
+
+ //
+ // New accessors for new decoder.
+ //
+ uint64_t readIntReg(int reg_idx)
+ {
+ return regs.readIntReg(reg_idx);
+ }
+
+ FloatReg readFloatReg(int reg_idx, int width)
+ {
+ return regs.readFloatReg(reg_idx, width);
+ }
+
+ FloatReg readFloatReg(int reg_idx)
+ {
+ return regs.readFloatReg(reg_idx);
+ }
+
+ FloatRegBits readFloatRegBits(int reg_idx, int width)
+ {
+ return regs.readFloatRegBits(reg_idx, width);
+ }
+
+ FloatRegBits readFloatRegBits(int reg_idx)
+ {
+ return regs.readFloatRegBits(reg_idx);
+ }
+
+ void setIntReg(int reg_idx, uint64_t val)
+ {
+ regs.setIntReg(reg_idx, val);
+ }
+
+ void setFloatReg(int reg_idx, FloatReg val, int width)
+ {
+ regs.setFloatReg(reg_idx, val, width);
+ }
+
+ void setFloatReg(int reg_idx, FloatReg val)
+ {
+ regs.setFloatReg(reg_idx, val);
+ }
+
+ void setFloatRegBits(int reg_idx, FloatRegBits val, int width)
+ {
+ regs.setFloatRegBits(reg_idx, val, width);
+ }
+
+ void setFloatRegBits(int reg_idx, FloatRegBits val)
+ {
+ regs.setFloatRegBits(reg_idx, val);
+ }
+
+ uint64_t readPC()
+ {
+ return regs.readPC();
+ }
+
+ void setPC(uint64_t val)
+ {
+ regs.setPC(val);
+ }
+
+ uint64_t readNextPC()
+ {
+ return regs.readNextPC();
+ }
+
+ void setNextPC(uint64_t val)
+ {
+ regs.setNextPC(val);
+ }
+
+ uint64_t readNextNPC()
+ {
+ return regs.readNextNPC();
+ }
+
+ void setNextNPC(uint64_t val)
+ {
+ regs.setNextNPC(val);
+ }
+
+
+ MiscReg readMiscReg(int misc_reg)
+ {
+ return regs.readMiscReg(misc_reg);
+ }
+
+ MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault)
+ {
+ return regs.readMiscRegWithEffect(misc_reg, fault, proxy);
+ }
+
+ Fault setMiscReg(int misc_reg, const MiscReg &val)
+ {
+ return regs.setMiscReg(misc_reg, val);
+ }
+
+ Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val)
+ {
+ return regs.setMiscRegWithEffect(misc_reg, val, proxy);
+ }
+
+ unsigned readStCondFailures() { return storeCondFailures; }
+
+ void setStCondFailures(unsigned sc_failures)
+ { storeCondFailures = sc_failures; }
+
+ void clearArchRegs() { regs.clear(); }
+
+#if FULL_SYSTEM
+ int readIntrFlag() { return regs.intrflag; }
+ void setIntrFlag(int val) { regs.intrflag = val; }
+ Fault hwrei();
+ bool inPalMode() { return AlphaISA::PcPAL(regs.readPC()); }
+ bool simPalCheck(int palFunc);
+#endif
+
+#if !FULL_SYSTEM
+ TheISA::IntReg getSyscallArg(int i)
+ {
+ return regs.readIntReg(TheISA::ArgumentReg0 + i);
+ }
+
+ // used to shift args for indirect syscall
+ void setSyscallArg(int i, TheISA::IntReg val)
+ {
+ regs.setIntReg(TheISA::ArgumentReg0 + i, val);
+ }
+
+ void setSyscallReturn(SyscallReturn return_value)
+ {
+ TheISA::setSyscallReturn(return_value, &regs);
+ }
+
+ void syscall(int64_t callnum)
+ {
+ process->syscall(callnum, proxy);
+ }
+
+ Counter readFuncExeInst() { return func_exe_inst; }
+
+ void setFuncExeInst(Counter new_val) { func_exe_inst = new_val; }
+#endif
+
+ void changeRegFileContext(RegFile::ContextParam param,
+ RegFile::ContextVal val)
+ {
+ regs.changeContext(param, val);
+ }
+};
+
+
+// for non-speculative execution context, spec_mode is always false
+inline bool
+CPUExecContext::misspeculating()
+{
+ return false;
+}
+
+#endif // __CPU_CPU_EXEC_CONTEXT_HH__
diff --git a/src/cpu/cpu_models.py b/src/cpu/cpu_models.py
new file mode 100644
index 000000000..30cbabde1
--- /dev/null
+++ b/src/cpu/cpu_models.py
@@ -0,0 +1,74 @@
+# Copyright (c) 2003-2006 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+################
+# CpuModel class
+#
+# The CpuModel class encapsulates everything the ISA parser needs to
+# know about a particular CPU model.
+
+class CpuModel:
+ # Dict of available CPU model objects. Accessible as CpuModel.dict.
+ dict = {}
+
+ # Constructor. Automatically adds models to CpuModel.dict.
+ def __init__(self, name, filename, includes, strings):
+ self.name = name
+ self.filename = filename # filename for output exec code
+ self.includes = includes # include files needed in exec file
+ # The 'strings' dict holds all the per-CPU symbols we can
+ # substitute into templates etc.
+ self.strings = strings
+ # Add self to dict
+ CpuModel.dict[name] = self
+
+
+#
+# Define CPU models.
+#
+# Parameters are:
+# - name of model
+# - filename for generated ISA execution file
+# - includes needed for generated ISA execution file
+# - substitution strings for ISA description templates
+#
+
+CpuModel('AtomicSimpleCPU', 'atomic_simple_cpu_exec.cc',
+ '#include "cpu/simple/atomic.hh"',
+ { 'CPU_exec_context': 'AtomicSimpleCPU' })
+CpuModel('TimingSimpleCPU', 'timing_simple_cpu_exec.cc',
+ '#include "cpu/simple/timing.hh"',
+ { 'CPU_exec_context': 'TimingSimpleCPU' })
+CpuModel('FastCPU', 'fast_cpu_exec.cc',
+ '#include "cpu/fast/cpu.hh"',
+ { 'CPU_exec_context': 'FastCPU' })
+CpuModel('FullCPU', 'full_cpu_exec.cc',
+ '#include "encumbered/cpu/full/dyn_inst.hh"',
+ { 'CPU_exec_context': 'DynInst' })
+CpuModel('AlphaFullCPU', 'alpha_o3_exec.cc',
+ '#include "cpu/o3/alpha_dyn_inst.hh"',
+ { 'CPU_exec_context': 'AlphaDynInst<AlphaSimpleImpl>' })
+
diff --git a/src/cpu/exec_context.hh b/src/cpu/exec_context.hh
new file mode 100644
index 000000000..1f26183ab
--- /dev/null
+++ b/src/cpu/exec_context.hh
@@ -0,0 +1,450 @@
+/*
+ * Copyright (c) 2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPU_EXEC_CONTEXT_HH__
+#define __CPU_EXEC_CONTEXT_HH__
+
+#include "config/full_system.hh"
+#include "mem/request.hh"
+#include "sim/faults.hh"
+#include "sim/host.hh"
+#include "sim/serialize.hh"
+#include "sim/byteswap.hh"
+
+// @todo: Figure out a more architecture independent way to obtain the ITB and
+// DTB pointers.
+class AlphaDTB;
+class AlphaITB;
+class BaseCPU;
+class Event;
+class TranslatingPort;
+class FunctionalPort;
+class VirtualPort;
+class Process;
+class System;
+
+class ExecContext
+{
+ protected:
+ typedef TheISA::RegFile RegFile;
+ typedef TheISA::MachInst MachInst;
+ typedef TheISA::IntReg IntReg;
+ typedef TheISA::FloatReg FloatReg;
+ typedef TheISA::FloatRegBits FloatRegBits;
+ typedef TheISA::MiscRegFile MiscRegFile;
+ typedef TheISA::MiscReg MiscReg;
+ public:
+ enum Status
+ {
+ /// Initialized but not running yet. All CPUs start in
+ /// this state, but most transition to Active on cycle 1.
+ /// In MP or SMT systems, non-primary contexts will stay
+ /// in this state until a thread is assigned to them.
+ Unallocated,
+
+ /// Running. Instructions should be executed only when
+ /// the context is in this state.
+ Active,
+
+ /// Temporarily inactive. Entered while waiting for
+ /// synchronization, etc.
+ Suspended,
+
+ /// Permanently shut down. Entered when target executes
+ /// m5exit pseudo-instruction. When all contexts enter
+ /// this state, the simulation will terminate.
+ Halted
+ };
+
+ virtual ~ExecContext() { };
+
+ virtual BaseCPU *getCpuPtr() = 0;
+
+ virtual void setCpuId(int id) = 0;
+
+ virtual int readCpuId() = 0;
+
+#if FULL_SYSTEM
+ virtual System *getSystemPtr() = 0;
+
+ virtual AlphaITB *getITBPtr() = 0;
+
+ virtual AlphaDTB * getDTBPtr() = 0;
+
+ virtual FunctionalPort *getPhysPort() = 0;
+
+ virtual VirtualPort *getVirtPort(ExecContext *xc = NULL) = 0;
+
+ virtual void delVirtPort(VirtualPort *vp) = 0;
+#else
+ virtual TranslatingPort *getMemPort() = 0;
+
+ virtual Process *getProcessPtr() = 0;
+#endif
+
+ virtual Status status() const = 0;
+
+ virtual void setStatus(Status new_status) = 0;
+
+ /// Set the status to Active. Optional delay indicates number of
+ /// cycles to wait before beginning execution.
+ virtual void activate(int delay = 1) = 0;
+
+ /// Set the status to Suspended.
+ virtual void suspend() = 0;
+
+ /// Set the status to Unallocated.
+ virtual void deallocate() = 0;
+
+ /// Set the status to Halted.
+ virtual void halt() = 0;
+
+#if FULL_SYSTEM
+ virtual void dumpFuncProfile() = 0;
+#endif
+
+ virtual void takeOverFrom(ExecContext *old_context) = 0;
+
+ virtual void regStats(const std::string &name) = 0;
+
+ virtual void serialize(std::ostream &os) = 0;
+ virtual void unserialize(Checkpoint *cp, const std::string &section) = 0;
+
+#if FULL_SYSTEM
+ virtual Event *getQuiesceEvent() = 0;
+
+ // Not necessarily the best location for these...
+ // Having an extra function just to read these is obnoxious
+ virtual Tick readLastActivate() = 0;
+ virtual Tick readLastSuspend() = 0;
+
+ virtual void profileClear() = 0;
+ virtual void profileSample() = 0;
+#endif
+
+ virtual int getThreadNum() = 0;
+
+ virtual int getInstAsid() = 0;
+ virtual int getDataAsid() = 0;
+
+ virtual Fault translateInstReq(RequestPtr &req) = 0;
+
+ virtual Fault translateDataReadReq(RequestPtr &req) = 0;
+
+ virtual Fault translateDataWriteReq(RequestPtr &req) = 0;
+
+ // Also somewhat obnoxious. Really only used for the TLB fault.
+ // However, may be quite useful in SPARC.
+ virtual TheISA::MachInst getInst() = 0;
+
+ virtual void copyArchRegs(ExecContext *xc) = 0;
+
+ virtual void clearArchRegs() = 0;
+
+ //
+ // New accessors for new decoder.
+ //
+ virtual uint64_t readIntReg(int reg_idx) = 0;
+
+ virtual FloatReg readFloatReg(int reg_idx, int width) = 0;
+
+ virtual FloatReg readFloatReg(int reg_idx) = 0;
+
+ virtual FloatRegBits readFloatRegBits(int reg_idx, int width) = 0;
+
+ virtual FloatRegBits readFloatRegBits(int reg_idx) = 0;
+
+ virtual void setIntReg(int reg_idx, uint64_t val) = 0;
+
+ virtual void setFloatReg(int reg_idx, FloatReg val, int width) = 0;
+
+ virtual void setFloatReg(int reg_idx, FloatReg val) = 0;
+
+ virtual void setFloatRegBits(int reg_idx, FloatRegBits val) = 0;
+
+ virtual void setFloatRegBits(int reg_idx, FloatRegBits val, int width) = 0;
+
+ virtual uint64_t readPC() = 0;
+
+ virtual void setPC(uint64_t val) = 0;
+
+ virtual uint64_t readNextPC() = 0;
+
+ virtual void setNextPC(uint64_t val) = 0;
+
+ virtual uint64_t readNextNPC() = 0;
+
+ virtual void setNextNPC(uint64_t val) = 0;
+
+ virtual MiscReg readMiscReg(int misc_reg) = 0;
+
+ virtual MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) = 0;
+
+ virtual Fault setMiscReg(int misc_reg, const MiscReg &val) = 0;
+
+ virtual Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) = 0;
+
+ // Also not necessarily the best location for these two. Hopefully will go
+ // away once we decide upon where st cond failures goes.
+ virtual unsigned readStCondFailures() = 0;
+
+ virtual void setStCondFailures(unsigned sc_failures) = 0;
+
+#if FULL_SYSTEM
+ virtual int readIntrFlag() = 0;
+ virtual void setIntrFlag(int val) = 0;
+ virtual Fault hwrei() = 0;
+ virtual bool inPalMode() = 0;
+ virtual bool simPalCheck(int palFunc) = 0;
+#endif
+
+ // Only really makes sense for old CPU model. Still could be useful though.
+ virtual bool misspeculating() = 0;
+
+#if !FULL_SYSTEM
+ virtual IntReg getSyscallArg(int i) = 0;
+
+ // used to shift args for indirect syscall
+ virtual void setSyscallArg(int i, IntReg val) = 0;
+
+ virtual void setSyscallReturn(SyscallReturn return_value) = 0;
+
+ virtual void syscall(int64_t callnum) = 0;
+
+ // Same with st cond failures.
+ virtual Counter readFuncExeInst() = 0;
+
+ virtual void setFuncExeInst(Counter new_val) = 0;
+#endif
+
+ virtual void changeRegFileContext(RegFile::ContextParam param,
+ RegFile::ContextVal val) = 0;
+};
+
+template <class XC>
+class ProxyExecContext : public ExecContext
+{
+ public:
+ ProxyExecContext(XC *actual_xc)
+ { actualXC = actual_xc; }
+
+ private:
+ XC *actualXC;
+
+ public:
+
+ BaseCPU *getCpuPtr() { return actualXC->getCpuPtr(); }
+
+ void setCpuId(int id) { actualXC->setCpuId(id); }
+
+ int readCpuId() { return actualXC->readCpuId(); }
+
+#if FULL_SYSTEM
+ System *getSystemPtr() { return actualXC->getSystemPtr(); }
+
+ AlphaITB *getITBPtr() { return actualXC->getITBPtr(); }
+
+ AlphaDTB *getDTBPtr() { return actualXC->getDTBPtr(); }
+
+ FunctionalPort *getPhysPort() { return actualXC->getPhysPort(); }
+
+ VirtualPort *getVirtPort(ExecContext *xc = NULL) { return actualXC->getVirtPort(xc); }
+
+ void delVirtPort(VirtualPort *vp) { return actualXC->delVirtPort(vp); }
+#else
+ TranslatingPort *getMemPort() { return actualXC->getMemPort(); }
+
+ Process *getProcessPtr() { return actualXC->getProcessPtr(); }
+#endif
+
+ Status status() const { return actualXC->status(); }
+
+ void setStatus(Status new_status) { actualXC->setStatus(new_status); }
+
+ /// Set the status to Active. Optional delay indicates number of
+ /// cycles to wait before beginning execution.
+ void activate(int delay = 1) { actualXC->activate(delay); }
+
+ /// Set the status to Suspended.
+ void suspend() { actualXC->suspend(); }
+
+ /// Set the status to Unallocated.
+ void deallocate() { actualXC->deallocate(); }
+
+ /// Set the status to Halted.
+ void halt() { actualXC->halt(); }
+
+#if FULL_SYSTEM
+ void dumpFuncProfile() { actualXC->dumpFuncProfile(); }
+#endif
+
+ void takeOverFrom(ExecContext *oldContext)
+ { actualXC->takeOverFrom(oldContext); }
+
+ void regStats(const std::string &name) { actualXC->regStats(name); }
+
+ void serialize(std::ostream &os) { actualXC->serialize(os); }
+ void unserialize(Checkpoint *cp, const std::string &section)
+ { actualXC->unserialize(cp, section); }
+
+#if FULL_SYSTEM
+ Event *getQuiesceEvent() { return actualXC->getQuiesceEvent(); }
+
+ Tick readLastActivate() { return actualXC->readLastActivate(); }
+ Tick readLastSuspend() { return actualXC->readLastSuspend(); }
+
+ void profileClear() { return actualXC->profileClear(); }
+ void profileSample() { return actualXC->profileSample(); }
+#endif
+
+ int getThreadNum() { return actualXC->getThreadNum(); }
+
+ int getInstAsid() { return actualXC->getInstAsid(); }
+ int getDataAsid() { return actualXC->getDataAsid(); }
+
+ Fault translateInstReq(RequestPtr &req)
+ { return actualXC->translateInstReq(req); }
+
+ Fault translateDataReadReq(RequestPtr &req)
+ { return actualXC->translateDataReadReq(req); }
+
+ Fault translateDataWriteReq(RequestPtr &req)
+ { return actualXC->translateDataWriteReq(req); }
+
+ // @todo: Do I need this?
+ MachInst getInst() { return actualXC->getInst(); }
+
+ // @todo: Do I need this?
+ void copyArchRegs(ExecContext *xc) { actualXC->copyArchRegs(xc); }
+
+ void clearArchRegs() { actualXC->clearArchRegs(); }
+
+ //
+ // New accessors for new decoder.
+ //
+ uint64_t readIntReg(int reg_idx)
+ { return actualXC->readIntReg(reg_idx); }
+
+ FloatReg readFloatReg(int reg_idx, int width)
+ { return actualXC->readFloatReg(reg_idx, width); }
+
+ FloatReg readFloatReg(int reg_idx)
+ { return actualXC->readFloatReg(reg_idx); }
+
+ FloatRegBits readFloatRegBits(int reg_idx, int width)
+ { return actualXC->readFloatRegBits(reg_idx, width); }
+
+ FloatRegBits readFloatRegBits(int reg_idx)
+ { return actualXC->readFloatRegBits(reg_idx); }
+
+ void setIntReg(int reg_idx, uint64_t val)
+ { actualXC->setIntReg(reg_idx, val); }
+
+ void setFloatReg(int reg_idx, FloatReg val, int width)
+ { actualXC->setFloatReg(reg_idx, val, width); }
+
+ void setFloatReg(int reg_idx, FloatReg val)
+ { actualXC->setFloatReg(reg_idx, val); }
+
+ void setFloatRegBits(int reg_idx, FloatRegBits val, int width)
+ { actualXC->setFloatRegBits(reg_idx, val, width); }
+
+ void setFloatRegBits(int reg_idx, FloatRegBits val)
+ { actualXC->setFloatRegBits(reg_idx, val); }
+
+ uint64_t readPC() { return actualXC->readPC(); }
+
+ void setPC(uint64_t val) { actualXC->setPC(val); }
+
+ uint64_t readNextPC() { return actualXC->readNextPC(); }
+
+ void setNextPC(uint64_t val) { actualXC->setNextPC(val); }
+
+ uint64_t readNextNPC() { return actualXC->readNextNPC(); }
+
+ void setNextNPC(uint64_t val) { actualXC->setNextNPC(val); }
+
+ MiscReg readMiscReg(int misc_reg)
+ { return actualXC->readMiscReg(misc_reg); }
+
+ MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault)
+ { return actualXC->readMiscRegWithEffect(misc_reg, fault); }
+
+ Fault setMiscReg(int misc_reg, const MiscReg &val)
+ { return actualXC->setMiscReg(misc_reg, val); }
+
+ Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val)
+ { return actualXC->setMiscRegWithEffect(misc_reg, val); }
+
+ unsigned readStCondFailures()
+ { return actualXC->readStCondFailures(); }
+
+ void setStCondFailures(unsigned sc_failures)
+ { actualXC->setStCondFailures(sc_failures); }
+
+#if FULL_SYSTEM
+ int readIntrFlag() { return actualXC->readIntrFlag(); }
+
+ void setIntrFlag(int val) { actualXC->setIntrFlag(val); }
+
+ Fault hwrei() { return actualXC->hwrei(); }
+
+ bool inPalMode() { return actualXC->inPalMode(); }
+
+ bool simPalCheck(int palFunc) { return actualXC->simPalCheck(palFunc); }
+#endif
+
+ // @todo: Fix this!
+ bool misspeculating() { return actualXC->misspeculating(); }
+
+#if !FULL_SYSTEM
+ IntReg getSyscallArg(int i) { return actualXC->getSyscallArg(i); }
+
+ // used to shift args for indirect syscall
+ void setSyscallArg(int i, IntReg val)
+ { actualXC->setSyscallArg(i, val); }
+
+ void setSyscallReturn(SyscallReturn return_value)
+ { actualXC->setSyscallReturn(return_value); }
+
+ void syscall(int64_t callnum) { actualXC->syscall(callnum); }
+
+ Counter readFuncExeInst() { return actualXC->readFuncExeInst(); }
+
+ void setFuncExeInst(Counter new_val)
+ { return actualXC->setFuncExeInst(new_val); }
+#endif
+
+ void changeRegFileContext(RegFile::ContextParam param,
+ RegFile::ContextVal val)
+ {
+ actualXC->changeRegFileContext(param, val);
+ }
+};
+
+#endif
diff --git a/src/cpu/exetrace.cc b/src/cpu/exetrace.cc
new file mode 100644
index 000000000..0ed3b43c4
--- /dev/null
+++ b/src/cpu/exetrace.cc
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <fstream>
+#include <iomanip>
+
+#include "base/loader/symtab.hh"
+#include "cpu/base.hh"
+#include "cpu/exetrace.hh"
+#include "cpu/static_inst.hh"
+#include "sim/param.hh"
+#include "sim/system.hh"
+
+using namespace std;
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Methods for the InstRecord object
+//
+
+
+void
+Trace::InstRecord::dump(ostream &outs)
+{
+ if (flags[INTEL_FORMAT]) {
+#if FULL_SYSTEM
+ bool is_trace_system = (cpu->system->name() == trace_system);
+#else
+ bool is_trace_system = true;
+#endif
+ if (is_trace_system) {
+ ccprintf(outs, "%7d ) ", cycle);
+ outs << "0x" << hex << PC << ":\t";
+ if (staticInst->isLoad()) {
+ outs << "<RD 0x" << hex << addr;
+ outs << ">";
+ } else if (staticInst->isStore()) {
+ outs << "<WR 0x" << hex << addr;
+ outs << ">";
+ }
+ outs << endl;
+ }
+ } else {
+ if (flags[PRINT_CYCLE])
+ ccprintf(outs, "%7d: ", cycle);
+
+ outs << cpu->name() << " ";
+
+ if (flags[TRACE_MISSPEC])
+ outs << (misspeculating ? "-" : "+") << " ";
+
+ if (flags[PRINT_THREAD_NUM])
+ outs << "T" << thread << " : ";
+
+
+ std::string sym_str;
+ Addr sym_addr;
+ if (debugSymbolTable
+ && debugSymbolTable->findNearestSymbol(PC, sym_str, sym_addr)) {
+ if (PC != sym_addr)
+ sym_str += csprintf("+%d", PC - sym_addr);
+ outs << "@" << sym_str << " : ";
+ }
+ else {
+ outs << "0x" << hex << PC << " : ";
+ }
+
+ //
+ // Print decoded instruction
+ //
+
+#if defined(__GNUC__) && (__GNUC__ < 3)
+ // There's a bug in gcc 2.x library that prevents setw()
+ // from working properly on strings
+ string mc(staticInst->disassemble(PC, debugSymbolTable));
+ while (mc.length() < 26)
+ mc += " ";
+ outs << mc;
+#else
+ outs << setw(26) << left << staticInst->disassemble(PC, debugSymbolTable);
+#endif
+
+ outs << " : ";
+
+ if (flags[PRINT_OP_CLASS]) {
+ outs << opClassStrings[staticInst->opClass()] << " : ";
+ }
+
+ if (flags[PRINT_RESULT_DATA] && data_status != DataInvalid) {
+ outs << " D=";
+#if 0
+ if (data_status == DataDouble)
+ ccprintf(outs, "%f", data.as_double);
+ else
+ ccprintf(outs, "%#018x", data.as_int);
+#else
+ ccprintf(outs, "%#018x", data.as_int);
+#endif
+ }
+
+ if (flags[PRINT_EFF_ADDR] && addr_valid)
+ outs << " A=0x" << hex << addr;
+
+ if (flags[PRINT_INT_REGS] && regs_valid) {
+ for (int i = 0; i < TheISA::NumIntRegs;)
+ for (int j = i + 1; i <= j; i++)
+ ccprintf(outs, "r%02d = %#018x%s", i,
+ iregs->regs.readReg(i),
+ ((i == j) ? "\n" : " "));
+ outs << "\n";
+ }
+
+ if (flags[PRINT_FETCH_SEQ] && fetch_seq_valid)
+ outs << " FetchSeq=" << dec << fetch_seq;
+
+ if (flags[PRINT_CP_SEQ] && cp_seq_valid)
+ outs << " CPSeq=" << dec << cp_seq;
+
+ //
+ // End of line...
+ //
+ outs << endl;
+ }
+}
+
+
+vector<bool> Trace::InstRecord::flags(NUM_BITS);
+string Trace::InstRecord::trace_system;
+
+////////////////////////////////////////////////////////////////////////
+//
+// Parameter space for per-cycle execution address tracing options.
+// Derive from ParamContext so we can override checkParams() function.
+//
+class ExecutionTraceParamContext : public ParamContext
+{
+ public:
+ ExecutionTraceParamContext(const string &_iniSection)
+ : ParamContext(_iniSection)
+ {
+ }
+
+ void checkParams(); // defined at bottom of file
+};
+
+ExecutionTraceParamContext exeTraceParams("exetrace");
+
+Param<bool> exe_trace_spec(&exeTraceParams, "speculative",
+ "capture speculative instructions", true);
+
+Param<bool> exe_trace_print_cycle(&exeTraceParams, "print_cycle",
+ "print cycle number", true);
+Param<bool> exe_trace_print_opclass(&exeTraceParams, "print_opclass",
+ "print op class", true);
+Param<bool> exe_trace_print_thread(&exeTraceParams, "print_thread",
+ "print thread number", true);
+Param<bool> exe_trace_print_effaddr(&exeTraceParams, "print_effaddr",
+ "print effective address", true);
+Param<bool> exe_trace_print_data(&exeTraceParams, "print_data",
+ "print result data", true);
+Param<bool> exe_trace_print_iregs(&exeTraceParams, "print_iregs",
+ "print all integer regs", false);
+Param<bool> exe_trace_print_fetchseq(&exeTraceParams, "print_fetchseq",
+ "print fetch sequence number", false);
+Param<bool> exe_trace_print_cp_seq(&exeTraceParams, "print_cpseq",
+ "print correct-path sequence number", false);
+Param<bool> exe_trace_intel_format(&exeTraceParams, "intel_format",
+ "print trace in intel compatible format", false);
+Param<string> exe_trace_system(&exeTraceParams, "trace_system",
+ "print trace of which system (client or server)",
+ "client");
+
+
+//
+// Helper function for ExecutionTraceParamContext::checkParams() just
+// to get us into the InstRecord namespace
+//
+void
+Trace::InstRecord::setParams()
+{
+ flags[TRACE_MISSPEC] = exe_trace_spec;
+
+ flags[PRINT_CYCLE] = exe_trace_print_cycle;
+ flags[PRINT_OP_CLASS] = exe_trace_print_opclass;
+ flags[PRINT_THREAD_NUM] = exe_trace_print_thread;
+ flags[PRINT_RESULT_DATA] = exe_trace_print_effaddr;
+ flags[PRINT_EFF_ADDR] = exe_trace_print_data;
+ flags[PRINT_INT_REGS] = exe_trace_print_iregs;
+ flags[PRINT_FETCH_SEQ] = exe_trace_print_fetchseq;
+ flags[PRINT_CP_SEQ] = exe_trace_print_cp_seq;
+ flags[INTEL_FORMAT] = exe_trace_intel_format;
+ trace_system = exe_trace_system;
+}
+
+void
+ExecutionTraceParamContext::checkParams()
+{
+ Trace::InstRecord::setParams();
+}
+
diff --git a/src/cpu/exetrace.hh b/src/cpu/exetrace.hh
new file mode 100644
index 000000000..a26cdc517
--- /dev/null
+++ b/src/cpu/exetrace.hh
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __EXETRACE_HH__
+#define __EXETRACE_HH__
+
+#include <fstream>
+#include <vector>
+
+#include "sim/host.hh"
+#include "cpu/inst_seq.hh" // for InstSeqNum
+#include "base/trace.hh"
+#include "cpu/exec_context.hh"
+#include "cpu/static_inst.hh"
+
+class BaseCPU;
+
+
+namespace Trace {
+
+class InstRecord : public Record
+{
+ protected:
+ typedef TheISA::IntRegFile IntRegFile;
+
+ // The following fields are initialized by the constructor and
+ // thus guaranteed to be valid.
+ BaseCPU *cpu;
+ // need to make this ref-counted so it doesn't go away before we
+ // dump the record
+ StaticInstPtr staticInst;
+ Addr PC;
+ bool misspeculating;
+ unsigned thread;
+
+ // The remaining fields are only valid for particular instruction
+ // types (e.g, addresses for memory ops) or when particular
+ // options are enabled (e.g., tracing full register contents).
+ // Each data field has an associated valid flag to indicate
+ // whether the data field is valid.
+ Addr addr;
+ bool addr_valid;
+
+ union {
+ uint64_t as_int;
+ double as_double;
+ } data;
+ enum {
+ DataInvalid = 0,
+ DataInt8 = 1, // set to equal number of bytes
+ DataInt16 = 2,
+ DataInt32 = 4,
+ DataInt64 = 8,
+ DataDouble = 3
+ } data_status;
+
+ InstSeqNum fetch_seq;
+ bool fetch_seq_valid;
+
+ InstSeqNum cp_seq;
+ bool cp_seq_valid;
+
+ struct iRegFile {
+ IntRegFile regs;
+ };
+ iRegFile *iregs;
+ bool regs_valid;
+
+ public:
+ InstRecord(Tick _cycle, BaseCPU *_cpu,
+ const StaticInstPtr &_staticInst,
+ Addr _pc, bool spec, int _thread)
+ : Record(_cycle), cpu(_cpu), staticInst(_staticInst), PC(_pc),
+ misspeculating(spec), thread(_thread)
+ {
+ data_status = DataInvalid;
+ addr_valid = false;
+ regs_valid = false;
+
+ fetch_seq_valid = false;
+ cp_seq_valid = false;
+ }
+
+ virtual ~InstRecord() { }
+
+ virtual void dump(std::ostream &outs);
+
+ void setAddr(Addr a) { addr = a; addr_valid = true; }
+
+ void setData(uint64_t d) { data.as_int = d; data_status = DataInt64; }
+ void setData(uint32_t d) { data.as_int = d; data_status = DataInt32; }
+ void setData(uint16_t d) { data.as_int = d; data_status = DataInt16; }
+ void setData(uint8_t d) { data.as_int = d; data_status = DataInt8; }
+
+ void setData(int64_t d) { setData((uint64_t)d); }
+ void setData(int32_t d) { setData((uint32_t)d); }
+ void setData(int16_t d) { setData((uint16_t)d); }
+ void setData(int8_t d) { setData((uint8_t)d); }
+
+ void setData(double d) { data.as_double = d; data_status = DataDouble; }
+
+ void setFetchSeq(InstSeqNum seq)
+ { fetch_seq = seq; fetch_seq_valid = true; }
+
+ void setCPSeq(InstSeqNum seq)
+ { cp_seq = seq; cp_seq_valid = true; }
+
+ void setRegs(const IntRegFile &regs);
+
+ void finalize() { theLog.append(this); }
+
+ enum InstExecFlagBits {
+ TRACE_MISSPEC = 0,
+ PRINT_CYCLE,
+ PRINT_OP_CLASS,
+ PRINT_THREAD_NUM,
+ PRINT_RESULT_DATA,
+ PRINT_EFF_ADDR,
+ PRINT_INT_REGS,
+ PRINT_FETCH_SEQ,
+ PRINT_CP_SEQ,
+ INTEL_FORMAT,
+ NUM_BITS
+ };
+
+ static std::vector<bool> flags;
+ static std::string trace_system;
+
+ static void setParams();
+
+ static bool traceMisspec() { return flags[TRACE_MISSPEC]; }
+};
+
+
+inline void
+InstRecord::setRegs(const IntRegFile &regs)
+{
+ if (!iregs)
+ iregs = new iRegFile;
+
+ memcpy(&iregs->regs, &regs, sizeof(IntRegFile));
+ regs_valid = true;
+}
+
+inline
+InstRecord *
+getInstRecord(Tick cycle, ExecContext *xc, BaseCPU *cpu,
+ const StaticInstPtr staticInst,
+ Addr pc, int thread = 0)
+{
+ if (DTRACE(InstExec) &&
+ (InstRecord::traceMisspec() || !xc->misspeculating())) {
+ return new InstRecord(cycle, cpu, staticInst, pc,
+ xc->misspeculating(), thread);
+ }
+
+ return NULL;
+}
+
+
+}
+
+#endif // __EXETRACE_HH__
diff --git a/src/cpu/inst_seq.hh b/src/cpu/inst_seq.hh
new file mode 100644
index 000000000..8de047af7
--- /dev/null
+++ b/src/cpu/inst_seq.hh
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2001, 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __STD_TYPES_HH__
+#define __STD_TYPES_HH__
+
+// inst sequence type, used to order instructions in the ready list,
+// if this rolls over the ready list order temporarily will get messed
+// up, but execution will continue and complete correctly
+typedef uint64_t InstSeqNum;
+
+// inst tag type, used to tag an operation instance in the IQ
+typedef unsigned int InstTag;
+
+#endif // __STD_TYPES_HH__
diff --git a/src/cpu/intr_control.cc b/src/cpu/intr_control.cc
new file mode 100644
index 000000000..43e7f654c
--- /dev/null
+++ b/src/cpu/intr_control.cc
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string>
+#include <vector>
+
+#include "cpu/base.hh"
+#include "cpu/exec_context.hh"
+#include "cpu/intr_control.hh"
+#include "sim/builder.hh"
+#include "sim/sim_object.hh"
+
+using namespace std;
+
+IntrControl::IntrControl(const string &name, BaseCPU *c)
+ : SimObject(name), cpu(c)
+{}
+
+/* @todo
+ *Fix the cpu sim object parameter to be a system pointer
+ *instead, to avoid some extra dereferencing
+ */
+void
+IntrControl::post(int int_num, int index)
+{
+ std::vector<ExecContext *> &xcvec = cpu->system->execContexts;
+ BaseCPU *temp = xcvec[0]->getCpuPtr();
+ temp->post_interrupt(int_num, index);
+}
+
+void
+IntrControl::post(int cpu_id, int int_num, int index)
+{
+ std::vector<ExecContext *> &xcvec = cpu->system->execContexts;
+ BaseCPU *temp = xcvec[cpu_id]->getCpuPtr();
+ temp->post_interrupt(int_num, index);
+}
+
+void
+IntrControl::clear(int int_num, int index)
+{
+ std::vector<ExecContext *> &xcvec = cpu->system->execContexts;
+ BaseCPU *temp = xcvec[0]->getCpuPtr();
+ temp->clear_interrupt(int_num, index);
+}
+
+void
+IntrControl::clear(int cpu_id, int int_num, int index)
+{
+ std::vector<ExecContext *> &xcvec = cpu->system->execContexts;
+ BaseCPU *temp = xcvec[cpu_id]->getCpuPtr();
+ temp->clear_interrupt(int_num, index);
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(IntrControl)
+
+ SimObjectParam<BaseCPU *> cpu;
+
+END_DECLARE_SIM_OBJECT_PARAMS(IntrControl)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(IntrControl)
+
+ INIT_PARAM(cpu, "the cpu")
+
+END_INIT_SIM_OBJECT_PARAMS(IntrControl)
+
+CREATE_SIM_OBJECT(IntrControl)
+{
+ return new IntrControl(getInstanceName(), cpu);
+}
+
+REGISTER_SIM_OBJECT("IntrControl", IntrControl)
diff --git a/src/cpu/intr_control.hh b/src/cpu/intr_control.hh
new file mode 100644
index 000000000..5ec4e14cb
--- /dev/null
+++ b/src/cpu/intr_control.hh
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __INTR_CONTROL_HH__
+#define __INTR_CONTROL_HH__
+
+#include <vector>
+#include "base/misc.hh"
+#include "cpu/base.hh"
+#include "sim/sim_object.hh"
+#include "sim/system.hh"
+
+
+class IntrControl : public SimObject
+{
+ public:
+ BaseCPU *cpu;
+ IntrControl(const std::string &name, BaseCPU *c);
+
+ void clear(int int_num, int index = 0);
+ void post(int int_num, int index = 0);
+ void clear(int cpu_id, int int_num, int index);
+ void post(int cpu_id, int int_num, int index);
+};
+
+#endif // __INTR_CONTROL_HH__
+
+
+
+
+
+
+
diff --git a/src/cpu/memtest/memtest.cc b/src/cpu/memtest/memtest.cc
new file mode 100644
index 000000000..54def1012
--- /dev/null
+++ b/src/cpu/memtest/memtest.cc
@@ -0,0 +1,440 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// FIX ME: make trackBlkAddr use blocksize from actual cache, not hard coded
+
+#include <iomanip>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/misc.hh"
+#include "base/statistics.hh"
+#include "cpu/cpu_exec_context.hh"
+#include "cpu/memtest/memtest.hh"
+#include "mem/cache/base_cache.hh"
+#include "sim/builder.hh"
+#include "sim/sim_events.hh"
+#include "sim/stats.hh"
+
+using namespace std;
+using namespace TheISA;
+
+int TESTER_ALLOCATOR=0;
+
+MemTest::MemTest(const string &name,
+ MemInterface *_cache_interface,
+ FunctionalMemory *main_mem,
+ FunctionalMemory *check_mem,
+ unsigned _memorySize,
+ unsigned _percentReads,
+ unsigned _percentCopies,
+ unsigned _percentUncacheable,
+ unsigned _progressInterval,
+ unsigned _percentSourceUnaligned,
+ unsigned _percentDestUnaligned,
+ Addr _traceAddr,
+ Counter _max_loads)
+ : SimObject(name),
+ tickEvent(this),
+ cacheInterface(_cache_interface),
+ mainMem(main_mem),
+ checkMem(check_mem),
+ size(_memorySize),
+ percentReads(_percentReads),
+ percentCopies(_percentCopies),
+ percentUncacheable(_percentUncacheable),
+ progressInterval(_progressInterval),
+ nextProgressMessage(_progressInterval),
+ percentSourceUnaligned(_percentSourceUnaligned),
+ percentDestUnaligned(percentDestUnaligned),
+ maxLoads(_max_loads)
+{
+ vector<string> cmd;
+ cmd.push_back("/bin/ls");
+ vector<string> null_vec;
+ cpuXC = new CPUExecContext(NULL, 0, mainMem, 0);
+
+ blockSize = cacheInterface->getBlockSize();
+ blockAddrMask = blockSize - 1;
+ traceBlockAddr = blockAddr(_traceAddr);
+
+ //setup data storage with interesting values
+ uint8_t *data1 = new uint8_t[size];
+ uint8_t *data2 = new uint8_t[size];
+ uint8_t *data3 = new uint8_t[size];
+ memset(data1, 1, size);
+ memset(data2, 2, size);
+ memset(data3, 3, size);
+ curTick = 0;
+
+ baseAddr1 = 0x100000;
+ baseAddr2 = 0x400000;
+ uncacheAddr = 0x800000;
+
+ // set up intial memory contents here
+ mainMem->prot_write(baseAddr1, data1, size);
+ checkMem->prot_write(baseAddr1, data1, size);
+ mainMem->prot_write(baseAddr2, data2, size);
+ checkMem->prot_write(baseAddr2, data2, size);
+ mainMem->prot_write(uncacheAddr, data3, size);
+ checkMem->prot_write(uncacheAddr, data3, size);
+
+ delete [] data1;
+ delete [] data2;
+ delete [] data3;
+
+ // set up counters
+ noResponseCycles = 0;
+ numReads = 0;
+ tickEvent.schedule(0);
+
+ id = TESTER_ALLOCATOR++;
+}
+
+static void
+printData(ostream &os, uint8_t *data, int nbytes)
+{
+ os << hex << setfill('0');
+ // assume little-endian: print bytes from highest address to lowest
+ for (uint8_t *dp = data + nbytes - 1; dp >= data; --dp) {
+ os << setw(2) << (unsigned)*dp;
+ }
+ os << dec;
+}
+
+void
+MemTest::completeRequest(MemReqPtr &req, uint8_t *data)
+{
+ //Remove the address from the list of outstanding
+ std::set<unsigned>::iterator removeAddr = outstandingAddrs.find(req->paddr);
+ assert(removeAddr != outstandingAddrs.end());
+ outstandingAddrs.erase(removeAddr);
+
+ switch (req->cmd) {
+ case Read:
+ if (memcmp(req->data, data, req->size) != 0) {
+ cerr << name() << ": on read of 0x" << hex << req->paddr
+ << " (0x" << hex << blockAddr(req->paddr) << ")"
+ << "@ cycle " << dec << curTick
+ << ", cache returns 0x";
+ printData(cerr, req->data, req->size);
+ cerr << ", expected 0x";
+ printData(cerr, data, req->size);
+ cerr << endl;
+ fatal("");
+ }
+
+ numReads++;
+ numReadsStat++;
+
+ if (numReads == nextProgressMessage) {
+ ccprintf(cerr, "%s: completed %d read accesses @%d\n",
+ name(), numReads, curTick);
+ nextProgressMessage += progressInterval;
+ }
+
+ if (numReads >= maxLoads)
+ SimExit(curTick, "Maximum number of loads reached!");
+ break;
+
+ case Write:
+ numWritesStat++;
+ break;
+
+ case Copy:
+ //Also remove dest from outstanding list
+ removeAddr = outstandingAddrs.find(req->dest);
+ assert(removeAddr != outstandingAddrs.end());
+ outstandingAddrs.erase(removeAddr);
+ numCopiesStat++;
+ break;
+
+ default:
+ panic("invalid command");
+ }
+
+ if (blockAddr(req->paddr) == traceBlockAddr) {
+ cerr << name() << ": completed "
+ << (req->cmd.isWrite() ? "write" : "read")
+ << " access of "
+ << dec << req->size << " bytes at address 0x"
+ << hex << req->paddr
+ << " (0x" << hex << blockAddr(req->paddr) << ")"
+ << ", value = 0x";
+ printData(cerr, req->data, req->size);
+ cerr << " @ cycle " << dec << curTick;
+
+ cerr << endl;
+ }
+
+ noResponseCycles = 0;
+ delete [] data;
+}
+
+
+void
+MemTest::regStats()
+{
+ using namespace Stats;
+
+
+ numReadsStat
+ .name(name() + ".num_reads")
+ .desc("number of read accesses completed")
+ ;
+
+ numWritesStat
+ .name(name() + ".num_writes")
+ .desc("number of write accesses completed")
+ ;
+
+ numCopiesStat
+ .name(name() + ".num_copies")
+ .desc("number of copy accesses completed")
+ ;
+}
+
+void
+MemTest::tick()
+{
+ if (!tickEvent.scheduled())
+ tickEvent.schedule(curTick + cycles(1));
+
+ if (++noResponseCycles >= 500000) {
+ cerr << name() << ": deadlocked at cycle " << curTick << endl;
+ fatal("");
+ }
+
+ if (cacheInterface->isBlocked()) {
+ return;
+ }
+
+ //make new request
+ unsigned cmd = random() % 100;
+ unsigned offset = random() % size;
+ unsigned base = random() % 2;
+ uint64_t data = random();
+ unsigned access_size = random() % 4;
+ unsigned cacheable = random() % 100;
+
+ //If we aren't doing copies, use id as offset, and do a false sharing
+ //mem tester
+ if (percentCopies == 0) {
+ //We can eliminate the lower bits of the offset, and then use the id
+ //to offset within the blks
+ offset &= ~63; //Not the low order bits
+ offset += id;
+ access_size = 0;
+ }
+
+ MemReqPtr req = new MemReq();
+
+ if (cacheable < percentUncacheable) {
+ req->flags |= UNCACHEABLE;
+ req->paddr = uncacheAddr + offset;
+ } else {
+ req->paddr = ((base) ? baseAddr1 : baseAddr2) + offset;
+ }
+ // bool probe = (random() % 2 == 1) && !req->isUncacheable();
+ bool probe = false;
+
+ req->size = 1 << access_size;
+ req->data = new uint8_t[req->size];
+ req->paddr &= ~(req->size - 1);
+ req->time = curTick;
+ req->xc = cpuXC->getProxy();
+
+ if (cmd < percentReads) {
+ // read
+
+ //For now we only allow one outstanding request per addreess per tester
+ //This means we assume CPU does write forwarding to reads that alias something
+ //in the cpu store buffer.
+ if (outstandingAddrs.find(req->paddr) != outstandingAddrs.end()) return;
+ else outstandingAddrs.insert(req->paddr);
+
+ req->cmd = Read;
+ uint8_t *result = new uint8_t[8];
+ checkMem->access(Read, req->paddr, result, req->size);
+ if (blockAddr(req->paddr) == traceBlockAddr) {
+ cerr << name()
+ << ": initiating read "
+ << ((probe) ? "probe of " : "access of ")
+ << dec << req->size << " bytes from addr 0x"
+ << hex << req->paddr
+ << " (0x" << hex << blockAddr(req->paddr) << ")"
+ << " at cycle "
+ << dec << curTick << endl;
+ }
+ if (probe) {
+ cacheInterface->probeAndUpdate(req);
+ completeRequest(req, result);
+ } else {
+ req->completionEvent = new MemCompleteEvent(req, result, this);
+ cacheInterface->access(req);
+ }
+ } else if (cmd < (100 - percentCopies)){
+ // write
+
+ //For now we only allow one outstanding request per addreess per tester
+ //This means we assume CPU does write forwarding to reads that alias something
+ //in the cpu store buffer.
+ if (outstandingAddrs.find(req->paddr) != outstandingAddrs.end()) return;
+ else outstandingAddrs.insert(req->paddr);
+
+ req->cmd = Write;
+ memcpy(req->data, &data, req->size);
+ checkMem->access(Write, req->paddr, req->data, req->size);
+ if (blockAddr(req->paddr) == traceBlockAddr) {
+ cerr << name() << ": initiating write "
+ << ((probe)?"probe of ":"access of ")
+ << dec << req->size << " bytes (value = 0x";
+ printData(cerr, req->data, req->size);
+ cerr << ") to addr 0x"
+ << hex << req->paddr
+ << " (0x" << hex << blockAddr(req->paddr) << ")"
+ << " at cycle "
+ << dec << curTick << endl;
+ }
+ if (probe) {
+ cacheInterface->probeAndUpdate(req);
+ completeRequest(req, NULL);
+ } else {
+ req->completionEvent = new MemCompleteEvent(req, NULL, this);
+ cacheInterface->access(req);
+ }
+ } else {
+ // copy
+ unsigned source_align = random() % 100;
+ unsigned dest_align = random() % 100;
+ unsigned offset2 = random() % size;
+
+ Addr source = ((base) ? baseAddr1 : baseAddr2) + offset;
+ Addr dest = ((base) ? baseAddr2 : baseAddr1) + offset2;
+ if (outstandingAddrs.find(source) != outstandingAddrs.end()) return;
+ else outstandingAddrs.insert(source);
+ if (outstandingAddrs.find(dest) != outstandingAddrs.end()) return;
+ else outstandingAddrs.insert(dest);
+
+ if (source_align >= percentSourceUnaligned) {
+ source = blockAddr(source);
+ }
+ if (dest_align >= percentDestUnaligned) {
+ dest = blockAddr(dest);
+ }
+ req->cmd = Copy;
+ req->flags &= ~UNCACHEABLE;
+ req->paddr = source;
+ req->dest = dest;
+ delete [] req->data;
+ req->data = new uint8_t[blockSize];
+ req->size = blockSize;
+ if (source == traceBlockAddr || dest == traceBlockAddr) {
+ cerr << name()
+ << ": initiating copy of "
+ << dec << req->size << " bytes from addr 0x"
+ << hex << source
+ << " (0x" << hex << blockAddr(source) << ")"
+ << " to addr 0x"
+ << hex << dest
+ << " (0x" << hex << blockAddr(dest) << ")"
+ << " at cycle "
+ << dec << curTick << endl;
+ }
+ cacheInterface->access(req);
+ uint8_t result[blockSize];
+ checkMem->access(Read, source, &result, blockSize);
+ checkMem->access(Write, dest, &result, blockSize);
+ }
+}
+
+
+void
+MemCompleteEvent::process()
+{
+ tester->completeRequest(req, data);
+ delete this;
+}
+
+
+const char *
+MemCompleteEvent::description()
+{
+ return "memory access completion";
+}
+
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(MemTest)
+
+ SimObjectParam<BaseCache *> cache;
+ SimObjectParam<FunctionalMemory *> main_mem;
+ SimObjectParam<FunctionalMemory *> check_mem;
+ Param<unsigned> memory_size;
+ Param<unsigned> percent_reads;
+ Param<unsigned> percent_copies;
+ Param<unsigned> percent_uncacheable;
+ Param<unsigned> progress_interval;
+ Param<unsigned> percent_source_unaligned;
+ Param<unsigned> percent_dest_unaligned;
+ Param<Addr> trace_addr;
+ Param<Counter> max_loads;
+
+END_DECLARE_SIM_OBJECT_PARAMS(MemTest)
+
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(MemTest)
+
+ INIT_PARAM(cache, "L1 cache"),
+ INIT_PARAM(main_mem, "hierarchical memory"),
+ INIT_PARAM(check_mem, "check memory"),
+ INIT_PARAM(memory_size, "memory size"),
+ INIT_PARAM(percent_reads, "target read percentage"),
+ INIT_PARAM(percent_copies, "target copy percentage"),
+ INIT_PARAM(percent_uncacheable, "target uncacheable percentage"),
+ INIT_PARAM(progress_interval, "progress report interval (in accesses)"),
+ INIT_PARAM(percent_source_unaligned,
+ "percent of copy source address that are unaligned"),
+ INIT_PARAM(percent_dest_unaligned,
+ "percent of copy dest address that are unaligned"),
+ INIT_PARAM(trace_addr, "address to trace"),
+ INIT_PARAM(max_loads, "terminate when we have reached this load count")
+
+END_INIT_SIM_OBJECT_PARAMS(MemTest)
+
+
+CREATE_SIM_OBJECT(MemTest)
+{
+ return new MemTest(getInstanceName(), cache->getInterface(), main_mem,
+ check_mem, memory_size, percent_reads, percent_copies,
+ percent_uncacheable, progress_interval,
+ percent_source_unaligned, percent_dest_unaligned,
+ trace_addr, max_loads);
+}
+
+REGISTER_SIM_OBJECT("MemTest", MemTest)
diff --git a/src/cpu/memtest/memtest.hh b/src/cpu/memtest/memtest.hh
new file mode 100644
index 000000000..cdb40a26a
--- /dev/null
+++ b/src/cpu/memtest/memtest.hh
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPU_MEMTEST_MEMTEST_HH__
+#define __CPU_MEMTEST_MEMTEST_HH__
+
+#include <set>
+
+#include "base/statistics.hh"
+#include "mem/functional/functional.hh"
+#include "mem/mem_interface.hh"
+#include "sim/eventq.hh"
+#include "sim/sim_exit.hh"
+#include "sim/sim_object.hh"
+#include "sim/stats.hh"
+
+class ExecContext;
+class MemTest : public SimObject
+{
+ public:
+
+ MemTest(const std::string &name,
+ MemInterface *_cache_interface,
+ FunctionalMemory *main_mem,
+ FunctionalMemory *check_mem,
+ unsigned _memorySize,
+ unsigned _percentReads,
+ unsigned _percentCopies,
+ unsigned _percentUncacheable,
+ unsigned _progressInterval,
+ unsigned _percentSourceUnaligned,
+ unsigned _percentDestUnaligned,
+ Addr _traceAddr,
+ Counter _max_loads);
+
+ // register statistics
+ virtual void regStats();
+
+ inline Tick cycles(int numCycles) const { return numCycles; }
+
+ // main simulation loop (one cycle)
+ void tick();
+
+ protected:
+ class TickEvent : public Event
+ {
+ private:
+ MemTest *cpu;
+ public:
+ TickEvent(MemTest *c)
+ : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) {}
+ void process() {cpu->tick();}
+ virtual const char *description() { return "tick event"; }
+ };
+
+ TickEvent tickEvent;
+
+ MemInterface *cacheInterface;
+ FunctionalMemory *mainMem;
+ FunctionalMemory *checkMem;
+ CPUExecContext *cpuXC;
+
+ unsigned size; // size of testing memory region
+
+ unsigned percentReads; // target percentage of read accesses
+ unsigned percentCopies; // target percentage of copy accesses
+ unsigned percentUncacheable;
+
+ int id;
+
+ std::set<unsigned> outstandingAddrs;
+
+ unsigned blockSize;
+
+ Addr blockAddrMask;
+
+ Addr blockAddr(Addr addr)
+ {
+ return (addr & ~blockAddrMask);
+ }
+
+ Addr traceBlockAddr;
+
+ Addr baseAddr1; // fix this to option
+ Addr baseAddr2; // fix this to option
+ Addr uncacheAddr;
+
+ unsigned progressInterval; // frequency of progress reports
+ Tick nextProgressMessage; // access # for next progress report
+
+ unsigned percentSourceUnaligned;
+ unsigned percentDestUnaligned;
+
+ Tick noResponseCycles;
+
+ uint64_t numReads;
+ uint64_t maxLoads;
+ Stats::Scalar<> numReadsStat;
+ Stats::Scalar<> numWritesStat;
+ Stats::Scalar<> numCopiesStat;
+
+ // called by MemCompleteEvent::process()
+ void completeRequest(MemReqPtr &req, uint8_t *data);
+
+ friend class MemCompleteEvent;
+};
+
+
+class MemCompleteEvent : public Event
+{
+ MemReqPtr req;
+ uint8_t *data;
+ MemTest *tester;
+
+ public:
+
+ MemCompleteEvent(MemReqPtr &_req, uint8_t *_data, MemTest *_tester)
+ : Event(&mainEventQueue),
+ req(_req), data(_data), tester(_tester)
+ {
+ }
+
+ void process();
+
+ virtual const char *description();
+};
+
+#endif // __CPU_MEMTEST_MEMTEST_HH__
+
+
+
diff --git a/src/cpu/o3/2bit_local_pred.cc b/src/cpu/o3/2bit_local_pred.cc
new file mode 100644
index 000000000..d9744eec7
--- /dev/null
+++ b/src/cpu/o3/2bit_local_pred.cc
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "base/trace.hh"
+#include "cpu/o3/2bit_local_pred.hh"
+
+DefaultBP::DefaultBP(unsigned _localPredictorSize,
+ unsigned _localCtrBits,
+ unsigned _instShiftAmt)
+ : localPredictorSize(_localPredictorSize),
+ localCtrBits(_localCtrBits),
+ instShiftAmt(_instShiftAmt)
+{
+ // Should do checks here to make sure sizes are correct (powers of 2).
+
+ // Setup the index mask.
+ indexMask = localPredictorSize - 1;
+
+ DPRINTF(Fetch, "Branch predictor: index mask: %#x\n", indexMask);
+
+ // Setup the array of counters for the local predictor.
+ localCtrs = new SatCounter[localPredictorSize];
+
+ for (int i = 0; i < localPredictorSize; ++i)
+ localCtrs[i].setBits(_localCtrBits);
+
+ DPRINTF(Fetch, "Branch predictor: local predictor size: %i\n",
+ localPredictorSize);
+
+ DPRINTF(Fetch, "Branch predictor: local counter bits: %i\n", localCtrBits);
+
+ DPRINTF(Fetch, "Branch predictor: instruction shift amount: %i\n",
+ instShiftAmt);
+}
+
+bool
+DefaultBP::lookup(Addr &branch_addr)
+{
+ bool taken;
+ uint8_t local_prediction;
+ unsigned local_predictor_idx = getLocalIndex(branch_addr);
+
+ DPRINTF(Fetch, "Branch predictor: Looking up index %#x\n",
+ local_predictor_idx);
+
+ assert(local_predictor_idx < localPredictorSize);
+
+ local_prediction = localCtrs[local_predictor_idx].read();
+
+ DPRINTF(Fetch, "Branch predictor: prediction is %i.\n",
+ (int)local_prediction);
+
+ taken = getPrediction(local_prediction);
+
+#if 0
+ // Speculative update.
+ if (taken) {
+ DPRINTF(Fetch, "Branch predictor: Branch updated as taken.\n");
+ localCtrs[local_predictor_idx].increment();
+ } else {
+ DPRINTF(Fetch, "Branch predictor: Branch updated as not taken.\n");
+ localCtrs[local_predictor_idx].decrement();
+ }
+#endif
+
+ return taken;
+}
+
+void
+DefaultBP::update(Addr &branch_addr, bool taken)
+{
+ unsigned local_predictor_idx;
+
+ // Update the local predictor.
+ local_predictor_idx = getLocalIndex(branch_addr);
+
+ DPRINTF(Fetch, "Branch predictor: Looking up index %#x\n",
+ local_predictor_idx);
+
+ assert(local_predictor_idx < localPredictorSize);
+
+ if (taken) {
+ DPRINTF(Fetch, "Branch predictor: Branch updated as taken.\n");
+ localCtrs[local_predictor_idx].increment();
+ } else {
+ DPRINTF(Fetch, "Branch predictor: Branch updated as not taken.\n");
+ localCtrs[local_predictor_idx].decrement();
+ }
+}
+
+inline
+bool
+DefaultBP::getPrediction(uint8_t &count)
+{
+ // Get the MSB of the count
+ return (count >> (localCtrBits - 1));
+}
+
+inline
+unsigned
+DefaultBP::getLocalIndex(Addr &branch_addr)
+{
+ return (branch_addr >> instShiftAmt) & indexMask;
+}
diff --git a/src/cpu/o3/2bit_local_pred.hh b/src/cpu/o3/2bit_local_pred.hh
new file mode 100644
index 000000000..97433e542
--- /dev/null
+++ b/src/cpu/o3/2bit_local_pred.hh
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPU_O3_CPU_2BIT_LOCAL_PRED_HH__
+#define __CPU_O3_CPU_2BIT_LOCAL_PRED_HH__
+
+// For Addr type.
+#include "arch/isa_traits.hh"
+#include "cpu/o3/sat_counter.hh"
+
+class DefaultBP
+{
+ public:
+ /**
+ * Default branch predictor constructor.
+ */
+ DefaultBP(unsigned localPredictorSize, unsigned localCtrBits,
+ unsigned instShiftAmt);
+
+ /**
+ * Looks up the given address in the branch predictor and returns
+ * a true/false value as to whether it is taken.
+ * @param branch_addr The address of the branch to look up.
+ * @return Whether or not the branch is taken.
+ */
+ bool lookup(Addr &branch_addr);
+
+ /**
+ * Updates the branch predictor with the actual result of a branch.
+ * @param branch_addr The address of the branch to update.
+ * @param taken Whether or not the branch was taken.
+ */
+ void update(Addr &branch_addr, bool taken);
+
+ private:
+
+ /** Returns the taken/not taken prediction given the value of the
+ * counter.
+ */
+ inline bool getPrediction(uint8_t &count);
+
+ /** Calculates the local index based on the PC. */
+ inline unsigned getLocalIndex(Addr &PC);
+
+ /** Array of counters that make up the local predictor. */
+ SatCounter *localCtrs;
+
+ /** Size of the local predictor. */
+ unsigned localPredictorSize;
+
+ /** Number of bits of the local predictor's counters. */
+ unsigned localCtrBits;
+
+ /** Number of bits to shift the PC when calculating index. */
+ unsigned instShiftAmt;
+
+ /** Mask to get index bits. */
+ unsigned indexMask;
+};
+
+#endif // __CPU_O3_CPU_2BIT_LOCAL_PRED_HH__
diff --git a/src/cpu/o3/alpha_cpu.cc b/src/cpu/o3/alpha_cpu.cc
new file mode 100644
index 000000000..7bc90dae6
--- /dev/null
+++ b/src/cpu/o3/alpha_cpu.cc
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "cpu/o3/alpha_impl.hh"
+#include "cpu/o3/alpha_cpu_impl.hh"
+#include "cpu/o3/alpha_dyn_inst.hh"
+
+// Force instantiation of AlphaFullCPU for all the implemntations that are
+// needed. Consider merging this and alpha_dyn_inst.cc, and maybe all
+// classes that depend on a certain impl, into one file (alpha_impl.cc?).
+template class AlphaFullCPU<AlphaSimpleImpl>;
diff --git a/src/cpu/o3/alpha_cpu.hh b/src/cpu/o3/alpha_cpu.hh
new file mode 100644
index 000000000..8e1e0f42a
--- /dev/null
+++ b/src/cpu/o3/alpha_cpu.hh
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Todo: Find all the stuff in ExecContext and ev5 that needs to be
+// specifically designed for this CPU.
+
+#ifndef __CPU_O3_CPU_ALPHA_FULL_CPU_HH__
+#define __CPU_O3_CPU_ALPHA_FULL_CPU_HH__
+
+#include "cpu/o3/cpu.hh"
+#include "arch/isa_traits.hh"
+#include "sim/byteswap.hh"
+
+template <class Impl>
+class AlphaFullCPU : public FullO3CPU<Impl>
+{
+ protected:
+ typedef TheISA::IntReg IntReg;
+ typedef TheISA::MiscReg MiscReg;
+ typedef TheISA::RegFile RegFile;
+ typedef TheISA::MiscRegFile MiscRegFile;
+
+ public:
+ typedef typename Impl::Params Params;
+
+ public:
+ AlphaFullCPU(Params &params);
+
+#if FULL_SYSTEM
+ AlphaITB *itb;
+ AlphaDTB *dtb;
+#endif
+
+ public:
+ void regStats();
+
+#if FULL_SYSTEM
+ //Note that the interrupt stuff from the base CPU might be somewhat
+ //ISA specific (ie NumInterruptLevels). These functions might not
+ //be needed in FullCPU though.
+// void post_interrupt(int int_num, int index);
+// void clear_interrupt(int int_num, int index);
+// void clear_interrupts();
+
+ Fault translateInstReq(MemReqPtr &req)
+ {
+ return itb->translate(req);
+ }
+
+ Fault translateDataReadReq(MemReqPtr &req)
+ {
+ return dtb->translate(req, false);
+ }
+
+ Fault translateDataWriteReq(MemReqPtr &req)
+ {
+ return dtb->translate(req, true);
+ }
+
+#else
+ Fault dummyTranslation(MemReqPtr &req)
+ {
+#if 0
+ assert((req->vaddr >> 48 & 0xffff) == 0);
+#endif
+
+ // put the asid in the upper 16 bits of the paddr
+ req->paddr = req->vaddr & ~((Addr)0xffff << sizeof(Addr) * 8 - 16);
+ req->paddr = req->paddr | (Addr)req->asid << sizeof(Addr) * 8 - 16;
+ return NoFault;
+ }
+
+ Fault translateInstReq(MemReqPtr &req)
+ {
+ return dummyTranslation(req);
+ }
+
+ Fault translateDataReadReq(MemReqPtr &req)
+ {
+ return dummyTranslation(req);
+ }
+
+ Fault translateDataWriteReq(MemReqPtr &req)
+ {
+ return dummyTranslation(req);
+ }
+
+#endif
+
+ // Later on may want to remove this misc stuff from the regfile and
+ // have it handled at this level. Might prove to be an issue when
+ // trying to rename source/destination registers...
+ MiscReg readMiscReg(int misc_reg)
+ {
+ // Dummy function for now.
+ // @todo: Fix this once reg file gets fixed.
+ return 0;
+ }
+
+ Fault setMiscReg(int misc_reg, const MiscReg &val)
+ {
+ // Dummy function for now.
+ // @todo: Fix this once reg file gets fixed.
+ return NoFault;
+ }
+
+ // Most of the full system code and syscall emulation is not yet
+ // implemented. These functions do show what the final interface will
+ // look like.
+#if FULL_SYSTEM
+ int readIntrFlag();
+ void setIntrFlag(int val);
+ Fault hwrei();
+ bool inPalMode() { return AlphaISA::PcPAL(this->regFile.readPC()); }
+ bool inPalMode(uint64_t PC)
+ { return AlphaISA::PcPAL(PC); }
+
+ void trap(Fault fault);
+ bool simPalCheck(int palFunc);
+
+ void processInterrupts();
+#endif
+
+
+#if !FULL_SYSTEM
+ // Need to change these into regfile calls that directly set a certain
+ // register. Actually, these functions should handle most of this
+ // functionality by themselves; should look up the rename and then
+ // set the register.
+ IntReg getSyscallArg(int i)
+ {
+ return this->cpuXC->readIntReg(AlphaISA::ArgumentReg0 + i);
+ }
+
+ // used to shift args for indirect syscall
+ void setSyscallArg(int i, IntReg val)
+ {
+ this->cpuXC->setIntReg(AlphaISA::ArgumentReg0 + i, val);
+ }
+
+ void setSyscallReturn(int64_t return_value)
+ {
+ // check for error condition. Alpha syscall convention is to
+ // indicate success/failure in reg a3 (r19) and put the
+ // return value itself in the standard return value reg (v0).
+ const int RegA3 = 19; // only place this is used
+ if (return_value >= 0) {
+ // no error
+ this->cpuXC->setIntReg(RegA3, 0);
+ this->cpuXC->setIntReg(AlphaISA::ReturnValueReg, return_value);
+ } else {
+ // got an error, return details
+ this->cpuXC->setIntReg(RegA3, (IntReg) -1);
+ this->cpuXC->setIntReg(AlphaISA::ReturnValueReg, -return_value);
+ }
+ }
+
+ void syscall(short thread_num);
+ void squashStages();
+
+#endif
+
+ void copyToXC();
+ void copyFromXC();
+
+ public:
+#if FULL_SYSTEM
+ bool palShadowEnabled;
+
+ // Not sure this is used anywhere.
+ void intr_post(RegFile *regs, Fault fault, Addr pc);
+ // Actually used within exec files. Implement properly.
+ void swapPALShadow(bool use_shadow);
+ // Called by CPU constructor. Can implement as I please.
+ void initCPU(RegFile *regs);
+ // Called by initCPU. Implement as I please.
+ void initIPRs(RegFile *regs);
+
+ void halt() { panic("Halt not implemented!\n"); }
+#endif
+
+
+ template <class T>
+ Fault read(MemReqPtr &req, T &data)
+ {
+#if FULL_SYSTEM && THE_ISA == ALPHA_ISA
+ if (req->flags & LOCKED) {
+ req->xc->setMiscReg(TheISA::Lock_Addr_DepTag, req->paddr);
+ req->xc->setMiscReg(TheISA::Lock_Flag_DepTag, true);
+ }
+#endif
+
+ Fault error;
+ error = this->mem->read(req, data);
+ data = gtoh(data);
+ return error;
+ }
+
+ template <class T>
+ Fault read(MemReqPtr &req, T &data, int load_idx)
+ {
+ return this->iew.ldstQueue.read(req, data, load_idx);
+ }
+
+ template <class T>
+ Fault write(MemReqPtr &req, T &data)
+ {
+#if FULL_SYSTEM && THE_ISA == ALPHA_ISA
+ ExecContext *xc;
+
+ // If this is a store conditional, act appropriately
+ if (req->flags & LOCKED) {
+ xc = req->xc;
+
+ if (req->flags & UNCACHEABLE) {
+ // Don't update result register (see stq_c in isa_desc)
+ req->result = 2;
+ xc->setStCondFailures(0);//Needed? [RGD]
+ } else {
+ bool lock_flag = xc->readMiscReg(TheISA::Lock_Flag_DepTag);
+ Addr lock_addr = xc->readMiscReg(TheISA::Lock_Addr_DepTag);
+ req->result = lock_flag;
+ if (!lock_flag ||
+ ((lock_addr & ~0xf) != (req->paddr & ~0xf))) {
+ xc->setMiscReg(TheISA::Lock_Flag_DepTag, false);
+ xc->setStCondFailures(xc->readStCondFailures() + 1);
+ if (((xc->readStCondFailures()) % 100000) == 0) {
+ std::cerr << "Warning: "
+ << xc->readStCondFailures()
+ << " consecutive store conditional failures "
+ << "on cpu " << req->xc->readCpuId()
+ << std::endl;
+ }
+ return NoFault;
+ }
+ else xc->setStCondFailures(0);
+ }
+ }
+
+ // Need to clear any locked flags on other proccessors for
+ // this address. Only do this for succsful Store Conditionals
+ // and all other stores (WH64?). Unsuccessful Store
+ // Conditionals would have returned above, and wouldn't fall
+ // through.
+ for (int i = 0; i < this->system->execContexts.size(); i++){
+ xc = this->system->execContexts[i];
+ if ((xc->readMiscReg(TheISA::Lock_Addr_DepTag) & ~0xf) ==
+ (req->paddr & ~0xf)) {
+ xc->setMiscReg(TheISA::Lock_Flag_DepTag, false);
+ }
+ }
+
+#endif
+
+ return this->mem->write(req, (T)htog(data));
+ }
+
+ template <class T>
+ Fault write(MemReqPtr &req, T &data, int store_idx)
+ {
+ return this->iew.ldstQueue.write(req, data, store_idx);
+ }
+
+};
+
+#endif // __CPU_O3_CPU_ALPHA_FULL_CPU_HH__
diff --git a/src/cpu/o3/alpha_cpu_builder.cc b/src/cpu/o3/alpha_cpu_builder.cc
new file mode 100644
index 000000000..6025b8ef2
--- /dev/null
+++ b/src/cpu/o3/alpha_cpu_builder.cc
@@ -0,0 +1,392 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "base/inifile.hh"
+#include "base/loader/symtab.hh"
+#include "base/misc.hh"
+#include "cpu/base.hh"
+#include "cpu/exetrace.hh"
+#include "cpu/o3/alpha_cpu.hh"
+#include "cpu/o3/alpha_impl.hh"
+#include "mem/base_mem.hh"
+#include "mem/cache/base_cache.hh"
+#include "mem/mem_interface.hh"
+#include "sim/builder.hh"
+#include "sim/debug.hh"
+#include "sim/host.hh"
+#include "sim/process.hh"
+#include "sim/sim_events.hh"
+#include "sim/sim_object.hh"
+#include "sim/stats.hh"
+
+#if FULL_SYSTEM
+#include "base/remote_gdb.hh"
+#include "mem/functional/memory_control.hh"
+#include "mem/functional/physical.hh"
+#include "sim/system.hh"
+#include "arch/tlb.hh"
+#include "arch/vtophys.hh"
+#else // !FULL_SYSTEM
+#include "mem/functional/functional.hh"
+#endif // FULL_SYSTEM
+
+class DerivAlphaFullCPU : public AlphaFullCPU<AlphaSimpleImpl>
+{
+ public:
+ DerivAlphaFullCPU(AlphaSimpleParams p)
+ : AlphaFullCPU<AlphaSimpleImpl>(p)
+ { }
+};
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(DerivAlphaFullCPU)
+
+ Param<int> clock;
+ Param<int> numThreads;
+
+#if FULL_SYSTEM
+SimObjectParam<System *> system;
+Param<int> cpu_id;
+SimObjectParam<AlphaITB *> itb;
+SimObjectParam<AlphaDTB *> dtb;
+#else
+SimObjectVectorParam<Process *> workload;
+#endif // FULL_SYSTEM
+SimObjectParam<FunctionalMemory *> mem;
+
+Param<Counter> max_insts_any_thread;
+Param<Counter> max_insts_all_threads;
+Param<Counter> max_loads_any_thread;
+Param<Counter> max_loads_all_threads;
+
+SimObjectParam<BaseCache *> icache;
+SimObjectParam<BaseCache *> dcache;
+
+Param<unsigned> decodeToFetchDelay;
+Param<unsigned> renameToFetchDelay;
+Param<unsigned> iewToFetchDelay;
+Param<unsigned> commitToFetchDelay;
+Param<unsigned> fetchWidth;
+
+Param<unsigned> renameToDecodeDelay;
+Param<unsigned> iewToDecodeDelay;
+Param<unsigned> commitToDecodeDelay;
+Param<unsigned> fetchToDecodeDelay;
+Param<unsigned> decodeWidth;
+
+Param<unsigned> iewToRenameDelay;
+Param<unsigned> commitToRenameDelay;
+Param<unsigned> decodeToRenameDelay;
+Param<unsigned> renameWidth;
+
+Param<unsigned> commitToIEWDelay;
+Param<unsigned> renameToIEWDelay;
+Param<unsigned> issueToExecuteDelay;
+Param<unsigned> issueWidth;
+Param<unsigned> executeWidth;
+Param<unsigned> executeIntWidth;
+Param<unsigned> executeFloatWidth;
+Param<unsigned> executeBranchWidth;
+Param<unsigned> executeMemoryWidth;
+
+Param<unsigned> iewToCommitDelay;
+Param<unsigned> renameToROBDelay;
+Param<unsigned> commitWidth;
+Param<unsigned> squashWidth;
+
+#if 0
+Param<unsigned> localPredictorSize;
+Param<unsigned> localPredictorCtrBits;
+#endif
+Param<unsigned> local_predictor_size;
+Param<unsigned> local_ctr_bits;
+Param<unsigned> local_history_table_size;
+Param<unsigned> local_history_bits;
+Param<unsigned> global_predictor_size;
+Param<unsigned> global_ctr_bits;
+Param<unsigned> global_history_bits;
+Param<unsigned> choice_predictor_size;
+Param<unsigned> choice_ctr_bits;
+
+Param<unsigned> BTBEntries;
+Param<unsigned> BTBTagSize;
+
+Param<unsigned> RASSize;
+
+Param<unsigned> LQEntries;
+Param<unsigned> SQEntries;
+Param<unsigned> LFSTSize;
+Param<unsigned> SSITSize;
+
+Param<unsigned> numPhysIntRegs;
+Param<unsigned> numPhysFloatRegs;
+Param<unsigned> numIQEntries;
+Param<unsigned> numROBEntries;
+
+Param<unsigned> instShiftAmt;
+
+Param<bool> defer_registration;
+
+Param<bool> function_trace;
+Param<Tick> function_trace_start;
+
+END_DECLARE_SIM_OBJECT_PARAMS(DerivAlphaFullCPU)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(DerivAlphaFullCPU)
+
+ INIT_PARAM(clock, "clock speed"),
+ INIT_PARAM(numThreads, "number of HW thread contexts"),
+
+#if FULL_SYSTEM
+ INIT_PARAM(system, "System object"),
+ INIT_PARAM(cpu_id, "processor ID"),
+ INIT_PARAM(itb, "Instruction translation buffer"),
+ INIT_PARAM(dtb, "Data translation buffer"),
+#else
+ INIT_PARAM(workload, "Processes to run"),
+#endif // FULL_SYSTEM
+
+ INIT_PARAM_DFLT(mem, "Memory", NULL),
+
+ INIT_PARAM_DFLT(max_insts_any_thread,
+ "Terminate when any thread reaches this inst count",
+ 0),
+ INIT_PARAM_DFLT(max_insts_all_threads,
+ "Terminate when all threads have reached"
+ "this inst count",
+ 0),
+ INIT_PARAM_DFLT(max_loads_any_thread,
+ "Terminate when any thread reaches this load count",
+ 0),
+ INIT_PARAM_DFLT(max_loads_all_threads,
+ "Terminate when all threads have reached this load"
+ "count",
+ 0),
+
+ INIT_PARAM_DFLT(icache, "L1 instruction cache", NULL),
+ INIT_PARAM_DFLT(dcache, "L1 data cache", NULL),
+
+ INIT_PARAM(decodeToFetchDelay, "Decode to fetch delay"),
+ INIT_PARAM(renameToFetchDelay, "Rename to fetch delay"),
+ INIT_PARAM(iewToFetchDelay, "Issue/Execute/Writeback to fetch"
+ "delay"),
+ INIT_PARAM(commitToFetchDelay, "Commit to fetch delay"),
+ INIT_PARAM(fetchWidth, "Fetch width"),
+
+ INIT_PARAM(renameToDecodeDelay, "Rename to decode delay"),
+ INIT_PARAM(iewToDecodeDelay, "Issue/Execute/Writeback to decode"
+ "delay"),
+ INIT_PARAM(commitToDecodeDelay, "Commit to decode delay"),
+ INIT_PARAM(fetchToDecodeDelay, "Fetch to decode delay"),
+ INIT_PARAM(decodeWidth, "Decode width"),
+
+ INIT_PARAM(iewToRenameDelay, "Issue/Execute/Writeback to rename"
+ "delay"),
+ INIT_PARAM(commitToRenameDelay, "Commit to rename delay"),
+ INIT_PARAM(decodeToRenameDelay, "Decode to rename delay"),
+ INIT_PARAM(renameWidth, "Rename width"),
+
+ INIT_PARAM(commitToIEWDelay, "Commit to "
+ "Issue/Execute/Writeback delay"),
+ INIT_PARAM(renameToIEWDelay, "Rename to "
+ "Issue/Execute/Writeback delay"),
+ INIT_PARAM(issueToExecuteDelay, "Issue to execute delay (internal"
+ "to the IEW stage)"),
+ INIT_PARAM(issueWidth, "Issue width"),
+ INIT_PARAM(executeWidth, "Execute width"),
+ INIT_PARAM(executeIntWidth, "Integer execute width"),
+ INIT_PARAM(executeFloatWidth, "Floating point execute width"),
+ INIT_PARAM(executeBranchWidth, "Branch execute width"),
+ INIT_PARAM(executeMemoryWidth, "Memory execute width"),
+
+ INIT_PARAM(iewToCommitDelay, "Issue/Execute/Writeback to commit "
+ "delay"),
+ INIT_PARAM(renameToROBDelay, "Rename to reorder buffer delay"),
+ INIT_PARAM(commitWidth, "Commit width"),
+ INIT_PARAM(squashWidth, "Squash width"),
+
+#if 0
+ INIT_PARAM(localPredictorSize, "Size of the local predictor in entries. "
+ "Must be a power of 2."),
+ INIT_PARAM(localPredictorCtrBits, "Number of bits per counter for bpred"),
+#endif
+ INIT_PARAM(local_predictor_size, "Size of local predictor"),
+ INIT_PARAM(local_ctr_bits, "Bits per counter"),
+ INIT_PARAM(local_history_table_size, "Size of local history table"),
+ INIT_PARAM(local_history_bits, "Bits for the local history"),
+ INIT_PARAM(global_predictor_size, "Size of global predictor"),
+ INIT_PARAM(global_ctr_bits, "Bits per counter"),
+ INIT_PARAM(global_history_bits, "Bits of history"),
+ INIT_PARAM(choice_predictor_size, "Size of choice predictor"),
+ INIT_PARAM(choice_ctr_bits, "Bits of choice counters"),
+
+ INIT_PARAM(BTBEntries, "Number of BTB entries"),
+ INIT_PARAM(BTBTagSize, "Size of the BTB tags, in bits"),
+
+ INIT_PARAM(RASSize, "RAS size"),
+
+ INIT_PARAM(LQEntries, "Number of load queue entries"),
+ INIT_PARAM(SQEntries, "Number of store queue entries"),
+ INIT_PARAM(LFSTSize, "Last fetched store table size"),
+ INIT_PARAM(SSITSize, "Store set ID table size"),
+
+ INIT_PARAM(numPhysIntRegs, "Number of physical integer registers"),
+ INIT_PARAM(numPhysFloatRegs, "Number of physical floating point "
+ "registers"),
+ INIT_PARAM(numIQEntries, "Number of instruction queue entries"),
+ INIT_PARAM(numROBEntries, "Number of reorder buffer entries"),
+
+ INIT_PARAM(instShiftAmt, "Number of bits to shift instructions by"),
+ INIT_PARAM(defer_registration, "defer system registration (for sampling)"),
+
+ INIT_PARAM(function_trace, "Enable function trace"),
+ INIT_PARAM(function_trace_start, "Cycle to start function trace")
+
+END_INIT_SIM_OBJECT_PARAMS(DerivAlphaFullCPU)
+
+CREATE_SIM_OBJECT(DerivAlphaFullCPU)
+{
+ DerivAlphaFullCPU *cpu;
+
+#if FULL_SYSTEM
+ // Full-system only supports a single thread for the moment.
+ int actual_num_threads = 1;
+#else
+ // In non-full-system mode, we infer the number of threads from
+ // the workload if it's not explicitly specified.
+ int actual_num_threads =
+ numThreads.isValid() ? numThreads : workload.size();
+
+ if (workload.size() == 0) {
+ fatal("Must specify at least one workload!");
+ }
+
+#endif
+
+ AlphaSimpleParams params;
+
+ params.clock = clock;
+
+ params.name = getInstanceName();
+ params.numberOfThreads = actual_num_threads;
+
+#if FULL_SYSTEM
+ params.system = system;
+ params.cpu_id = cpu_id;
+ params.itb = itb;
+ params.dtb = dtb;
+#else
+ params.workload = workload;
+#endif // FULL_SYSTEM
+
+ params.mem = mem;
+
+ params.max_insts_any_thread = max_insts_any_thread;
+ params.max_insts_all_threads = max_insts_all_threads;
+ params.max_loads_any_thread = max_loads_any_thread;
+ params.max_loads_all_threads = max_loads_all_threads;
+
+ //
+ // Caches
+ //
+ params.icacheInterface = icache ? icache->getInterface() : NULL;
+ params.dcacheInterface = dcache ? dcache->getInterface() : NULL;
+
+ params.decodeToFetchDelay = decodeToFetchDelay;
+ params.renameToFetchDelay = renameToFetchDelay;
+ params.iewToFetchDelay = iewToFetchDelay;
+ params.commitToFetchDelay = commitToFetchDelay;
+ params.fetchWidth = fetchWidth;
+
+ params.renameToDecodeDelay = renameToDecodeDelay;
+ params.iewToDecodeDelay = iewToDecodeDelay;
+ params.commitToDecodeDelay = commitToDecodeDelay;
+ params.fetchToDecodeDelay = fetchToDecodeDelay;
+ params.decodeWidth = decodeWidth;
+
+ params.iewToRenameDelay = iewToRenameDelay;
+ params.commitToRenameDelay = commitToRenameDelay;
+ params.decodeToRenameDelay = decodeToRenameDelay;
+ params.renameWidth = renameWidth;
+
+ params.commitToIEWDelay = commitToIEWDelay;
+ params.renameToIEWDelay = renameToIEWDelay;
+ params.issueToExecuteDelay = issueToExecuteDelay;
+ params.issueWidth = issueWidth;
+ params.executeWidth = executeWidth;
+ params.executeIntWidth = executeIntWidth;
+ params.executeFloatWidth = executeFloatWidth;
+ params.executeBranchWidth = executeBranchWidth;
+ params.executeMemoryWidth = executeMemoryWidth;
+
+ params.iewToCommitDelay = iewToCommitDelay;
+ params.renameToROBDelay = renameToROBDelay;
+ params.commitWidth = commitWidth;
+ params.squashWidth = squashWidth;
+#if 0
+ params.localPredictorSize = localPredictorSize;
+ params.localPredictorCtrBits = localPredictorCtrBits;
+#endif
+ params.local_predictor_size = local_predictor_size;
+ params.local_ctr_bits = local_ctr_bits;
+ params.local_history_table_size = local_history_table_size;
+ params.local_history_bits = local_history_bits;
+ params.global_predictor_size = global_predictor_size;
+ params.global_ctr_bits = global_ctr_bits;
+ params.global_history_bits = global_history_bits;
+ params.choice_predictor_size = choice_predictor_size;
+ params.choice_ctr_bits = choice_ctr_bits;
+
+ params.BTBEntries = BTBEntries;
+ params.BTBTagSize = BTBTagSize;
+
+ params.RASSize = RASSize;
+
+ params.LQEntries = LQEntries;
+ params.SQEntries = SQEntries;
+ params.SSITSize = SSITSize;
+ params.LFSTSize = LFSTSize;
+
+ params.numPhysIntRegs = numPhysIntRegs;
+ params.numPhysFloatRegs = numPhysFloatRegs;
+ params.numIQEntries = numIQEntries;
+ params.numROBEntries = numROBEntries;
+
+ params.instShiftAmt = 2;
+
+ params.defReg = defer_registration;
+
+ params.functionTrace = function_trace;
+ params.functionTraceStart = function_trace_start;
+
+ cpu = new DerivAlphaFullCPU(params);
+
+ return cpu;
+}
+
+REGISTER_SIM_OBJECT("DerivAlphaFullCPU", DerivAlphaFullCPU)
+
diff --git a/src/cpu/o3/alpha_cpu_impl.hh b/src/cpu/o3/alpha_cpu_impl.hh
new file mode 100644
index 000000000..7c4c2b969
--- /dev/null
+++ b/src/cpu/o3/alpha_cpu_impl.hh
@@ -0,0 +1,371 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "arch/alpha/faults.hh"
+#include "base/cprintf.hh"
+#include "base/statistics.hh"
+#include "base/timebuf.hh"
+#include "mem/cache/cache.hh" // for dynamic cast
+#include "mem/mem_interface.hh"
+#include "sim/builder.hh"
+#include "sim/sim_events.hh"
+#include "sim/stats.hh"
+
+#include "cpu/o3/alpha_cpu.hh"
+#include "cpu/o3/alpha_params.hh"
+#include "cpu/o3/comm.hh"
+
+#if FULL_SYSTEM
+#include "arch/alpha/osfpal.hh"
+#include "arch/alpha/isa_traits.hh"
+#endif
+
+template <class Impl>
+AlphaFullCPU<Impl>::AlphaFullCPU(Params &params)
+ : FullO3CPU<Impl>(params)
+{
+ DPRINTF(FullCPU, "AlphaFullCPU: Creating AlphaFullCPU object.\n");
+
+ this->fetch.setCPU(this);
+ this->decode.setCPU(this);
+ this->rename.setCPU(this);
+ this->iew.setCPU(this);
+ this->commit.setCPU(this);
+
+ this->rob.setCPU(this);
+}
+
+template <class Impl>
+void
+AlphaFullCPU<Impl>::regStats()
+{
+ // Register stats for everything that has stats.
+ this->fullCPURegStats();
+ this->fetch.regStats();
+ this->decode.regStats();
+ this->rename.regStats();
+ this->iew.regStats();
+ this->commit.regStats();
+}
+
+#if !FULL_SYSTEM
+
+// Will probably need to know which thread is calling syscall
+// Will need to pass that information in to the DynInst when it is constructed,
+// so that this call can be made with the proper thread number.
+template <class Impl>
+void
+AlphaFullCPU<Impl>::syscall(short thread_num)
+{
+ DPRINTF(FullCPU, "AlphaFullCPU: Syscall() called.\n\n");
+
+ // Commit stage needs to run as well.
+ this->commit.tick();
+
+ squashStages();
+
+ // Temporarily increase this by one to account for the syscall
+ // instruction.
+ ++(this->funcExeInst);
+
+ // Copy over all important state to xc once all the unrolling is done.
+ copyToXC();
+
+ // This is hardcoded to thread 0 while the CPU is only single threaded.
+ this->thread[0]->syscall();
+
+ // Copy over all important state back to CPU.
+ copyFromXC();
+
+ // Decrease funcExeInst by one as the normal commit will handle
+ // incrememnting it.
+ --(this->funcExeInst);
+}
+
+// This is not a pretty function, and should only be used if it is necessary
+// to fake having everything squash all at once (ie for non-full system
+// syscalls). Maybe put this at the FullCPU level?
+template <class Impl>
+void
+AlphaFullCPU<Impl>::squashStages()
+{
+ InstSeqNum rob_head = this->rob.readHeadSeqNum();
+
+ // Now hack the time buffer to put this sequence number in the places
+ // where the stages might read it.
+ for (int i = 0; i < 5; ++i)
+ {
+ this->timeBuffer.access(-i)->commitInfo.doneSeqNum = rob_head;
+ }
+
+ this->fetch.squash(this->rob.readHeadNextPC());
+ this->fetchQueue.advance();
+
+ this->decode.squash();
+ this->decodeQueue.advance();
+
+ this->rename.squash();
+ this->renameQueue.advance();
+ this->renameQueue.advance();
+
+ // Be sure to advance the IEW queues so that the commit stage doesn't
+ // try to set an instruction as completed at the same time that it
+ // might be deleting it.
+ this->iew.squash();
+ this->iewQueue.advance();
+ this->iewQueue.advance();
+ // Needs to tell the LSQ to write back all of its data
+ this->iew.lsqWriteback();
+
+ this->rob.squash(rob_head);
+ this->commit.setSquashing();
+
+ // Now hack the time buffer to clear the sequence numbers in the places
+ // where the stages might read it.?
+ for (int i = 0; i < 5; ++i)
+ {
+ this->timeBuffer.access(-i)->commitInfo.doneSeqNum = 0;
+ }
+
+}
+
+#endif // FULL_SYSTEM
+
+template <class Impl>
+void
+AlphaFullCPU<Impl>::copyToXC()
+{
+ PhysRegIndex renamed_reg;
+
+ // First loop through the integer registers.
+ for (int i = 0; i < AlphaISA::NumIntRegs; ++i)
+ {
+ renamed_reg = this->renameMap.lookup(i);
+ this->cpuXC->setIntReg(i, this->regFile.readIntReg(renamed_reg));
+ DPRINTF(FullCPU, "FullCPU: Copying register %i, has data %lli.\n",
+ renamed_reg, this->regFile.intRegFile[renamed_reg]);
+ }
+
+ // Then loop through the floating point registers.
+ for (int i = 0; i < AlphaISA::NumFloatRegs; ++i)
+ {
+ renamed_reg = this->renameMap.lookup(i + AlphaISA::FP_Base_DepTag);
+ this->cpuXC->setFloatRegBits(i,
+ this->regFile.readFloatRegBits(renamed_reg));
+ }
+
+ this->cpuXC->setMiscReg(AlphaISA::Fpcr_DepTag,
+ this->regFile.readMiscReg(AlphaISA::Fpcr_DepTag));
+ this->cpuXC->setMiscReg(AlphaISA::Uniq_DepTag,
+ this->regFile.readMiscReg(AlphaISA::Uniq_DepTag));
+ this->cpuXC->setMiscReg(AlphaISA::Lock_Flag_DepTag,
+ this->regFile.readMiscReg(AlphaISA::Lock_Flag_DepTag));
+ this->cpuXC->setMiscReg(AlphaISA::Lock_Addr_DepTag,
+ this->regFile.readMiscReg(AlphaISA::Lock_Addr_DepTag));
+
+ this->cpuXC->setPC(this->rob.readHeadPC());
+ this->cpuXC->setNextPC(this->cpuXC->readPC()+4);
+
+#if !FULL_SYSTEM
+ this->cpuXC->setFuncExeInst(this->funcExeInst);
+#endif
+}
+
+// This function will probably mess things up unless the ROB is empty and
+// there are no instructions in the pipeline.
+template <class Impl>
+void
+AlphaFullCPU<Impl>::copyFromXC()
+{
+ PhysRegIndex renamed_reg;
+
+ // First loop through the integer registers.
+ for (int i = 0; i < AlphaISA::NumIntRegs; ++i)
+ {
+ renamed_reg = this->renameMap.lookup(i);
+
+ DPRINTF(FullCPU, "FullCPU: Copying over register %i, had data %lli, "
+ "now has data %lli.\n",
+ renamed_reg, this->regFile.intRegFile[renamed_reg],
+ this->cpuXC->readIntReg(i));
+
+ this->regFile.setIntReg(renamed_reg, this->cpuXC->readIntReg(i));
+ }
+
+ // Then loop through the floating point registers.
+ for (int i = 0; i < AlphaISA::NumFloatRegs; ++i)
+ {
+ renamed_reg = this->renameMap.lookup(i + AlphaISA::FP_Base_DepTag);
+ this->regFile.setFloatRegBits(renamed_reg,
+ this->cpuXC->readFloatRegBits(i));
+ }
+
+ // Then loop through the misc registers.
+ this->regFile.setMiscReg(AlphaISA::Fpcr_DepTag,
+ this->cpuXC->readMiscReg(AlphaISA::Fpcr_DepTag));
+ this->regFile.setMiscReg(AlphaISA::Uniq_DepTag,
+ this->cpuXC->readMiscReg(AlphaISA::Uniq_DepTag));
+ this->regFile.setMiscReg(AlphaISA::Lock_Flag_DepTag,
+ this->cpuXC->readMiscReg(AlphaISA::Lock_Flag_DepTag));
+ this->regFile.setMiscReg(AlphaISA::Lock_Addr_DepTag,
+ this->cpuXC->readMiscReg(AlphaISA::Lock_Addr_DepTag));
+
+ // Then finally set the PC and the next PC.
+// regFile.pc = cpuXC->regs.pc;
+// regFile.npc = cpuXC->regs.npc;
+#if !FULL_SYSTEM
+ this->funcExeInst = this->cpuXC->readFuncExeInst();
+#endif
+}
+
+#if FULL_SYSTEM
+
+template <class Impl>
+int
+AlphaFullCPU<Impl>::readIntrFlag()
+{
+ return this->regFile.readIntrFlag();
+}
+
+template <class Impl>
+void
+AlphaFullCPU<Impl>::setIntrFlag(int val)
+{
+ this->regFile.setIntrFlag(val);
+}
+
+// Can force commit stage to squash and stuff.
+template <class Impl>
+Fault
+AlphaFullCPU<Impl>::hwrei()
+{
+ if (!inPalMode())
+ return new AlphaISA::UnimplementedOpcodeFault;
+
+ this->setNextPC(this->regFile.miscRegs.readReg(AlphaISA::IPR_EXC_ADDR));
+
+// kernelStats.hwrei();
+
+ if ((this->regFile.miscRegs.readReg(AlphaISA::IPR_EXC_ADDR) & 1) == 0)
+// AlphaISA::swap_palshadow(&regs, false);
+
+ this->checkInterrupts = true;
+
+ // FIXME: XXX check for interrupts? XXX
+ return NoFault;
+}
+
+template <class Impl>
+bool
+AlphaFullCPU<Impl>::simPalCheck(int palFunc)
+{
+// kernelStats.callpal(palFunc);
+
+ switch (palFunc) {
+ case PAL::halt:
+ halt();
+ if (--System::numSystemsRunning == 0)
+ new SimExitEvent("all cpus halted");
+ break;
+
+ case PAL::bpt:
+ case PAL::bugchk:
+ if (this->system->breakpoint())
+ return false;
+ break;
+ }
+
+ return true;
+}
+
+// Probably shouldn't be able to switch to the trap handler as quickly as
+// this. Also needs to get the exception restart address from the commit
+// stage.
+template <class Impl>
+void
+AlphaFullCPU<Impl>::trap(Fault fault)
+{
+/* // Keep in mind that a trap may be initiated by fetch if there's a TLB
+ // miss
+ uint64_t PC = this->commit.readCommitPC();
+
+ DPRINTF(Fault, "Fault %s\n", fault->name());
+ this->recordEvent(csprintf("Fault %s", fault->name()));
+
+ //kernelStats.fault(fault);
+
+ if (fault->isA<ArithmeticFault>())
+ panic("Arithmetic traps are unimplemented!");
+
+ // exception restart address - Get the commit PC
+ if (!fault->isA<InterruptFault>() || !inPalMode(PC))
+ this->regFile.miscRegs.setReg(AlphaISA::IPR_EXC_ADDR, PC);
+
+ if (fault->isA<PalFault>() || fault->isA<ArithmeticFault>())
+ // || fault == InterruptFault && !PC_PAL(regs.pc)
+ {
+ // traps... skip faulting instruction
+ AlphaISA::MiscReg ipr_exc_addr =
+ this->regFile.miscRegs.readReg(AlphaISA::IPR_EXC_ADDR);
+ this->regFile.miscRegs.setReg(AlphaISA::IPR_EXC_ADDR,
+ ipr_exc_addr + 4);
+ }
+
+ if (!inPalMode(PC))
+ swapPALShadow(true);
+
+ this->regFile.setPC(this->regFile.miscRegs.readReg(AlphaISA::IPR_PAL_BASE) +
+ (dynamic_cast<AlphaFault *>(fault.get()))->vect());
+ this->regFile.setNextPC(PC + sizeof(MachInst));*/
+}
+
+template <class Impl>
+void
+AlphaFullCPU<Impl>::processInterrupts()
+{
+ // Check for interrupts here. For now can copy the code that exists
+ // within isa_fullsys_traits.hh.
+}
+
+// swap_palshadow swaps in the values of the shadow registers and
+// swaps them with the values of the physical registers that map to the
+// same logical index.
+template <class Impl>
+void
+AlphaFullCPU<Impl>::swapPALShadow(bool use_shadow)
+{
+ if (palShadowEnabled == use_shadow)
+ panic("swap_palshadow: wrong PAL shadow state");
+
+ palShadowEnabled = use_shadow;
+
+ // Will have to lookup in rename map to get physical registers, then
+ // swap.
+}
+
+#endif // FULL_SYSTEM
diff --git a/src/cpu/o3/alpha_dyn_inst.cc b/src/cpu/o3/alpha_dyn_inst.cc
new file mode 100644
index 000000000..72ac77d95
--- /dev/null
+++ b/src/cpu/o3/alpha_dyn_inst.cc
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "cpu/o3/alpha_dyn_inst_impl.hh"
+#include "cpu/o3/alpha_impl.hh"
+
+// Force instantiation of AlphaDynInst for all the implementations that
+// are needed.
+template class AlphaDynInst<AlphaSimpleImpl>;
diff --git a/src/cpu/o3/alpha_dyn_inst.hh b/src/cpu/o3/alpha_dyn_inst.hh
new file mode 100644
index 000000000..5b8a05e5c
--- /dev/null
+++ b/src/cpu/o3/alpha_dyn_inst.hh
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPU_O3_CPU_ALPHA_DYN_INST_HH__
+#define __CPU_O3_CPU_ALPHA_DYN_INST_HH__
+
+#include "cpu/base_dyn_inst.hh"
+#include "cpu/o3/alpha_cpu.hh"
+#include "cpu/o3/alpha_impl.hh"
+#include "cpu/inst_seq.hh"
+
+/**
+ * Mostly implementation specific AlphaDynInst. It is templated in case there
+ * are other implementations that are similar enough to be able to use this
+ * class without changes. This is mainly useful if there are multiple similar
+ * CPU implementations of the same ISA.
+ */
+
+template <class Impl>
+class AlphaDynInst : public BaseDynInst<Impl>
+{
+ public:
+ /** Typedef for the CPU. */
+ typedef typename Impl::FullCPU FullCPU;
+
+ /** Binary machine instruction type. */
+ typedef TheISA::MachInst MachInst;
+ /** Logical register index type. */
+ typedef TheISA::RegIndex RegIndex;
+ /** Integer register index type. */
+ typedef TheISA::IntReg IntReg;
+ /** Misc register index type. */
+ typedef TheISA::MiscReg MiscReg;
+
+ enum {
+ MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs
+ MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs
+ };
+
+ public:
+ /** BaseDynInst constructor given a binary instruction. */
+ AlphaDynInst(MachInst inst, Addr PC, Addr Pred_PC, InstSeqNum seq_num,
+ FullCPU *cpu);
+
+ /** BaseDynInst constructor given a static inst pointer. */
+ AlphaDynInst(StaticInstPtr &_staticInst);
+
+ /** Executes the instruction.*/
+ Fault execute()
+ {
+ return this->fault = this->staticInst->execute(this, this->traceData);
+ }
+
+ public:
+ MiscReg readMiscReg(int misc_reg)
+ {
+ // Dummy function for now.
+ // @todo: Fix this once reg file gets fixed.
+ return 0;
+ }
+
+ MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault)
+ {
+ // Dummy function for now.
+ // @todo: Fix this once reg file gets fixed.
+ return 0;
+ }
+
+ Fault setMiscReg(int misc_reg, const MiscReg &val)
+ {
+ // Dummy function for now.
+ // @todo: Fix this once reg file gets fixed.
+ return NoFault;
+ }
+
+ Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val)
+ {
+ // Dummy function for now.
+ // @todo: Fix this once reg file gets fixed.
+ return NoFault;
+ }
+
+#if FULL_SYSTEM
+ Fault hwrei();
+ int readIntrFlag();
+ void setIntrFlag(int val);
+ bool inPalMode();
+ void trap(Fault fault);
+ bool simPalCheck(int palFunc);
+#else
+ void syscall();
+#endif
+
+
+
+ private:
+ /** Physical register index of the destination registers of this
+ * instruction.
+ */
+ PhysRegIndex _destRegIdx[MaxInstDestRegs];
+
+ /** Physical register index of the source registers of this
+ * instruction.
+ */
+ PhysRegIndex _srcRegIdx[MaxInstSrcRegs];
+
+ /** Physical register index of the previous producers of the
+ * architected destinations.
+ */
+ PhysRegIndex _prevDestRegIdx[MaxInstDestRegs];
+
+ public:
+
+ // The register accessor methods provide the index of the
+ // instruction's operand (e.g., 0 or 1), not the architectural
+ // register index, to simplify the implementation of register
+ // renaming. We find the architectural register index by indexing
+ // into the instruction's own operand index table. Note that a
+ // raw pointer to the StaticInst is provided instead of a
+ // ref-counted StaticInstPtr to redice overhead. This is fine as
+ // long as these methods don't copy the pointer into any long-term
+ // storage (which is pretty hard to imagine they would have reason
+ // to do).
+
+ uint64_t readIntReg(const StaticInst *si, int idx)
+ {
+ return this->cpu->readIntReg(_srcRegIdx[idx]);
+ }
+
+ FloatReg readFloatReg(const StaticInst *si, int idx, int width)
+ {
+ return this->cpu->readFloatReg(_srcRegIdx[idx], width);
+ }
+
+ FloatReg readFloatReg(const StaticInst *si, int idx)
+ {
+ return this->cpu->readFloatReg(_srcRegIdx[idx]);
+ }
+
+ FloatRegBits readFloatRegBits(const StaticInst *si, int idx, int width)
+ {
+ return this->cpu->readFloatRegBits(_srcRegIdx[idx], width);
+ }
+
+ FloatRegBits readFloatRegBits(const StaticInst *si, int idx)
+ {
+ return this->cpu->readFloatRegBits(_srcRegIdx[idx]);
+ }
+
+ /** @todo: Make results into arrays so they can handle multiple dest
+ * registers.
+ */
+ void setIntReg(const StaticInst *si, int idx, uint64_t val)
+ {
+ this->cpu->setIntReg(_destRegIdx[idx], val);
+ this->instResult.integer = val;
+ }
+
+ void setFloatReg(const StaticInst *si, int idx, FloatReg val, int width)
+ {
+ this->cpu->setFloatReg(_destRegIdx[idx], val, width);
+ this->instResult.fp = val;
+ }
+
+ void setFloatReg(const StaticInst *si, int idx, FloatReg val)
+ {
+ this->cpu->setFloatReg(_destRegIdx[idx], val);
+ this->instResult.dbl = val;
+ }
+
+ void setFloatRegBits(const StaticInst *si, int idx,
+ FloatRegBits val, int width)
+ {
+ this->cpu->setFloatRegBits(_destRegIdx[idx], val, width);
+ this->instResult.integer = val;
+ }
+
+ void setFloatRegBits(const StaticInst *si, int idx, FloatRegBits val)
+ {
+ this->cpu->setFloatRegBits(_destRegIdx[idx], val);
+ this->instResult.integer = val;
+ }
+
+ /** Returns the physical register index of the i'th destination
+ * register.
+ */
+ PhysRegIndex renamedDestRegIdx(int idx) const
+ {
+ return _destRegIdx[idx];
+ }
+
+ /** Returns the physical register index of the i'th source register. */
+ PhysRegIndex renamedSrcRegIdx(int idx) const
+ {
+ return _srcRegIdx[idx];
+ }
+
+ /** Returns the physical register index of the previous physical register
+ * that remapped to the same logical register index.
+ */
+ PhysRegIndex prevDestRegIdx(int idx) const
+ {
+ return _prevDestRegIdx[idx];
+ }
+
+ /** Renames a destination register to a physical register. Also records
+ * the previous physical register that the logical register mapped to.
+ */
+ void renameDestReg(int idx,
+ PhysRegIndex renamed_dest,
+ PhysRegIndex previous_rename)
+ {
+ _destRegIdx[idx] = renamed_dest;
+ _prevDestRegIdx[idx] = previous_rename;
+ }
+
+ /** Renames a source logical register to the physical register which
+ * has/will produce that logical register's result.
+ * @todo: add in whether or not the source register is ready.
+ */
+ void renameSrcReg(int idx, PhysRegIndex renamed_src)
+ {
+ _srcRegIdx[idx] = renamed_src;
+ }
+
+ public:
+ Fault calcEA()
+ {
+ return this->staticInst->eaCompInst()->execute(this, this->traceData);
+ }
+
+ Fault memAccess()
+ {
+ return this->staticInst->memAccInst()->execute(this, this->traceData);
+ }
+};
+
+#endif // __CPU_O3_CPU_ALPHA_DYN_INST_HH__
+
diff --git a/src/cpu/o3/alpha_dyn_inst_impl.hh b/src/cpu/o3/alpha_dyn_inst_impl.hh
new file mode 100644
index 000000000..96b7d3430
--- /dev/null
+++ b/src/cpu/o3/alpha_dyn_inst_impl.hh
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "cpu/o3/alpha_dyn_inst.hh"
+
+template <class Impl>
+AlphaDynInst<Impl>::AlphaDynInst(MachInst inst, Addr PC, Addr Pred_PC,
+ InstSeqNum seq_num, FullCPU *cpu)
+ : BaseDynInst<Impl>(inst, PC, Pred_PC, seq_num, cpu)
+{
+ // Make sure to have the renamed register entries set to the same
+ // as the normal register entries. It will allow the IQ to work
+ // without any modifications.
+ for (int i = 0; i < this->staticInst->numDestRegs(); i++)
+ {
+ _destRegIdx[i] = this->staticInst->destRegIdx(i);
+ }
+
+ for (int i = 0; i < this->staticInst->numSrcRegs(); i++)
+ {
+ _srcRegIdx[i] = this->staticInst->srcRegIdx(i);
+ this->_readySrcRegIdx[i] = 0;
+ }
+
+}
+
+template <class Impl>
+AlphaDynInst<Impl>::AlphaDynInst(StaticInstPtr &_staticInst)
+ : BaseDynInst<Impl>(_staticInst)
+{
+ // Make sure to have the renamed register entries set to the same
+ // as the normal register entries. It will allow the IQ to work
+ // without any modifications.
+ for (int i = 0; i < _staticInst->numDestRegs(); i++)
+ {
+ _destRegIdx[i] = _staticInst->destRegIdx(i);
+ }
+
+ for (int i = 0; i < _staticInst->numSrcRegs(); i++)
+ {
+ _srcRegIdx[i] = _staticInst->srcRegIdx(i);
+ }
+}
+
+#if FULL_SYSTEM
+template <class Impl>
+Fault
+AlphaDynInst<Impl>::hwrei()
+{
+ return this->cpu->hwrei();
+}
+
+template <class Impl>
+int
+AlphaDynInst<Impl>::readIntrFlag()
+{
+return this->cpu->readIntrFlag();
+}
+
+template <class Impl>
+void
+AlphaDynInst<Impl>::setIntrFlag(int val)
+{
+ this->cpu->setIntrFlag(val);
+}
+
+template <class Impl>
+bool
+AlphaDynInst<Impl>::inPalMode()
+{
+ return this->cpu->inPalMode();
+}
+
+template <class Impl>
+void
+AlphaDynInst<Impl>::trap(Fault fault)
+{
+ this->cpu->trap(fault);
+}
+
+template <class Impl>
+bool
+AlphaDynInst<Impl>::simPalCheck(int palFunc)
+{
+ return this->cpu->simPalCheck(palFunc);
+}
+#else
+template <class Impl>
+void
+AlphaDynInst<Impl>::syscall()
+{
+ this->cpu->syscall(this->threadNumber);
+}
+#endif
+
diff --git a/src/cpu/o3/alpha_impl.hh b/src/cpu/o3/alpha_impl.hh
new file mode 100644
index 000000000..5e39fcb37
--- /dev/null
+++ b/src/cpu/o3/alpha_impl.hh
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPU_O3_CPU_ALPHA_IMPL_HH__
+#define __CPU_O3_CPU_ALPHA_IMPL_HH__
+
+#include "arch/alpha/isa_traits.hh"
+
+#include "cpu/o3/alpha_params.hh"
+#include "cpu/o3/cpu_policy.hh"
+
+// Forward declarations.
+template <class Impl>
+class AlphaDynInst;
+
+template <class Impl>
+class AlphaFullCPU;
+
+/** Implementation specific struct that defines several key things to the
+ * CPU, the stages within the CPU, the time buffers, and the DynInst.
+ * The struct defines the ISA, the CPU policy, the specific DynInst, the
+ * specific FullCPU, and all of the structs from the time buffers to do
+ * communication.
+ * This is one of the key things that must be defined for each hardware
+ * specific CPU implementation.
+ */
+struct AlphaSimpleImpl
+{
+ /** The type of MachInst. */
+ typedef TheISA::MachInst MachInst;
+
+ /** The CPU policy to be used (ie fetch, decode, etc.). */
+ typedef SimpleCPUPolicy<AlphaSimpleImpl> CPUPol;
+
+ /** The DynInst to be used. */
+ typedef AlphaDynInst<AlphaSimpleImpl> DynInst;
+
+ /** The refcounted DynInst pointer to be used. In most cases this is
+ * what should be used, and not DynInst *.
+ */
+ typedef RefCountingPtr<DynInst> DynInstPtr;
+
+ /** The FullCPU to be used. */
+ typedef AlphaFullCPU<AlphaSimpleImpl> FullCPU;
+
+ /** The Params to be passed to each stage. */
+ typedef AlphaSimpleParams Params;
+
+ enum {
+ MaxWidth = 8
+ };
+};
+
+#endif // __CPU_O3_CPU_ALPHA_IMPL_HH__
diff --git a/src/cpu/o3/alpha_params.hh b/src/cpu/o3/alpha_params.hh
new file mode 100644
index 000000000..79b0937e3
--- /dev/null
+++ b/src/cpu/o3/alpha_params.hh
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPU_O3_CPU_ALPHA_SIMPLE_PARAMS_HH__
+#define __CPU_O3_CPU_ALPHA_SIMPLE_PARAMS_HH__
+
+#include "cpu/o3/cpu.hh"
+
+//Forward declarations
+class System;
+class AlphaITB;
+class AlphaDTB;
+class FunctionalMemory;
+class Process;
+class MemInterface;
+
+/**
+ * This file defines the parameters that will be used for the AlphaFullCPU.
+ * This must be defined externally so that the Impl can have a params class
+ * defined that it can pass to all of the individual stages.
+ */
+
+class AlphaSimpleParams : public BaseFullCPU::Params
+{
+ public:
+
+#if FULL_SYSTEM
+ AlphaITB *itb; AlphaDTB *dtb;
+#else
+ std::vector<Process *> workload;
+ Process *process;
+#endif // FULL_SYSTEM
+
+ FunctionalMemory *mem;
+
+ //
+ // Caches
+ //
+ MemInterface *icacheInterface;
+ MemInterface *dcacheInterface;
+
+ //
+ // Fetch
+ //
+ unsigned decodeToFetchDelay;
+ unsigned renameToFetchDelay;
+ unsigned iewToFetchDelay;
+ unsigned commitToFetchDelay;
+ unsigned fetchWidth;
+
+ //
+ // Decode
+ //
+ unsigned renameToDecodeDelay;
+ unsigned iewToDecodeDelay;
+ unsigned commitToDecodeDelay;
+ unsigned fetchToDecodeDelay;
+ unsigned decodeWidth;
+
+ //
+ // Rename
+ //
+ unsigned iewToRenameDelay;
+ unsigned commitToRenameDelay;
+ unsigned decodeToRenameDelay;
+ unsigned renameWidth;
+
+ //
+ // IEW
+ //
+ unsigned commitToIEWDelay;
+ unsigned renameToIEWDelay;
+ unsigned issueToExecuteDelay;
+ unsigned issueWidth;
+ unsigned executeWidth;
+ unsigned executeIntWidth;
+ unsigned executeFloatWidth;
+ unsigned executeBranchWidth;
+ unsigned executeMemoryWidth;
+
+ //
+ // Commit
+ //
+ unsigned iewToCommitDelay;
+ unsigned renameToROBDelay;
+ unsigned commitWidth;
+ unsigned squashWidth;
+
+ //
+ // Branch predictor (BP & BTB)
+ //
+/*
+ unsigned localPredictorSize;
+ unsigned localPredictorCtrBits;
+*/
+
+ unsigned local_predictor_size;
+ unsigned local_ctr_bits;
+ unsigned local_history_table_size;
+ unsigned local_history_bits;
+ unsigned global_predictor_size;
+ unsigned global_ctr_bits;
+ unsigned global_history_bits;
+ unsigned choice_predictor_size;
+ unsigned choice_ctr_bits;
+
+ unsigned BTBEntries;
+ unsigned BTBTagSize;
+
+ unsigned RASSize;
+
+ //
+ // Load store queue
+ //
+ unsigned LQEntries;
+ unsigned SQEntries;
+
+ //
+ // Memory dependence
+ //
+ unsigned SSITSize;
+ unsigned LFSTSize;
+
+ //
+ // Miscellaneous
+ //
+ unsigned numPhysIntRegs;
+ unsigned numPhysFloatRegs;
+ unsigned numIQEntries;
+ unsigned numROBEntries;
+
+ // Probably can get this from somewhere.
+ unsigned instShiftAmt;
+
+ bool defReg;
+};
+
+#endif // __CPU_O3_CPU_ALPHA_PARAMS_HH__
diff --git a/src/cpu/o3/bpred_unit.cc b/src/cpu/o3/bpred_unit.cc
new file mode 100644
index 000000000..85bd6f0a6
--- /dev/null
+++ b/src/cpu/o3/bpred_unit.cc
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "cpu/o3/bpred_unit_impl.hh"
+#include "cpu/o3/alpha_impl.hh"
+#include "cpu/o3/alpha_dyn_inst.hh"
+
+template class TwobitBPredUnit<AlphaSimpleImpl>;
diff --git a/src/cpu/o3/bpred_unit.hh b/src/cpu/o3/bpred_unit.hh
new file mode 100644
index 000000000..2725684f7
--- /dev/null
+++ b/src/cpu/o3/bpred_unit.hh
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BPRED_UNIT_HH__
+#define __BPRED_UNIT_HH__
+
+// For Addr type.
+#include "arch/isa_traits.hh"
+#include "base/statistics.hh"
+#include "cpu/inst_seq.hh"
+
+#include "cpu/o3/2bit_local_pred.hh"
+#include "cpu/o3/tournament_pred.hh"
+#include "cpu/o3/btb.hh"
+#include "cpu/o3/ras.hh"
+
+#include <list>
+
+/**
+ * Basically a wrapper class to hold both the branch predictor
+ * and the BTB. Right now I'm unsure of the implementation; it would
+ * be nicer to have something closer to the CPUPolicy or the Impl where
+ * this is just typedefs, but it forces the upper level stages to be
+ * aware of the constructors of the BP and the BTB. The nicer thing
+ * to do is have this templated on the Impl, accept the usual Params
+ * object, and be able to call the constructors on the BP and BTB.
+ */
+template<class Impl>
+class TwobitBPredUnit
+{
+ public:
+ typedef typename Impl::Params Params;
+ typedef typename Impl::DynInstPtr DynInstPtr;
+
+ TwobitBPredUnit(Params &params);
+
+ void regStats();
+
+ bool predict(DynInstPtr &inst, Addr &PC);
+
+ void update(const InstSeqNum &done_sn);
+
+ void squash(const InstSeqNum &squashed_sn);
+
+ void squash(const InstSeqNum &squashed_sn, const Addr &corr_target,
+ bool actually_taken);
+
+ bool BPLookup(Addr &inst_PC)
+ { return BP.lookup(inst_PC); }
+
+ bool BTBValid(Addr &inst_PC)
+ { return BTB.valid(inst_PC); }
+
+ Addr BTBLookup(Addr &inst_PC)
+ { return BTB.lookup(inst_PC); }
+
+ // Will want to include global history.
+ void BPUpdate(Addr &inst_PC, bool taken)
+ { BP.update(inst_PC, taken); }
+
+ void BTBUpdate(Addr &inst_PC, Addr &target_PC)
+ { BTB.update(inst_PC, target_PC); }
+
+ private:
+ struct PredictorHistory {
+ PredictorHistory(const InstSeqNum &seq_num, const Addr &inst_PC,
+ const bool pred_taken)
+ : seqNum(seq_num), PC(inst_PC), predTaken(pred_taken),
+ globalHistory(0), usedRAS(0), wasCall(0), RASIndex(0),
+ RASTarget(0)
+ { }
+
+ InstSeqNum seqNum;
+
+ Addr PC;
+
+ bool predTaken;
+
+ unsigned globalHistory;
+
+ bool usedRAS;
+
+ bool wasCall;
+
+ unsigned RASIndex;
+
+ Addr RASTarget;
+ };
+
+ std::list<PredictorHistory> predHist;
+
+ DefaultBP BP;
+
+ DefaultBTB BTB;
+
+ ReturnAddrStack RAS;
+
+ Stats::Scalar<> lookups;
+ Stats::Scalar<> condPredicted;
+ Stats::Scalar<> condIncorrect;
+ Stats::Scalar<> BTBLookups;
+ Stats::Scalar<> BTBHits;
+ Stats::Scalar<> BTBCorrect;
+ Stats::Scalar<> usedRAS;
+ Stats::Scalar<> RASIncorrect;
+};
+
+#endif // __BPRED_UNIT_HH__
diff --git a/src/cpu/o3/bpred_unit_impl.hh b/src/cpu/o3/bpred_unit_impl.hh
new file mode 100644
index 000000000..8d16a0cdf
--- /dev/null
+++ b/src/cpu/o3/bpred_unit_impl.hh
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "base/trace.hh"
+#include "base/traceflags.hh"
+#include "cpu/o3/bpred_unit.hh"
+
+template<class Impl>
+TwobitBPredUnit<Impl>::TwobitBPredUnit(Params &params)
+ : BP(params.local_predictor_size,
+ params.local_ctr_bits,
+ params.instShiftAmt),
+ BTB(params.BTBEntries,
+ params.BTBTagSize,
+ params.instShiftAmt),
+ RAS(params.RASSize)
+{
+}
+
+template <class Impl>
+void
+TwobitBPredUnit<Impl>::regStats()
+{
+ lookups
+ .name(name() + ".BPredUnit.lookups")
+ .desc("Number of BP lookups")
+ ;
+
+ condPredicted
+ .name(name() + ".BPredUnit.condPredicted")
+ .desc("Number of conditional branches predicted")
+ ;
+
+ condIncorrect
+ .name(name() + ".BPredUnit.condIncorrect")
+ .desc("Number of conditional branches incorrect")
+ ;
+
+ BTBLookups
+ .name(name() + ".BPredUnit.BTBLookups")
+ .desc("Number of BTB lookups")
+ ;
+
+ BTBHits
+ .name(name() + ".BPredUnit.BTBHits")
+ .desc("Number of BTB hits")
+ ;
+
+ BTBCorrect
+ .name(name() + ".BPredUnit.BTBCorrect")
+ .desc("Number of correct BTB predictions (this stat may not "
+ "work properly.")
+ ;
+
+ usedRAS
+ .name(name() + ".BPredUnit.usedRAS")
+ .desc("Number of times the RAS was used.")
+ ;
+
+ RASIncorrect
+ .name(name() + ".BPredUnit.RASInCorrect")
+ .desc("Number of incorrect RAS predictions.")
+ ;
+}
+
+template <class Impl>
+bool
+TwobitBPredUnit<Impl>::predict(DynInstPtr &inst, Addr &PC)
+{
+ // See if branch predictor predicts taken.
+ // If so, get its target addr either from the BTB or the RAS.
+ // Once that's done, speculatively update the predictor?
+ // Save off record of branch stuff so the RAS can be fixed
+ // up once it's done.
+
+ using TheISA::MachInst;
+
+ bool pred_taken = false;
+ Addr target;
+
+ ++lookups;
+
+ if (inst->isUncondCtrl()) {
+ DPRINTF(Fetch, "BranchPred: Unconditional control.\n");
+ pred_taken = true;
+ } else {
+ ++condPredicted;
+
+ pred_taken = BPLookup(PC);
+
+ DPRINTF(Fetch, "BranchPred: Branch predictor predicted %i for PC %#x"
+ "\n", pred_taken, inst->readPC());
+ }
+
+ PredictorHistory predict_record(inst->seqNum, PC, pred_taken);
+
+ // Now lookup in the BTB or RAS.
+ if (pred_taken) {
+ if (inst->isReturn()) {
+ ++usedRAS;
+
+ // If it's a function return call, then look up the address
+ // in the RAS.
+ target = RAS.top();
+
+ // Record the top entry of the RAS, and its index.
+ predict_record.usedRAS = true;
+ predict_record.RASIndex = RAS.topIdx();
+ predict_record.RASTarget = target;
+
+ RAS.pop();
+
+ DPRINTF(Fetch, "BranchPred: Instruction %#x is a return, RAS "
+ "predicted target: %#x, RAS index: %i.\n",
+ inst->readPC(), target, predict_record.RASIndex);
+ } else {
+ ++BTBLookups;
+
+ if (inst->isCall()) {
+ RAS.push(PC+sizeof(MachInst));
+
+ // Record that it was a call so that the top RAS entry can
+ // be popped off if the speculation is incorrect.
+ predict_record.wasCall = true;
+
+ DPRINTF(Fetch, "BranchPred: Instruction %#x was a call, "
+ "adding %#x to the RAS.\n",
+ inst->readPC(), PC+sizeof(MachInst));
+ }
+
+ if (BTB.valid(PC)) {
+ ++BTBHits;
+
+ //If it's anything else, use the BTB to get the target addr.
+ target = BTB.lookup(PC);
+
+ DPRINTF(Fetch, "BranchPred: Instruction %#x predicted target "
+ "is %#x.\n", inst->readPC(), target);
+
+ } else {
+ DPRINTF(Fetch, "BranchPred: BTB doesn't have a valid entry."
+ "\n");
+ pred_taken = false;
+ }
+
+ }
+ }
+
+ if (pred_taken) {
+ // Set the PC and the instruction's predicted target.
+ PC = target;
+ inst->setPredTarg(target);
+ } else {
+ PC = PC + sizeof(MachInst);
+ inst->setPredTarg(PC);
+ }
+
+ predHist.push_front(predict_record);
+
+ assert(!predHist.empty());
+
+ return pred_taken;
+}
+
+template <class Impl>
+void
+TwobitBPredUnit<Impl>::update(const InstSeqNum &done_sn)
+{
+ DPRINTF(Fetch, "BranchPred: Commiting branches until sequence number "
+ "%i.\n", done_sn);
+
+ while (!predHist.empty() && predHist.back().seqNum <= done_sn) {
+ assert(!predHist.empty());
+
+ // Update the branch predictor with the correct results of branches.
+ BP.update(predHist.back().PC, predHist.back().predTaken);
+
+ predHist.pop_back();
+ }
+}
+
+template <class Impl>
+void
+TwobitBPredUnit<Impl>::squash(const InstSeqNum &squashed_sn)
+{
+ while (!predHist.empty() && predHist.front().seqNum > squashed_sn) {
+ if (predHist.front().usedRAS) {
+ DPRINTF(Fetch, "BranchPred: Restoring top of RAS to: %i, "
+ "target: %#x.\n",
+ predHist.front().RASIndex,
+ predHist.front().RASTarget);
+
+ RAS.restore(predHist.front().RASIndex,
+ predHist.front().RASTarget);
+ } else if (predHist.front().wasCall) {
+ DPRINTF(Fetch, "BranchPred: Removing speculative entry added "
+ "to the RAS.\n");
+
+ RAS.pop();
+ }
+
+ predHist.pop_front();
+ }
+}
+
+template <class Impl>
+void
+TwobitBPredUnit<Impl>::squash(const InstSeqNum &squashed_sn,
+ const Addr &corr_target,
+ const bool actually_taken)
+{
+ // Now that we know that a branch was mispredicted, we need to undo
+ // all the branches that have been seen up until this branch and
+ // fix up everything.
+
+ ++condIncorrect;
+
+ DPRINTF(Fetch, "BranchPred: Squashing from sequence number %i, "
+ "setting target to %#x.\n",
+ squashed_sn, corr_target);
+
+ while (!predHist.empty() && predHist.front().seqNum > squashed_sn) {
+
+ if (predHist.front().usedRAS) {
+ DPRINTF(Fetch, "BranchPred: Restoring top of RAS to: %i, "
+ "target: %#x.\n",
+ predHist.front().RASIndex,
+ predHist.front().RASTarget);
+
+ RAS.restore(predHist.front().RASIndex,
+ predHist.front().RASTarget);
+ } else if (predHist.front().wasCall) {
+ DPRINTF(Fetch, "BranchPred: Removing speculative entry added "
+ "to the RAS.\n");
+
+ RAS.pop();
+ }
+
+ predHist.pop_front();
+ }
+
+ predHist.front().predTaken = actually_taken;
+
+ if (predHist.front().usedRAS) {
+ ++RASIncorrect;
+ }
+
+ BP.update(predHist.front().PC, actually_taken);
+
+ BTB.update(predHist.front().PC, corr_target);
+}
diff --git a/src/cpu/o3/btb.cc b/src/cpu/o3/btb.cc
new file mode 100644
index 000000000..2d39c3856
--- /dev/null
+++ b/src/cpu/o3/btb.cc
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "base/intmath.hh"
+#include "base/trace.hh"
+#include "cpu/o3/btb.hh"
+
+using namespace TheISA;
+
+DefaultBTB::DefaultBTB(unsigned _numEntries,
+ unsigned _tagBits,
+ unsigned _instShiftAmt)
+ : numEntries(_numEntries),
+ tagBits(_tagBits),
+ instShiftAmt(_instShiftAmt)
+{
+ // @todo Check to make sure num_entries is valid (a power of 2)
+
+ DPRINTF(Fetch, "BTB: Creating BTB object.\n");
+
+ btb = new BTBEntry[numEntries];
+
+ for (int i = 0; i < numEntries; ++i)
+ {
+ btb[i].valid = false;
+ }
+
+ idxMask = numEntries - 1;
+
+ tagMask = (1 << tagBits) - 1;
+
+ tagShiftAmt = instShiftAmt + floorLog2(numEntries);
+}
+
+inline
+unsigned
+DefaultBTB::getIndex(const Addr &inst_PC)
+{
+ // Need to shift PC over by the word offset.
+ return (inst_PC >> instShiftAmt) & idxMask;
+}
+
+inline
+Addr
+DefaultBTB::getTag(const Addr &inst_PC)
+{
+ return (inst_PC >> tagShiftAmt) & tagMask;
+}
+
+bool
+DefaultBTB::valid(const Addr &inst_PC)
+{
+ unsigned btb_idx = getIndex(inst_PC);
+
+ Addr inst_tag = getTag(inst_PC);
+
+ assert(btb_idx < numEntries);
+
+ if (btb[btb_idx].valid && inst_tag == btb[btb_idx].tag) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+// @todo Create some sort of return struct that has both whether or not the
+// address is valid, and also the address. For now will just use addr = 0 to
+// represent invalid entry.
+Addr
+DefaultBTB::lookup(const Addr &inst_PC)
+{
+ unsigned btb_idx = getIndex(inst_PC);
+
+ Addr inst_tag = getTag(inst_PC);
+
+ assert(btb_idx < numEntries);
+
+ if (btb[btb_idx].valid && inst_tag == btb[btb_idx].tag) {
+ return btb[btb_idx].target;
+ } else {
+ return 0;
+ }
+}
+
+void
+DefaultBTB::update(const Addr &inst_PC, const Addr &target)
+{
+ unsigned btb_idx = getIndex(inst_PC);
+
+ assert(btb_idx < numEntries);
+
+ btb[btb_idx].valid = true;
+ btb[btb_idx].target = target;
+ btb[btb_idx].tag = getTag(inst_PC);
+}
diff --git a/src/cpu/o3/btb.hh b/src/cpu/o3/btb.hh
new file mode 100644
index 000000000..77bdc32ea
--- /dev/null
+++ b/src/cpu/o3/btb.hh
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPU_O3_CPU_BTB_HH__
+#define __CPU_O3_CPU_BTB_HH__
+
+// For Addr type.
+#include "arch/isa_traits.hh"
+
+class DefaultBTB
+{
+ private:
+ struct BTBEntry
+ {
+ BTBEntry()
+ : tag(0), target(0), valid(false)
+ {
+ }
+
+ Addr tag;
+ Addr target;
+ bool valid;
+ };
+
+ public:
+ DefaultBTB(unsigned numEntries, unsigned tagBits,
+ unsigned instShiftAmt);
+
+ Addr lookup(const Addr &inst_PC);
+
+ bool valid(const Addr &inst_PC);
+
+ void update(const Addr &inst_PC, const Addr &target_PC);
+
+ private:
+ inline unsigned getIndex(const Addr &inst_PC);
+
+ inline Addr getTag(const Addr &inst_PC);
+
+ BTBEntry *btb;
+
+ unsigned numEntries;
+
+ unsigned idxMask;
+
+ unsigned tagBits;
+
+ unsigned tagMask;
+
+ unsigned instShiftAmt;
+
+ unsigned tagShiftAmt;
+};
+
+#endif // __CPU_O3_CPU_BTB_HH__
diff --git a/src/cpu/o3/comm.hh b/src/cpu/o3/comm.hh
new file mode 100644
index 000000000..c74c77ddf
--- /dev/null
+++ b/src/cpu/o3/comm.hh
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPU_O3_CPU_COMM_HH__
+#define __CPU_O3_CPU_COMM_HH__
+
+#include <vector>
+
+#include "arch/isa_traits.hh"
+#include "cpu/inst_seq.hh"
+#include "sim/host.hh"
+
+// Find better place to put this typedef.
+// The impl might be the best place for this.
+typedef short int PhysRegIndex;
+
+template<class Impl>
+struct SimpleFetchSimpleDecode {
+ typedef typename Impl::DynInstPtr DynInstPtr;
+
+ int size;
+
+ DynInstPtr insts[Impl::MaxWidth];
+};
+
+template<class Impl>
+struct SimpleDecodeSimpleRename {
+ typedef typename Impl::DynInstPtr DynInstPtr;
+
+ int size;
+
+ DynInstPtr insts[Impl::MaxWidth];
+};
+
+template<class Impl>
+struct SimpleRenameSimpleIEW {
+ typedef typename Impl::DynInstPtr DynInstPtr;
+
+ int size;
+
+ DynInstPtr insts[Impl::MaxWidth];
+};
+
+template<class Impl>
+struct SimpleIEWSimpleCommit {
+ typedef typename Impl::DynInstPtr DynInstPtr;
+
+ int size;
+
+ DynInstPtr insts[Impl::MaxWidth];
+
+ bool squash;
+ bool branchMispredict;
+ bool branchTaken;
+ uint64_t mispredPC;
+ uint64_t nextPC;
+ InstSeqNum squashedSeqNum;
+};
+
+template<class Impl>
+struct IssueStruct {
+ typedef typename Impl::DynInstPtr DynInstPtr;
+
+ int size;
+
+ DynInstPtr insts[Impl::MaxWidth];
+};
+
+struct TimeBufStruct {
+ struct decodeComm {
+ bool squash;
+ bool stall;
+ bool predIncorrect;
+ uint64_t branchAddr;
+
+ InstSeqNum doneSeqNum;
+
+ // Might want to package this kind of branch stuff into a single
+ // struct as it is used pretty frequently.
+ bool branchMispredict;
+ bool branchTaken;
+ uint64_t mispredPC;
+ uint64_t nextPC;
+ };
+
+ decodeComm decodeInfo;
+
+ // Rename can't actually tell anything to squash or send a new PC back
+ // because it doesn't do anything along those lines. But maybe leave
+ // these fields in here to keep the stages mostly orthagonal.
+ struct renameComm {
+ bool squash;
+ bool stall;
+
+ uint64_t nextPC;
+ };
+
+ renameComm renameInfo;
+
+ struct iewComm {
+ bool stall;
+
+ // Also eventually include skid buffer space.
+ unsigned freeIQEntries;
+ };
+
+ iewComm iewInfo;
+
+ struct commitComm {
+ bool squash;
+ bool stall;
+ unsigned freeROBEntries;
+
+ bool branchMispredict;
+ bool branchTaken;
+ uint64_t mispredPC;
+ uint64_t nextPC;
+
+ bool robSquashing;
+
+ // Represents the instruction that has either been retired or
+ // squashed. Similar to having a single bus that broadcasts the
+ // retired or squashed sequence number.
+ InstSeqNum doneSeqNum;
+
+ // Extra bit of information so that the LDSTQ only updates when it
+ // needs to.
+ bool commitIsLoad;
+
+ // Communication specifically to the IQ to tell the IQ that it can
+ // schedule a non-speculative instruction.
+ InstSeqNum nonSpecSeqNum;
+ };
+
+ commitComm commitInfo;
+};
+
+#endif //__CPU_O3_CPU_COMM_HH__
diff --git a/src/cpu/o3/commit.cc b/src/cpu/o3/commit.cc
new file mode 100644
index 000000000..cf33d7f8b
--- /dev/null
+++ b/src/cpu/o3/commit.cc
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "cpu/o3/alpha_dyn_inst.hh"
+#include "cpu/o3/alpha_impl.hh"
+#include "cpu/o3/commit_impl.hh"
+
+template class SimpleCommit<AlphaSimpleImpl>;
diff --git a/src/cpu/o3/commit.hh b/src/cpu/o3/commit.hh
new file mode 100644
index 000000000..580c1a316
--- /dev/null
+++ b/src/cpu/o3/commit.hh
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Todo: Maybe have a special method for handling interrupts/traps.
+//
+// Traps: Have IEW send a signal to commit saying that there's a trap to
+// be handled. Have commit send the PC back to the fetch stage, along
+// with the current commit PC. Fetch will directly access the IPR and save
+// off all the proper stuff. Commit can send out a squash, or something
+// close to it.
+// Do the same for hwrei(). However, requires that commit be specifically
+// built to support that kind of stuff. Probably not horrible to have
+// commit support having the CPU tell it to squash the other stages and
+// restart at a given address. The IPR register does become an issue.
+// Probably not a big deal if the IPR stuff isn't cycle accurate. Can just
+// have the original function handle writing to the IPR register.
+
+#ifndef __CPU_O3_CPU_SIMPLE_COMMIT_HH__
+#define __CPU_O3_CPU_SIMPLE_COMMIT_HH__
+
+#include "base/statistics.hh"
+#include "base/timebuf.hh"
+#include "mem/memory_interface.hh"
+
+template<class Impl>
+class SimpleCommit
+{
+ public:
+ // Typedefs from the Impl.
+ typedef typename Impl::FullCPU FullCPU;
+ typedef typename Impl::DynInstPtr DynInstPtr;
+ typedef typename Impl::Params Params;
+ typedef typename Impl::CPUPol CPUPol;
+
+ typedef typename CPUPol::ROB ROB;
+
+ typedef typename CPUPol::TimeStruct TimeStruct;
+ typedef typename CPUPol::IEWStruct IEWStruct;
+ typedef typename CPUPol::RenameStruct RenameStruct;
+
+ public:
+ // I don't believe commit can block, so it will only have two
+ // statuses for now.
+ // Actually if there's a cache access that needs to block (ie
+ // uncachable load or just a mem access in commit) then the stage
+ // may have to wait.
+ enum Status {
+ Running,
+ Idle,
+ ROBSquashing,
+ DcacheMissStall,
+ DcacheMissComplete
+ };
+
+ private:
+ Status _status;
+
+ public:
+ SimpleCommit(Params &params);
+
+ void regStats();
+
+ void setCPU(FullCPU *cpu_ptr);
+
+ void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr);
+
+ void setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr);
+
+ void setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr);
+
+ void setROB(ROB *rob_ptr);
+
+ void tick();
+
+ void commit();
+
+ private:
+
+ void commitInsts();
+
+ bool commitHead(DynInstPtr &head_inst, unsigned inst_num);
+
+ void getInsts();
+
+ void markCompletedInsts();
+
+ public:
+ uint64_t readCommitPC();
+
+ void setSquashing() { _status = ROBSquashing; }
+
+ private:
+ /** Time buffer interface. */
+ TimeBuffer<TimeStruct> *timeBuffer;
+
+ /** Wire to write information heading to previous stages. */
+ typename TimeBuffer<TimeStruct>::wire toIEW;
+
+ /** Wire to read information from IEW (for ROB). */
+ typename TimeBuffer<TimeStruct>::wire robInfoFromIEW;
+
+ /** IEW instruction queue interface. */
+ TimeBuffer<IEWStruct> *iewQueue;
+
+ /** Wire to read information from IEW queue. */
+ typename TimeBuffer<IEWStruct>::wire fromIEW;
+
+ /** Rename instruction queue interface, for ROB. */
+ TimeBuffer<RenameStruct> *renameQueue;
+
+ /** Wire to read information from rename queue. */
+ typename TimeBuffer<RenameStruct>::wire fromRename;
+
+ /** ROB interface. */
+ ROB *rob;
+
+ /** Pointer to FullCPU. */
+ FullCPU *cpu;
+
+ /** Memory interface. Used for d-cache accesses. */
+ MemInterface *dcacheInterface;
+
+ private:
+ /** IEW to Commit delay, in ticks. */
+ unsigned iewToCommitDelay;
+
+ /** Rename to ROB delay, in ticks. */
+ unsigned renameToROBDelay;
+
+ /** Rename width, in instructions. Used so ROB knows how many
+ * instructions to get from the rename instruction queue.
+ */
+ unsigned renameWidth;
+
+ /** IEW width, in instructions. Used so ROB knows how many
+ * instructions to get from the IEW instruction queue.
+ */
+ unsigned iewWidth;
+
+ /** Commit width, in instructions. */
+ unsigned commitWidth;
+
+ Stats::Scalar<> commitCommittedInsts;
+ Stats::Scalar<> commitSquashedInsts;
+ Stats::Scalar<> commitSquashEvents;
+ Stats::Scalar<> commitNonSpecStalls;
+ Stats::Scalar<> commitCommittedBranches;
+ Stats::Scalar<> commitCommittedLoads;
+ Stats::Scalar<> commitCommittedMemRefs;
+ Stats::Scalar<> branchMispredicts;
+
+ Stats::Distribution<> n_committed_dist;
+};
+
+#endif // __CPU_O3_CPU_SIMPLE_COMMIT_HH__
diff --git a/src/cpu/o3/commit_impl.hh b/src/cpu/o3/commit_impl.hh
new file mode 100644
index 000000000..e289bc0c0
--- /dev/null
+++ b/src/cpu/o3/commit_impl.hh
@@ -0,0 +1,502 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "base/timebuf.hh"
+#include "cpu/o3/commit.hh"
+#include "cpu/exetrace.hh"
+
+template <class Impl>
+SimpleCommit<Impl>::SimpleCommit(Params &params)
+ : dcacheInterface(params.dcacheInterface),
+ iewToCommitDelay(params.iewToCommitDelay),
+ renameToROBDelay(params.renameToROBDelay),
+ renameWidth(params.renameWidth),
+ iewWidth(params.executeWidth),
+ commitWidth(params.commitWidth)
+{
+ _status = Idle;
+}
+
+template <class Impl>
+void
+SimpleCommit<Impl>::regStats()
+{
+ commitCommittedInsts
+ .name(name() + ".commitCommittedInsts")
+ .desc("The number of committed instructions")
+ .prereq(commitCommittedInsts);
+ commitSquashedInsts
+ .name(name() + ".commitSquashedInsts")
+ .desc("The number of squashed insts skipped by commit")
+ .prereq(commitSquashedInsts);
+ commitSquashEvents
+ .name(name() + ".commitSquashEvents")
+ .desc("The number of times commit is told to squash")
+ .prereq(commitSquashEvents);
+ commitNonSpecStalls
+ .name(name() + ".commitNonSpecStalls")
+ .desc("The number of times commit has been forced to stall to "
+ "communicate backwards")
+ .prereq(commitNonSpecStalls);
+ commitCommittedBranches
+ .name(name() + ".commitCommittedBranches")
+ .desc("The number of committed branches")
+ .prereq(commitCommittedBranches);
+ commitCommittedLoads
+ .name(name() + ".commitCommittedLoads")
+ .desc("The number of committed loads")
+ .prereq(commitCommittedLoads);
+ commitCommittedMemRefs
+ .name(name() + ".commitCommittedMemRefs")
+ .desc("The number of committed memory references")
+ .prereq(commitCommittedMemRefs);
+ branchMispredicts
+ .name(name() + ".branchMispredicts")
+ .desc("The number of times a branch was mispredicted")
+ .prereq(branchMispredicts);
+ n_committed_dist
+ .init(0,commitWidth,1)
+ .name(name() + ".COM:committed_per_cycle")
+ .desc("Number of insts commited each cycle")
+ .flags(Stats::pdf)
+ ;
+}
+
+template <class Impl>
+void
+SimpleCommit<Impl>::setCPU(FullCPU *cpu_ptr)
+{
+ DPRINTF(Commit, "Commit: Setting CPU pointer.\n");
+ cpu = cpu_ptr;
+}
+
+template <class Impl>
+void
+SimpleCommit<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
+{
+ DPRINTF(Commit, "Commit: Setting time buffer pointer.\n");
+ timeBuffer = tb_ptr;
+
+ // Setup wire to send information back to IEW.
+ toIEW = timeBuffer->getWire(0);
+
+ // Setup wire to read data from IEW (for the ROB).
+ robInfoFromIEW = timeBuffer->getWire(-iewToCommitDelay);
+}
+
+template <class Impl>
+void
+SimpleCommit<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr)
+{
+ DPRINTF(Commit, "Commit: Setting rename queue pointer.\n");
+ renameQueue = rq_ptr;
+
+ // Setup wire to get instructions from rename (for the ROB).
+ fromRename = renameQueue->getWire(-renameToROBDelay);
+}
+
+template <class Impl>
+void
+SimpleCommit<Impl>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr)
+{
+ DPRINTF(Commit, "Commit: Setting IEW queue pointer.\n");
+ iewQueue = iq_ptr;
+
+ // Setup wire to get instructions from IEW.
+ fromIEW = iewQueue->getWire(-iewToCommitDelay);
+}
+
+template <class Impl>
+void
+SimpleCommit<Impl>::setROB(ROB *rob_ptr)
+{
+ DPRINTF(Commit, "Commit: Setting ROB pointer.\n");
+ rob = rob_ptr;
+}
+
+template <class Impl>
+void
+SimpleCommit<Impl>::tick()
+{
+ // If the ROB is currently in its squash sequence, then continue
+ // to squash. In this case, commit does not do anything. Otherwise
+ // run commit.
+ if (_status == ROBSquashing) {
+ if (rob->isDoneSquashing()) {
+ _status = Running;
+ } else {
+ rob->doSquash();
+
+ // Send back sequence number of tail of ROB, so other stages
+ // can squash younger instructions. Note that really the only
+ // stage that this is important for is the IEW stage; other
+ // stages can just clear all their state as long as selective
+ // replay isn't used.
+ toIEW->commitInfo.doneSeqNum = rob->readTailSeqNum();
+ toIEW->commitInfo.robSquashing = true;
+ }
+ } else {
+ commit();
+ }
+
+ markCompletedInsts();
+
+ // Writeback number of free ROB entries here.
+ DPRINTF(Commit, "Commit: ROB has %d free entries.\n",
+ rob->numFreeEntries());
+ toIEW->commitInfo.freeROBEntries = rob->numFreeEntries();
+}
+
+template <class Impl>
+void
+SimpleCommit<Impl>::commit()
+{
+ //////////////////////////////////////
+ // Check for interrupts
+ //////////////////////////////////////
+
+ // Process interrupts if interrupts are enabled and not in PAL mode.
+ // Take the PC from commit and write it to the IPR, then squash. The
+ // interrupt completing will take care of restoring the PC from that value
+ // in the IPR. Look at IPR[EXC_ADDR];
+ // hwrei() is what resets the PC to the place where instruction execution
+ // beings again.
+#if FULL_SYSTEM
+ if (//checkInterrupts &&
+ cpu->check_interrupts() &&
+ !cpu->inPalMode(readCommitPC())) {
+ // Will need to squash all instructions currently in flight and have
+ // the interrupt handler restart at the last non-committed inst.
+ // Most of that can be handled through the trap() function. The
+ // processInterrupts() function really just checks for interrupts
+ // and then calls trap() if there is an interrupt present.
+
+ // CPU will handle implementation of the interrupt.
+ cpu->processInterrupts();
+ }
+#endif // FULL_SYSTEM
+
+ ////////////////////////////////////
+ // Check for squash signal, handle that first
+ ////////////////////////////////////
+
+ // Want to mainly check if the IEW stage is telling the ROB to squash.
+ // Should I also check if the commit stage is telling the ROB to squah?
+ // This might be necessary to keep the same timing between the IQ and
+ // the ROB...
+ if (fromIEW->squash) {
+ DPRINTF(Commit, "Commit: Squashing instructions in the ROB.\n");
+
+ _status = ROBSquashing;
+
+ InstSeqNum squashed_inst = fromIEW->squashedSeqNum;
+
+ rob->squash(squashed_inst);
+
+ // Send back the sequence number of the squashed instruction.
+ toIEW->commitInfo.doneSeqNum = squashed_inst;
+
+ // Send back the squash signal to tell stages that they should squash.
+ toIEW->commitInfo.squash = true;
+
+ // Send back the rob squashing signal so other stages know that the
+ // ROB is in the process of squashing.
+ toIEW->commitInfo.robSquashing = true;
+
+ toIEW->commitInfo.branchMispredict = fromIEW->branchMispredict;
+
+ toIEW->commitInfo.branchTaken = fromIEW->branchTaken;
+
+ toIEW->commitInfo.nextPC = fromIEW->nextPC;
+
+ toIEW->commitInfo.mispredPC = fromIEW->mispredPC;
+
+ if (toIEW->commitInfo.branchMispredict) {
+ ++branchMispredicts;
+ }
+ }
+
+ if (_status != ROBSquashing) {
+ // If we're not currently squashing, then get instructions.
+ getInsts();
+
+ // Try to commit any instructions.
+ commitInsts();
+ }
+
+ // If the ROB is empty, we can set this stage to idle. Use this
+ // in the future when the Idle status will actually be utilized.
+#if 0
+ if (rob->isEmpty()) {
+ DPRINTF(Commit, "Commit: ROB is empty. Status changed to idle.\n");
+ _status = Idle;
+ // Schedule an event so that commit will actually wake up
+ // once something gets put in the ROB.
+ }
+#endif
+}
+
+// Loop that goes through as many instructions in the ROB as possible and
+// tries to commit them. The actual work for committing is done by the
+// commitHead() function.
+template <class Impl>
+void
+SimpleCommit<Impl>::commitInsts()
+{
+ ////////////////////////////////////
+ // Handle commit
+ // Note that commit will be handled prior to the ROB so that the ROB
+ // only tries to commit instructions it has in this current cycle, and
+ // not instructions it is writing in during this cycle.
+ // Can't commit and squash things at the same time...
+ ////////////////////////////////////
+
+ if (rob->isEmpty())
+ return;
+
+ DynInstPtr head_inst = rob->readHeadInst();
+
+ unsigned num_committed = 0;
+
+ // Commit as many instructions as possible until the commit bandwidth
+ // limit is reached, or it becomes impossible to commit any more.
+ while (!rob->isEmpty() &&
+ head_inst->readyToCommit() &&
+ num_committed < commitWidth)
+ {
+ DPRINTF(Commit, "Commit: Trying to commit head instruction.\n");
+
+ // If the head instruction is squashed, it is ready to retire at any
+ // time. However, we need to avoid updating any other state
+ // incorrectly if it's already been squashed.
+ if (head_inst->isSquashed()) {
+
+ DPRINTF(Commit, "Commit: Retiring squashed instruction from "
+ "ROB.\n");
+
+ // Tell ROB to retire head instruction. This retires the head
+ // inst in the ROB without affecting any other stages.
+ rob->retireHead();
+
+ ++commitSquashedInsts;
+
+ } else {
+ // Increment the total number of non-speculative instructions
+ // executed.
+ // Hack for now: it really shouldn't happen until after the
+ // commit is deemed to be successful, but this count is needed
+ // for syscalls.
+ cpu->funcExeInst++;
+
+ // Try to commit the head instruction.
+ bool commit_success = commitHead(head_inst, num_committed);
+
+ // Update what instruction we are looking at if the commit worked.
+ if (commit_success) {
+ ++num_committed;
+
+ // Send back which instruction has been committed.
+ // @todo: Update this later when a wider pipeline is used.
+ // Hmm, can't really give a pointer here...perhaps the
+ // sequence number instead (copy).
+ toIEW->commitInfo.doneSeqNum = head_inst->seqNum;
+
+ ++commitCommittedInsts;
+
+ if (!head_inst->isNop()) {
+ cpu->instDone();
+ }
+ } else {
+ break;
+ }
+ }
+
+ // Update the pointer to read the next instruction in the ROB.
+ head_inst = rob->readHeadInst();
+ }
+
+ DPRINTF(CommitRate, "%i\n", num_committed);
+ n_committed_dist.sample(num_committed);
+}
+
+template <class Impl>
+bool
+SimpleCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
+{
+ // Make sure instruction is valid
+ assert(head_inst);
+
+ // If the instruction is not executed yet, then it is a non-speculative
+ // or store inst. Signal backwards that it should be executed.
+ if (!head_inst->isExecuted()) {
+ // Keep this number correct. We have not yet actually executed
+ // and committed this instruction.
+ cpu->funcExeInst--;
+
+ if (head_inst->isNonSpeculative()) {
+ DPRINTF(Commit, "Commit: Encountered a store or non-speculative "
+ "instruction at the head of the ROB, PC %#x.\n",
+ head_inst->readPC());
+
+ toIEW->commitInfo.nonSpecSeqNum = head_inst->seqNum;
+
+ // Change the instruction so it won't try to commit again until
+ // it is executed.
+ head_inst->clearCanCommit();
+
+ ++commitNonSpecStalls;
+
+ return false;
+ } else {
+ panic("Commit: Trying to commit un-executed instruction "
+ "of unknown type!\n");
+ }
+ }
+
+ // Now check if it's one of the special trap or barrier or
+ // serializing instructions.
+ if (head_inst->isThreadSync() ||
+ head_inst->isSerializing() ||
+ head_inst->isMemBarrier() ||
+ head_inst->isWriteBarrier() )
+ {
+ // Not handled for now. Mem barriers and write barriers are safe
+ // to simply let commit as memory accesses only happen once they
+ // reach the head of commit. Not sure about the other two.
+ panic("Serializing or barrier instructions"
+ " are not handled yet.\n");
+ }
+
+ // Check if the instruction caused a fault. If so, trap.
+ Fault inst_fault = head_inst->getFault();
+
+ if (inst_fault != NoFault) {
+ if (!head_inst->isNop()) {
+#if FULL_SYSTEM
+ cpu->trap(inst_fault);
+#else // !FULL_SYSTEM
+ panic("fault (%d) detected @ PC %08p", inst_fault,
+ head_inst->PC);
+#endif // FULL_SYSTEM
+ }
+ }
+
+ // Check if we're really ready to commit. If not then return false.
+ // I'm pretty sure all instructions should be able to commit if they've
+ // reached this far. For now leave this in as a check.
+ if (!rob->isHeadReady()) {
+ panic("Commit: Unable to commit head instruction!\n");
+ return false;
+ }
+
+ // If it's a branch, then send back branch prediction update info
+ // to the fetch stage.
+ // This should be handled in the iew stage if a mispredict happens...
+
+ if (head_inst->isControl()) {
+
+#if 0
+ toIEW->nextPC = head_inst->readPC();
+ //Maybe switch over to BTB incorrect.
+ toIEW->btbMissed = head_inst->btbMiss();
+ toIEW->target = head_inst->nextPC;
+ //Maybe also include global history information.
+ //This simple version will have no branch prediction however.
+#endif
+
+ ++commitCommittedBranches;
+ }
+
+ // Now that the instruction is going to be committed, finalize its
+ // trace data.
+ if (head_inst->traceData) {
+ head_inst->traceData->finalize();
+ }
+
+ //Finally clear the head ROB entry.
+ rob->retireHead();
+
+ // Return true to indicate that we have committed an instruction.
+ return true;
+}
+
+template <class Impl>
+void
+SimpleCommit<Impl>::getInsts()
+{
+ //////////////////////////////////////
+ // Handle ROB functions
+ //////////////////////////////////////
+
+ // Read any issued instructions and place them into the ROB. Do this
+ // prior to squashing to avoid having instructions in the ROB that
+ // don't get squashed properly.
+ int insts_to_process = min((int)renameWidth, fromRename->size);
+
+ for (int inst_num = 0;
+ inst_num < insts_to_process;
+ ++inst_num)
+ {
+ if (!fromRename->insts[inst_num]->isSquashed()) {
+ DPRINTF(Commit, "Commit: Inserting PC %#x into ROB.\n",
+ fromRename->insts[inst_num]->readPC());
+ rob->insertInst(fromRename->insts[inst_num]);
+ } else {
+ DPRINTF(Commit, "Commit: Instruction %i PC %#x was "
+ "squashed, skipping.\n",
+ fromRename->insts[inst_num]->seqNum,
+ fromRename->insts[inst_num]->readPC());
+ }
+ }
+}
+
+template <class Impl>
+void
+SimpleCommit<Impl>::markCompletedInsts()
+{
+ // Grab completed insts out of the IEW instruction queue, and mark
+ // instructions completed within the ROB.
+ for (int inst_num = 0;
+ inst_num < fromIEW->size && fromIEW->insts[inst_num];
+ ++inst_num)
+ {
+ DPRINTF(Commit, "Commit: Marking PC %#x, SN %i ready within ROB.\n",
+ fromIEW->insts[inst_num]->readPC(),
+ fromIEW->insts[inst_num]->seqNum);
+
+ // Mark the instruction as ready to commit.
+ fromIEW->insts[inst_num]->setCanCommit();
+ }
+}
+
+template <class Impl>
+uint64_t
+SimpleCommit<Impl>::readCommitPC()
+{
+ return rob->readHeadPC();
+}
diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc
new file mode 100644
index 000000000..a268dbc23
--- /dev/null
+++ b/src/cpu/o3/cpu.cc
@@ -0,0 +1,566 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config/full_system.hh"
+
+#if FULL_SYSTEM
+#include "sim/system.hh"
+#else
+#include "sim/process.hh"
+#endif
+#include "sim/root.hh"
+
+#include "cpu/cpu_exec_context.hh"
+#include "cpu/exec_context.hh"
+#include "cpu/o3/alpha_dyn_inst.hh"
+#include "cpu/o3/alpha_impl.hh"
+#include "cpu/o3/cpu.hh"
+
+using namespace std;
+
+BaseFullCPU::BaseFullCPU(Params &params)
+ : BaseCPU(&params), cpu_id(0)
+{
+}
+
+template <class Impl>
+FullO3CPU<Impl>::TickEvent::TickEvent(FullO3CPU<Impl> *c)
+ : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c)
+{
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::TickEvent::process()
+{
+ cpu->tick();
+}
+
+template <class Impl>
+const char *
+FullO3CPU<Impl>::TickEvent::description()
+{
+ return "FullO3CPU tick event";
+}
+
+//Call constructor to all the pipeline stages here
+template <class Impl>
+FullO3CPU<Impl>::FullO3CPU(Params &params)
+#if FULL_SYSTEM
+ : BaseFullCPU(params),
+#else
+ : BaseFullCPU(params),
+#endif // FULL_SYSTEM
+ tickEvent(this),
+ fetch(params),
+ decode(params),
+ rename(params),
+ iew(params),
+ commit(params),
+
+ regFile(params.numPhysIntRegs, params.numPhysFloatRegs),
+
+ freeList(TheISA::NumIntRegs, params.numPhysIntRegs,
+ TheISA::NumFloatRegs, params.numPhysFloatRegs),
+
+ renameMap(TheISA::NumIntRegs, params.numPhysIntRegs,
+ TheISA::NumFloatRegs, params.numPhysFloatRegs,
+ TheISA::NumMiscRegs,
+ TheISA::ZeroReg,
+ TheISA::ZeroReg + TheISA::NumIntRegs),
+
+ rob(params.numROBEntries, params.squashWidth),
+
+ // What to pass to these time buffers?
+ // For now just have these time buffers be pretty big.
+ timeBuffer(5, 5),
+ fetchQueue(5, 5),
+ decodeQueue(5, 5),
+ renameQueue(5, 5),
+ iewQueue(5, 5),
+
+ cpuXC(NULL),
+
+ globalSeqNum(1),
+
+#if FULL_SYSTEM
+ system(params.system),
+ memCtrl(system->memctrl),
+ physmem(system->physmem),
+ itb(params.itb),
+ dtb(params.dtb),
+ mem(params.mem),
+#else
+ // Hardcoded for a single thread!!
+ mem(params.workload[0]->getMemory()),
+#endif // FULL_SYSTEM
+
+ icacheInterface(params.icacheInterface),
+ dcacheInterface(params.dcacheInterface),
+ deferRegistration(params.defReg),
+ numInsts(0),
+ funcExeInst(0)
+{
+ _status = Idle;
+
+#if !FULL_SYSTEM
+ thread.resize(this->number_of_threads);
+#endif
+
+ for (int i = 0; i < this->number_of_threads; ++i) {
+#if FULL_SYSTEM
+ assert(i == 0);
+ thread[i] = new CPUExecContext(this, 0, system, itb, dtb, mem);
+ system->execContexts[i] = thread[i]->getProxy();
+
+ execContexts.push_back(system->execContexts[i]);
+#else
+ if (i < params.workload.size()) {
+ DPRINTF(FullCPU, "FullCPU: Workload[%i]'s starting PC is %#x, "
+ "process is %#x",
+ i, params.workload[i]->prog_entry, thread[i]);
+ thread[i] = new CPUExecContext(this, i, params.workload[i], i);
+ }
+ assert(params.workload[i]->getMemory() != NULL);
+ assert(mem != NULL);
+ execContexts.push_back(thread[i]->getProxy());
+#endif // !FULL_SYSTEM
+ }
+
+ // Note that this is a hack so that my code which still uses xc-> will
+ // still work. I should remove this eventually
+ cpuXC = thread[0];
+
+ // The stages also need their CPU pointer setup. However this must be
+ // done at the upper level CPU because they have pointers to the upper
+ // level CPU, and not this FullO3CPU.
+
+ // Give each of the stages the time buffer they will use.
+ fetch.setTimeBuffer(&timeBuffer);
+ decode.setTimeBuffer(&timeBuffer);
+ rename.setTimeBuffer(&timeBuffer);
+ iew.setTimeBuffer(&timeBuffer);
+ commit.setTimeBuffer(&timeBuffer);
+
+ // Also setup each of the stages' queues.
+ fetch.setFetchQueue(&fetchQueue);
+ decode.setFetchQueue(&fetchQueue);
+ decode.setDecodeQueue(&decodeQueue);
+ rename.setDecodeQueue(&decodeQueue);
+ rename.setRenameQueue(&renameQueue);
+ iew.setRenameQueue(&renameQueue);
+ iew.setIEWQueue(&iewQueue);
+ commit.setIEWQueue(&iewQueue);
+ commit.setRenameQueue(&renameQueue);
+
+ // Setup the rename map for whichever stages need it.
+ rename.setRenameMap(&renameMap);
+ iew.setRenameMap(&renameMap);
+
+ // Setup the free list for whichever stages need it.
+ rename.setFreeList(&freeList);
+ renameMap.setFreeList(&freeList);
+
+ // Setup the ROB for whichever stages need it.
+ commit.setROB(&rob);
+}
+
+template <class Impl>
+FullO3CPU<Impl>::~FullO3CPU()
+{
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::fullCPURegStats()
+{
+ // Register any of the FullCPU's stats here.
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::tick()
+{
+ DPRINTF(FullCPU, "\n\nFullCPU: Ticking main, FullO3CPU.\n");
+
+ //Tick each of the stages if they're actually running.
+ //Will want to figure out a way to unschedule itself if they're all
+ //going to be idle for a long time.
+ fetch.tick();
+
+ decode.tick();
+
+ rename.tick();
+
+ iew.tick();
+
+ commit.tick();
+
+ // Now advance the time buffers, unless the stage is stalled.
+ timeBuffer.advance();
+
+ fetchQueue.advance();
+ decodeQueue.advance();
+ renameQueue.advance();
+ iewQueue.advance();
+
+ if (_status == Running && !tickEvent.scheduled())
+ tickEvent.schedule(curTick + 1);
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::init()
+{
+ if(!deferRegistration)
+ {
+ this->registerExecContexts();
+
+ // Need to do a copy of the xc->regs into the CPU's regfile so
+ // that it can start properly.
+#if FULL_SYSTEM
+ ExecContext *src_xc = system->execContexts[0];
+ TheISA::initCPU(src_xc, src_xc->readCpuId());
+#else
+ ExecContext *src_xc = thread[0]->getProxy();
+#endif
+ // First loop through the integer registers.
+ for (int i = 0; i < TheISA::NumIntRegs; ++i)
+ {
+ regFile.intRegFile[i] = src_xc->readIntReg(i);
+ }
+
+ // Then loop through the floating point registers.
+ for (int i = 0; i < TheISA::NumFloatRegs; ++i)
+ {
+ regFile.floatRegFile.setRegBits(i, src_xc->readRegBits(i))
+ }
+/*
+ // Then loop through the misc registers.
+ regFile.miscRegs.fpcr = src_xc->regs.miscRegs.fpcr;
+ regFile.miscRegs.uniq = src_xc->regs.miscRegs.uniq;
+ regFile.miscRegs.lock_flag = src_xc->regs.miscRegs.lock_flag;
+ regFile.miscRegs.lock_addr = src_xc->regs.miscRegs.lock_addr;
+*/
+ // Then finally set the PC and the next PC.
+ regFile.pc = src_xc->readPC();
+ regFile.npc = src_xc->readNextPC();
+ }
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::activateContext(int thread_num, int delay)
+{
+ // Needs to set each stage to running as well.
+
+ scheduleTickEvent(delay);
+
+ _status = Running;
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::suspendContext(int thread_num)
+{
+ panic("suspendContext unimplemented!");
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::deallocateContext(int thread_num)
+{
+ panic("deallocateContext unimplemented!");
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::haltContext(int thread_num)
+{
+ panic("haltContext unimplemented!");
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::switchOut()
+{
+ panic("FullO3CPU does not have a switch out function.\n");
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU)
+{
+ BaseCPU::takeOverFrom(oldCPU);
+
+ assert(!tickEvent.scheduled());
+
+ // Set all status's to active, schedule the
+ // CPU's tick event.
+ for (int i = 0; i < execContexts.size(); ++i) {
+ ExecContext *xc = execContexts[i];
+ if (xc->status() == ExecContext::Active && _status != Running) {
+ _status = Running;
+ tickEvent.schedule(curTick);
+ }
+ }
+}
+
+template <class Impl>
+InstSeqNum
+FullO3CPU<Impl>::getAndIncrementInstSeq()
+{
+ // Hopefully this works right.
+ return globalSeqNum++;
+}
+
+template <class Impl>
+uint64_t
+FullO3CPU<Impl>::readIntReg(int reg_idx)
+{
+ return regFile.readIntReg(reg_idx);
+}
+
+template <class Impl>
+FloatReg
+FullO3CPU<Impl>::readFloatReg(int reg_idx, int width)
+{
+ return regFile.readFloatReg(reg_idx, width);
+}
+
+template <class Impl>
+FloatReg
+FullO3CPU<Impl>::readFloatReg(int reg_idx)
+{
+ return regFile.readFloatReg(reg_idx);
+}
+
+template <class Impl>
+FloatRegBits
+FullO3CPU<Impl>::readFloatRegBits(int reg_idx, int width)
+{
+ return regFile.readFloatRegBits(reg_idx, width);
+}
+
+template <class Impl>
+FloatRegBits
+FullO3CPU<Impl>::readFloatRegBits(int reg_idx)
+{
+ return regFile.readFloatRegBits(reg_idx);
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::setIntReg(int reg_idx, uint64_t val)
+{
+ regFile.setIntReg(reg_idx, val);
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::setFloatReg(int reg_idx, FloatReg val, int width)
+{
+ regFile.setFloatReg(reg_idx, val, width);
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::setFloatReg(int reg_idx, FloatReg val)
+{
+ regFile.setFloatReg(reg_idx, val);
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::setFloatRegBits(int reg_idx, FloatRegBits val, int width)
+{
+ regFile.setFloatRegBits(reg_idx, val, width);
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::setFloatRegBits(int reg_idx, FloatRegBits val)
+{
+ regFile.setFloatRegBits(reg_idx, val);
+}
+
+template <class Impl>
+uint64_t
+FullO3CPU<Impl>::readPC()
+{
+ return regFile.readPC();
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::setNextPC(uint64_t val)
+{
+ regFile.setNextPC(val);
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::setPC(Addr new_PC)
+{
+ regFile.setPC(new_PC);
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::addInst(DynInstPtr &inst)
+{
+ instList.push_back(inst);
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::instDone()
+{
+ // Keep an instruction count.
+ numInsts++;
+
+ // Check for instruction-count-based events.
+ comInstEventQueue[0]->serviceEvents(numInsts);
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::removeBackInst(DynInstPtr &inst)
+{
+ DynInstPtr inst_to_delete;
+
+ // Walk through the instruction list, removing any instructions
+ // that were inserted after the given instruction, inst.
+ while (instList.back() != inst)
+ {
+ assert(!instList.empty());
+
+ // Obtain the pointer to the instruction.
+ inst_to_delete = instList.back();
+
+ DPRINTF(FullCPU, "FullCPU: Removing instruction %i, PC %#x\n",
+ inst_to_delete->seqNum, inst_to_delete->readPC());
+
+ // Remove the instruction from the list.
+ instList.pop_back();
+
+ // Mark it as squashed.
+ inst_to_delete->setSquashed();
+ }
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::removeFrontInst(DynInstPtr &inst)
+{
+ DynInstPtr inst_to_remove;
+
+ // The front instruction should be the same one being asked to be removed.
+ assert(instList.front() == inst);
+
+ // Remove the front instruction.
+ inst_to_remove = inst;
+ instList.pop_front();
+
+ DPRINTF(FullCPU, "FullCPU: Removing committed instruction %#x, PC %#x\n",
+ inst_to_remove, inst_to_remove->readPC());
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::removeInstsNotInROB()
+{
+ DPRINTF(FullCPU, "FullCPU: Deleting instructions from instruction "
+ "list.\n");
+
+ DynInstPtr rob_tail = rob.readTailInst();
+
+ removeBackInst(rob_tail);
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::removeInstsUntil(const InstSeqNum &seq_num)
+{
+ DPRINTF(FullCPU, "FullCPU: Deleting instructions from instruction "
+ "list.\n");
+
+ DynInstPtr inst_to_delete;
+
+ while (instList.back()->seqNum > seq_num) {
+ assert(!instList.empty());
+
+ // Obtain the pointer to the instruction.
+ inst_to_delete = instList.back();
+
+ DPRINTF(FullCPU, "FullCPU: Removing instruction %i, PC %#x\n",
+ inst_to_delete->seqNum, inst_to_delete->readPC());
+
+ // Remove the instruction from the list.
+ instList.back() = NULL;
+ instList.pop_back();
+
+ // Mark it as squashed.
+ inst_to_delete->setSquashed();
+ }
+
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::removeAllInsts()
+{
+ instList.clear();
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::dumpInsts()
+{
+ int num = 0;
+ typename list<DynInstPtr>::iterator inst_list_it = instList.begin();
+
+ while (inst_list_it != instList.end())
+ {
+ cprintf("Instruction:%i\nPC:%#x\nSN:%lli\nIssued:%i\nSquashed:%i\n\n",
+ num, (*inst_list_it)->readPC(), (*inst_list_it)->seqNum,
+ (*inst_list_it)->isIssued(), (*inst_list_it)->isSquashed());
+ inst_list_it++;
+ ++num;
+ }
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::wakeDependents(DynInstPtr &inst)
+{
+ iew.wakeDependents(inst);
+}
+
+// Forward declaration of FullO3CPU.
+template class FullO3CPU<AlphaSimpleImpl>;
diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh
new file mode 100644
index 000000000..f7c80e8a1
--- /dev/null
+++ b/src/cpu/o3/cpu.hh
@@ -0,0 +1,363 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//Todo: Add in a lot of the functions that are ISA specific. Also define
+//the functions that currently exist within the base cpu class. Define
+//everything for the simobject stuff so it can be serialized and
+//instantiated, add in debugging statements everywhere. Have CPU schedule
+//itself properly. Threads!
+// Avoid running stages and advancing queues if idle/stalled.
+
+#ifndef __CPU_O3_CPU_FULL_CPU_HH__
+#define __CPU_O3_CPU_FULL_CPU_HH__
+
+#include <iostream>
+#include <list>
+#include <vector>
+
+#include "base/statistics.hh"
+#include "base/timebuf.hh"
+#include "config/full_system.hh"
+#include "cpu/base.hh"
+#include "cpu/cpu_exec_context.hh"
+#include "cpu/o3/comm.hh"
+#include "cpu/o3/cpu_policy.hh"
+#include "sim/process.hh"
+
+class ExecContext;
+class FunctionalMemory;
+class Process;
+
+class BaseFullCPU : public BaseCPU
+{
+ //Stuff that's pretty ISA independent will go here.
+ public:
+ typedef BaseCPU::Params Params;
+
+#if FULL_SYSTEM
+ BaseFullCPU(Params &params);
+#else
+ BaseFullCPU(Params &params);
+#endif // FULL_SYSTEM
+
+ protected:
+ int cpu_id;
+};
+
+template <class Impl>
+class FullO3CPU : public BaseFullCPU
+{
+ public:
+ //Put typedefs from the Impl here.
+ typedef typename Impl::CPUPol CPUPolicy;
+ typedef typename Impl::Params Params;
+ typedef typename Impl::DynInstPtr DynInstPtr;
+
+ public:
+ enum Status {
+ Running,
+ Idle,
+ Halted,
+ Blocked // ?
+ };
+
+ Status _status;
+
+ private:
+ class TickEvent : public Event
+ {
+ private:
+ FullO3CPU<Impl> *cpu;
+
+ public:
+ TickEvent(FullO3CPU<Impl> *c);
+ void process();
+ const char *description();
+ };
+
+ TickEvent tickEvent;
+
+ /// Schedule tick event, regardless of its current state.
+ void scheduleTickEvent(int delay)
+ {
+ if (tickEvent.squashed())
+ tickEvent.reschedule(curTick + delay);
+ else if (!tickEvent.scheduled())
+ tickEvent.schedule(curTick + delay);
+ }
+
+ /// Unschedule tick event, regardless of its current state.
+ void unscheduleTickEvent()
+ {
+ if (tickEvent.scheduled())
+ tickEvent.squash();
+ }
+
+ public:
+ FullO3CPU(Params &params);
+ ~FullO3CPU();
+
+ void fullCPURegStats();
+
+ void tick();
+
+ void init();
+
+ void activateContext(int thread_num, int delay);
+ void suspendContext(int thread_num);
+ void deallocateContext(int thread_num);
+ void haltContext(int thread_num);
+
+ void switchOut();
+ void takeOverFrom(BaseCPU *oldCPU);
+
+ /** Get the current instruction sequence number, and increment it. */
+ InstSeqNum getAndIncrementInstSeq();
+
+#if FULL_SYSTEM
+ /** Check if this address is a valid instruction address. */
+ bool validInstAddr(Addr addr) { return true; }
+
+ /** Check if this address is a valid data address. */
+ bool validDataAddr(Addr addr) { return true; }
+
+ /** Get instruction asid. */
+ int getInstAsid()
+ { return regFile.miscRegs.getInstAsid(); }
+
+ /** Get data asid. */
+ int getDataAsid()
+ { return regFile.miscRegs.getDataAsid(); }
+#else
+ bool validInstAddr(Addr addr)
+ { return thread[0]->validInstAddr(addr); }
+
+ bool validDataAddr(Addr addr)
+ { return thread[0]->validDataAddr(addr); }
+
+ int getInstAsid() { return thread[0]->getInstAsid(); }
+ int getDataAsid() { return thread[0]->getDataAsid(); }
+
+#endif
+
+ //
+ // New accessors for new decoder.
+ //
+ uint64_t readIntReg(int reg_idx);
+
+ FloatReg readFloatReg(int reg_idx);
+
+ FloatReg readFloatReg(int reg_idx, int width);
+
+ FloatRegBits readFloatRegBits(int reg_idx);
+
+ FloatRegBits readFloatRegBits(int reg_idx, int width);
+
+ void setIntReg(int reg_idx, uint64_t val);
+
+ void setFloatReg(int reg_idx, FloatReg val, int width);
+
+ void setFloatReg(int reg_idx, FloatReg val, int width);
+
+ void setFloatRegBits(int reg_idx, FloatRegBits val);
+
+ void setFloatRegBits(int reg_idx, FloatRegBits val);
+
+ uint64_t readPC();
+
+ void setNextPC(uint64_t val);
+
+ void setPC(Addr new_PC);
+
+ /** Function to add instruction onto the head of the list of the
+ * instructions. Used when new instructions are fetched.
+ */
+ void addInst(DynInstPtr &inst);
+
+ /** Function to tell the CPU that an instruction has completed. */
+ void instDone();
+
+ /** Remove all instructions in back of the given instruction, but leave
+ * that instruction in the list. This is useful in a squash, when there
+ * are instructions in this list that don't exist in structures such as
+ * the ROB. The instruction doesn't have to be the last instruction in
+ * the list, but will be once this function completes.
+ * @todo: Remove only up until that inst? Squashed inst is most likely
+ * valid.
+ */
+ void removeBackInst(DynInstPtr &inst);
+
+ /** Remove an instruction from the front of the list. It is expected
+ * that there are no instructions in front of it (that is, none are older
+ * than the instruction being removed). Used when retiring instructions.
+ * @todo: Remove the argument to this function, and just have it remove
+ * last instruction once it's verified that commit has the same ordering
+ * as the instruction list.
+ */
+ void removeFrontInst(DynInstPtr &inst);
+
+ /** Remove all instructions that are not currently in the ROB. */
+ void removeInstsNotInROB();
+
+ /** Remove all instructions younger than the given sequence number. */
+ void removeInstsUntil(const InstSeqNum &seq_num);
+
+ /** Remove all instructions from the list. */
+ void removeAllInsts();
+
+ void dumpInsts();
+
+ /** Basically a wrapper function so that instructions executed at
+ * commit can tell the instruction queue that they have completed.
+ * Eventually this hack should be removed.
+ */
+ void wakeDependents(DynInstPtr &inst);
+
+ public:
+ /** List of all the instructions in flight. */
+ list<DynInstPtr> instList;
+
+ //not sure these should be private.
+ protected:
+ /** The fetch stage. */
+ typename CPUPolicy::Fetch fetch;
+
+ /** The fetch stage's status. */
+ typename CPUPolicy::Fetch::Status fetchStatus;
+
+ /** The decode stage. */
+ typename CPUPolicy::Decode decode;
+
+ /** The decode stage's status. */
+ typename CPUPolicy::Decode::Status decodeStatus;
+
+ /** The dispatch stage. */
+ typename CPUPolicy::Rename rename;
+
+ /** The dispatch stage's status. */
+ typename CPUPolicy::Rename::Status renameStatus;
+
+ /** The issue/execute/writeback stages. */
+ typename CPUPolicy::IEW iew;
+
+ /** The issue/execute/writeback stage's status. */
+ typename CPUPolicy::IEW::Status iewStatus;
+
+ /** The commit stage. */
+ typename CPUPolicy::Commit commit;
+
+ /** The fetch stage's status. */
+ typename CPUPolicy::Commit::Status commitStatus;
+
+ //Might want to just pass these objects in to the constructors of the
+ //appropriate stage. regFile is in iew, freeList in dispatch, renameMap
+ //in dispatch, and the rob in commit.
+ /** The register file. */
+ typename CPUPolicy::RegFile regFile;
+
+ /** The free list. */
+ typename CPUPolicy::FreeList freeList;
+
+ /** The rename map. */
+ typename CPUPolicy::RenameMap renameMap;
+
+ /** The re-order buffer. */
+ typename CPUPolicy::ROB rob;
+
+ public:
+ /** Typedefs from the Impl to get the structs that each of the
+ * time buffers should use.
+ */
+ typedef typename CPUPolicy::TimeStruct TimeStruct;
+
+ typedef typename CPUPolicy::FetchStruct FetchStruct;
+
+ typedef typename CPUPolicy::DecodeStruct DecodeStruct;
+
+ typedef typename CPUPolicy::RenameStruct RenameStruct;
+
+ typedef typename CPUPolicy::IEWStruct IEWStruct;
+
+ /** The main time buffer to do backwards communication. */
+ TimeBuffer<TimeStruct> timeBuffer;
+
+ /** The fetch stage's instruction queue. */
+ TimeBuffer<FetchStruct> fetchQueue;
+
+ /** The decode stage's instruction queue. */
+ TimeBuffer<DecodeStruct> decodeQueue;
+
+ /** The rename stage's instruction queue. */
+ TimeBuffer<RenameStruct> renameQueue;
+
+ /** The IEW stage's instruction queue. */
+ TimeBuffer<IEWStruct> iewQueue;
+
+ public:
+ /** The temporary exec context to support older accessors. */
+ CPUExecContext *cpuXC;
+
+ /** Temporary function to get pointer to exec context. */
+ ExecContext *xcBase()
+ {
+ return thread[0]->getProxy();
+ }
+
+ CPUExecContext *cpuXCBase()
+ {
+ return thread[0];
+ }
+
+ InstSeqNum globalSeqNum;
+
+#if FULL_SYSTEM
+ System *system;
+
+ MemoryController *memCtrl;
+ PhysicalMemory *physmem;
+
+ AlphaITB *itb;
+ AlphaDTB *dtb;
+
+// SWContext *swCtx;
+#endif
+ std::vector<CPUExecContext *> thread;
+
+ FunctionalMemory *mem;
+
+ MemInterface *icacheInterface;
+ MemInterface *dcacheInterface;
+
+ bool deferRegistration;
+
+ Counter numInsts;
+
+ Counter funcExeInst;
+};
+
+#endif
diff --git a/src/cpu/o3/cpu_policy.hh b/src/cpu/o3/cpu_policy.hh
new file mode 100644
index 000000000..41f06f81b
--- /dev/null
+++ b/src/cpu/o3/cpu_policy.hh
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPU_O3_CPU_CPU_POLICY_HH__
+#define __CPU_O3_CPU_CPU_POLICY_HH__
+
+#include "cpu/o3/bpred_unit.hh"
+#include "cpu/o3/free_list.hh"
+#include "cpu/o3/inst_queue.hh"
+#include "cpu/o3/ldstq.hh"
+#include "cpu/o3/mem_dep_unit.hh"
+#include "cpu/o3/regfile.hh"
+#include "cpu/o3/rename_map.hh"
+#include "cpu/o3/rob.hh"
+#include "cpu/o3/store_set.hh"
+
+#include "cpu/o3/commit.hh"
+#include "cpu/o3/decode.hh"
+#include "cpu/o3/fetch.hh"
+#include "cpu/o3/iew.hh"
+#include "cpu/o3/rename.hh"
+
+#include "cpu/o3/comm.hh"
+
+template<class Impl>
+struct SimpleCPUPolicy
+{
+ typedef TwobitBPredUnit<Impl> BPredUnit;
+ typedef PhysRegFile<Impl> RegFile;
+ typedef SimpleFreeList FreeList;
+ typedef SimpleRenameMap RenameMap;
+ typedef ROB<Impl> ROB;
+ typedef InstructionQueue<Impl> IQ;
+ typedef MemDepUnit<StoreSet, Impl> MemDepUnit;
+ typedef LDSTQ<Impl> LDSTQ;
+
+ typedef SimpleFetch<Impl> Fetch;
+ typedef SimpleDecode<Impl> Decode;
+ typedef SimpleRename<Impl> Rename;
+ typedef SimpleIEW<Impl> IEW;
+ typedef SimpleCommit<Impl> Commit;
+
+ /** The struct for communication between fetch and decode. */
+ typedef SimpleFetchSimpleDecode<Impl> FetchStruct;
+
+ /** The struct for communication between decode and rename. */
+ typedef SimpleDecodeSimpleRename<Impl> DecodeStruct;
+
+ /** The struct for communication between rename and IEW. */
+ typedef SimpleRenameSimpleIEW<Impl> RenameStruct;
+
+ /** The struct for communication between IEW and commit. */
+ typedef SimpleIEWSimpleCommit<Impl> IEWStruct;
+
+ /** The struct for communication within the IEW stage. */
+ typedef IssueStruct<Impl> IssueStruct;
+
+ /** The struct for all backwards communication. */
+ typedef TimeBufStruct TimeStruct;
+
+};
+
+#endif //__CPU_O3_CPU_CPU_POLICY_HH__
diff --git a/src/cpu/o3/decode.cc b/src/cpu/o3/decode.cc
new file mode 100644
index 000000000..290648318
--- /dev/null
+++ b/src/cpu/o3/decode.cc
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "cpu/o3/alpha_dyn_inst.hh"
+#include "cpu/o3/alpha_impl.hh"
+#include "cpu/o3/decode_impl.hh"
+
+template class SimpleDecode<AlphaSimpleImpl>;
diff --git a/src/cpu/o3/decode.hh b/src/cpu/o3/decode.hh
new file mode 100644
index 000000000..5b9a0f822
--- /dev/null
+++ b/src/cpu/o3/decode.hh
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPU_O3_CPU_SIMPLE_DECODE_HH__
+#define __CPU_O3_CPU_SIMPLE_DECODE_HH__
+
+#include <queue>
+
+#include "base/statistics.hh"
+#include "base/timebuf.hh"
+
+template<class Impl>
+class SimpleDecode
+{
+ private:
+ // Typedefs from the Impl.
+ typedef typename Impl::FullCPU FullCPU;
+ typedef typename Impl::DynInstPtr DynInstPtr;
+ typedef typename Impl::Params Params;
+ typedef typename Impl::CPUPol CPUPol;
+
+ // Typedefs from the CPU policy.
+ typedef typename CPUPol::FetchStruct FetchStruct;
+ typedef typename CPUPol::DecodeStruct DecodeStruct;
+ typedef typename CPUPol::TimeStruct TimeStruct;
+
+ public:
+ // The only time decode will become blocked is if dispatch becomes
+ // blocked, which means IQ or ROB is probably full.
+ enum Status {
+ Running,
+ Idle,
+ Squashing,
+ Blocked,
+ Unblocking
+ };
+
+ private:
+ // May eventually need statuses on a per thread basis.
+ Status _status;
+
+ public:
+ SimpleDecode(Params &params);
+
+ void regStats();
+
+ void setCPU(FullCPU *cpu_ptr);
+
+ void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr);
+
+ void setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr);
+
+ void setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr);
+
+ void tick();
+
+ void decode();
+
+ private:
+ inline bool fetchInstsValid();
+
+ void block();
+
+ inline void unblock();
+
+ void squash(DynInstPtr &inst);
+
+ public:
+ // Might want to make squash a friend function.
+ void squash();
+
+ private:
+ // Interfaces to objects outside of decode.
+ /** CPU interface. */
+ FullCPU *cpu;
+
+ /** Time buffer interface. */
+ TimeBuffer<TimeStruct> *timeBuffer;
+
+ /** Wire to get rename's output from backwards time buffer. */
+ typename TimeBuffer<TimeStruct>::wire fromRename;
+
+ /** Wire to get iew's information from backwards time buffer. */
+ typename TimeBuffer<TimeStruct>::wire fromIEW;
+
+ /** Wire to get commit's information from backwards time buffer. */
+ typename TimeBuffer<TimeStruct>::wire fromCommit;
+
+ /** Wire to write information heading to previous stages. */
+ // Might not be the best name as not only fetch will read it.
+ typename TimeBuffer<TimeStruct>::wire toFetch;
+
+ /** Decode instruction queue. */
+ TimeBuffer<DecodeStruct> *decodeQueue;
+
+ /** Wire used to write any information heading to rename. */
+ typename TimeBuffer<DecodeStruct>::wire toRename;
+
+ /** Fetch instruction queue interface. */
+ TimeBuffer<FetchStruct> *fetchQueue;
+
+ /** Wire to get fetch's output from fetch queue. */
+ typename TimeBuffer<FetchStruct>::wire fromFetch;
+
+ /** Skid buffer between fetch and decode. */
+ std::queue<FetchStruct> skidBuffer;
+
+ //Consider making these unsigned to avoid any confusion.
+ /** Rename to decode delay, in ticks. */
+ unsigned renameToDecodeDelay;
+
+ /** IEW to decode delay, in ticks. */
+ unsigned iewToDecodeDelay;
+
+ /** Commit to decode delay, in ticks. */
+ unsigned commitToDecodeDelay;
+
+ /** Fetch to decode delay, in ticks. */
+ unsigned fetchToDecodeDelay;
+
+ /** The width of decode, in instructions. */
+ unsigned decodeWidth;
+
+ /** The instruction that decode is currently on. It needs to have
+ * persistent state so that when a stall occurs in the middle of a
+ * group of instructions, it can restart at the proper instruction.
+ */
+ unsigned numInst;
+
+ Stats::Scalar<> decodeIdleCycles;
+ Stats::Scalar<> decodeBlockedCycles;
+ Stats::Scalar<> decodeUnblockCycles;
+ Stats::Scalar<> decodeSquashCycles;
+ Stats::Scalar<> decodeBranchMispred;
+ Stats::Scalar<> decodeControlMispred;
+ Stats::Scalar<> decodeDecodedInsts;
+ Stats::Scalar<> decodeSquashedInsts;
+};
+
+#endif // __CPU_O3_CPU_SIMPLE_DECODE_HH__
diff --git a/src/cpu/o3/decode_impl.hh b/src/cpu/o3/decode_impl.hh
new file mode 100644
index 000000000..463f0ddac
--- /dev/null
+++ b/src/cpu/o3/decode_impl.hh
@@ -0,0 +1,425 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "cpu/o3/decode.hh"
+
+template<class Impl>
+SimpleDecode<Impl>::SimpleDecode(Params &params)
+ : renameToDecodeDelay(params.renameToDecodeDelay),
+ iewToDecodeDelay(params.iewToDecodeDelay),
+ commitToDecodeDelay(params.commitToDecodeDelay),
+ fetchToDecodeDelay(params.fetchToDecodeDelay),
+ decodeWidth(params.decodeWidth),
+ numInst(0)
+{
+ DPRINTF(Decode, "Decode: decodeWidth=%i.\n", decodeWidth);
+ _status = Idle;
+}
+
+template <class Impl>
+void
+SimpleDecode<Impl>::regStats()
+{
+ decodeIdleCycles
+ .name(name() + ".decodeIdleCycles")
+ .desc("Number of cycles decode is idle")
+ .prereq(decodeIdleCycles);
+ decodeBlockedCycles
+ .name(name() + ".decodeBlockedCycles")
+ .desc("Number of cycles decode is blocked")
+ .prereq(decodeBlockedCycles);
+ decodeUnblockCycles
+ .name(name() + ".decodeUnblockCycles")
+ .desc("Number of cycles decode is unblocking")
+ .prereq(decodeUnblockCycles);
+ decodeSquashCycles
+ .name(name() + ".decodeSquashCycles")
+ .desc("Number of cycles decode is squashing")
+ .prereq(decodeSquashCycles);
+ decodeBranchMispred
+ .name(name() + ".decodeBranchMispred")
+ .desc("Number of times decode detected a branch misprediction")
+ .prereq(decodeBranchMispred);
+ decodeControlMispred
+ .name(name() + ".decodeControlMispred")
+ .desc("Number of times decode detected an instruction incorrectly"
+ " predicted as a control")
+ .prereq(decodeControlMispred);
+ decodeDecodedInsts
+ .name(name() + ".decodeDecodedInsts")
+ .desc("Number of instructions handled by decode")
+ .prereq(decodeDecodedInsts);
+ decodeSquashedInsts
+ .name(name() + ".decodeSquashedInsts")
+ .desc("Number of squashed instructions handled by decode")
+ .prereq(decodeSquashedInsts);
+}
+
+template<class Impl>
+void
+SimpleDecode<Impl>::setCPU(FullCPU *cpu_ptr)
+{
+ DPRINTF(Decode, "Decode: Setting CPU pointer.\n");
+ cpu = cpu_ptr;
+}
+
+template<class Impl>
+void
+SimpleDecode<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
+{
+ DPRINTF(Decode, "Decode: Setting time buffer pointer.\n");
+ timeBuffer = tb_ptr;
+
+ // Setup wire to write information back to fetch.
+ toFetch = timeBuffer->getWire(0);
+
+ // Create wires to get information from proper places in time buffer.
+ fromRename = timeBuffer->getWire(-renameToDecodeDelay);
+ fromIEW = timeBuffer->getWire(-iewToDecodeDelay);
+ fromCommit = timeBuffer->getWire(-commitToDecodeDelay);
+}
+
+template<class Impl>
+void
+SimpleDecode<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr)
+{
+ DPRINTF(Decode, "Decode: Setting decode queue pointer.\n");
+ decodeQueue = dq_ptr;
+
+ // Setup wire to write information to proper place in decode queue.
+ toRename = decodeQueue->getWire(0);
+}
+
+template<class Impl>
+void
+SimpleDecode<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr)
+{
+ DPRINTF(Decode, "Decode: Setting fetch queue pointer.\n");
+ fetchQueue = fq_ptr;
+
+ // Setup wire to read information from fetch queue.
+ fromFetch = fetchQueue->getWire(-fetchToDecodeDelay);
+}
+
+template<class Impl>
+inline bool
+SimpleDecode<Impl>::fetchInstsValid()
+{
+ return fromFetch->size > 0;
+}
+
+template<class Impl>
+void
+SimpleDecode<Impl>::block()
+{
+ DPRINTF(Decode, "Decode: Blocking.\n");
+
+ // Set the status to Blocked.
+ _status = Blocked;
+
+ // Add the current inputs to the skid buffer so they can be
+ // reprocessed when this stage unblocks.
+ skidBuffer.push(*fromFetch);
+
+ // Note that this stage only signals previous stages to stall when
+ // it is the cause of the stall originates at this stage. Otherwise
+ // the previous stages are expected to check all possible stall signals.
+}
+
+template<class Impl>
+inline void
+SimpleDecode<Impl>::unblock()
+{
+ DPRINTF(Decode, "Decode: Unblocking, going to remove "
+ "instructions from skid buffer.\n");
+ // Remove the now processed instructions from the skid buffer.
+ skidBuffer.pop();
+
+ // If there's still information in the skid buffer, then
+ // continue to tell previous stages to stall. They will be
+ // able to restart once the skid buffer is empty.
+ if (!skidBuffer.empty()) {
+ toFetch->decodeInfo.stall = true;
+ } else {
+ DPRINTF(Decode, "Decode: Finished unblocking.\n");
+ _status = Running;
+ }
+}
+
+// This squash is specifically for when Decode detects a PC-relative branch
+// was predicted incorrectly.
+template<class Impl>
+void
+SimpleDecode<Impl>::squash(DynInstPtr &inst)
+{
+ DPRINTF(Decode, "Decode: Squashing due to incorrect branch prediction "
+ "detected at decode.\n");
+ Addr new_PC = inst->readNextPC();
+
+ toFetch->decodeInfo.branchMispredict = true;
+ toFetch->decodeInfo.doneSeqNum = inst->seqNum;
+ toFetch->decodeInfo.predIncorrect = true;
+ toFetch->decodeInfo.squash = true;
+ toFetch->decodeInfo.nextPC = new_PC;
+ toFetch->decodeInfo.branchTaken = true;
+
+ // Set status to squashing.
+ _status = Squashing;
+
+ // Clear the skid buffer in case it has any data in it.
+ while (!skidBuffer.empty()) {
+ skidBuffer.pop();
+ }
+
+ // Squash instructions up until this one
+ // Slightly unrealistic!
+ cpu->removeInstsUntil(inst->seqNum);
+}
+
+template<class Impl>
+void
+SimpleDecode<Impl>::squash()
+{
+ DPRINTF(Decode, "Decode: Squashing.\n");
+ // Set status to squashing.
+ _status = Squashing;
+
+ // Maybe advance the time buffer? Not sure what to do in the normal
+ // case.
+
+ // Clear the skid buffer in case it has any data in it.
+ while (!skidBuffer.empty())
+ {
+ skidBuffer.pop();
+ }
+}
+
+template<class Impl>
+void
+SimpleDecode<Impl>::tick()
+{
+ // Decode should try to execute as many instructions as its bandwidth
+ // will allow, as long as it is not currently blocked.
+ if (_status != Blocked && _status != Squashing) {
+ DPRINTF(Decode, "Decode: Not blocked, so attempting to run "
+ "stage.\n");
+ // Make sure that the skid buffer has something in it if the
+ // status is unblocking.
+ assert(_status == Unblocking ? !skidBuffer.empty() : 1);
+
+ decode();
+
+ // If the status was unblocking, then instructions from the skid
+ // buffer were used. Remove those instructions and handle
+ // the rest of unblocking.
+ if (_status == Unblocking) {
+ ++decodeUnblockCycles;
+
+ if (fetchInstsValid()) {
+ // Add the current inputs to the skid buffer so they can be
+ // reprocessed when this stage unblocks.
+ skidBuffer.push(*fromFetch);
+ }
+
+ unblock();
+ }
+ } else if (_status == Blocked) {
+ ++decodeBlockedCycles;
+
+ if (fetchInstsValid()) {
+ block();
+ }
+
+ if (!fromRename->renameInfo.stall &&
+ !fromIEW->iewInfo.stall &&
+ !fromCommit->commitInfo.stall) {
+ DPRINTF(Decode, "Decode: Stall signals cleared, going to "
+ "unblock.\n");
+ _status = Unblocking;
+
+ // Continue to tell previous stage to block until this
+ // stage is done unblocking.
+ toFetch->decodeInfo.stall = true;
+ } else {
+ DPRINTF(Decode, "Decode: Still blocked.\n");
+ toFetch->decodeInfo.stall = true;
+ }
+
+ if (fromCommit->commitInfo.squash ||
+ fromCommit->commitInfo.robSquashing) {
+ squash();
+ }
+ } else if (_status == Squashing) {
+ if (!fromCommit->commitInfo.squash &&
+ !fromCommit->commitInfo.robSquashing) {
+ _status = Running;
+ } else if (fromCommit->commitInfo.squash) {
+ ++decodeSquashCycles;
+
+ squash();
+ }
+ }
+}
+
+template<class Impl>
+void
+SimpleDecode<Impl>::decode()
+{
+ // Check time buffer if being told to squash.
+ if (fromCommit->commitInfo.squash) {
+ squash();
+ return;
+ }
+
+ // Check time buffer if being told to stall.
+ if (fromRename->renameInfo.stall ||
+ fromIEW->iewInfo.stall ||
+ fromCommit->commitInfo.stall) {
+ block();
+ return;
+ }
+
+ // Check fetch queue to see if instructions are available.
+ // If no available instructions, do nothing, unless this stage is
+ // currently unblocking.
+ if (!fetchInstsValid() && _status != Unblocking) {
+ DPRINTF(Decode, "Decode: Nothing to do, breaking out early.\n");
+ // Should I change the status to idle?
+ ++decodeIdleCycles;
+ return;
+ }
+
+ // Might be better to use a base DynInst * instead?
+ DynInstPtr inst;
+
+ unsigned to_rename_index = 0;
+
+ int insts_available = _status == Unblocking ?
+ skidBuffer.front().size - numInst :
+ fromFetch->size;
+
+ // Debug block...
+#if 0
+ if (insts_available) {
+ DPRINTF(Decode, "Decode: Instructions available.\n");
+ } else {
+ if (_status == Unblocking && skidBuffer.empty()) {
+ DPRINTF(Decode, "Decode: No instructions available, skid buffer "
+ "empty.\n");
+ } else if (_status != Unblocking &&
+ !fromFetch->insts[0]) {
+ DPRINTF(Decode, "Decode: No instructions available, fetch queue "
+ "empty.\n");
+ } else {
+ panic("Decode: No instructions available, unexpected condition!"
+ "\n");
+ }
+ }
+#endif
+
+ while (insts_available > 0)
+ {
+ DPRINTF(Decode, "Decode: Sending instruction to rename.\n");
+
+ inst = _status == Unblocking ? skidBuffer.front().insts[numInst] :
+ fromFetch->insts[numInst];
+
+ DPRINTF(Decode, "Decode: Processing instruction %i with PC %#x\n",
+ inst->seqNum, inst->readPC());
+
+ if (inst->isSquashed()) {
+ DPRINTF(Decode, "Decode: Instruction %i with PC %#x is "
+ "squashed, skipping.\n",
+ inst->seqNum, inst->readPC());
+
+ ++decodeSquashedInsts;
+
+ ++numInst;
+ --insts_available;
+
+ continue;
+ }
+
+
+ // Also check if instructions have no source registers. Mark
+ // them as ready to issue at any time. Not sure if this check
+ // should exist here or at a later stage; however it doesn't matter
+ // too much for function correctness.
+ // Isn't this handled by the inst queue?
+ if (inst->numSrcRegs() == 0) {
+ inst->setCanIssue();
+ }
+
+ // This current instruction is valid, so add it into the decode
+ // queue. The next instruction may not be valid, so check to
+ // see if branches were predicted correctly.
+ toRename->insts[to_rename_index] = inst;
+
+ ++(toRename->size);
+
+ // Ensure that if it was predicted as a branch, it really is a
+ // branch.
+ if (inst->predTaken() && !inst->isControl()) {
+ panic("Instruction predicted as a branch!");
+
+ ++decodeControlMispred;
+ // Might want to set some sort of boolean and just do
+ // a check at the end
+ squash(inst);
+ break;
+ }
+
+ // Go ahead and compute any PC-relative branches.
+
+ if (inst->isDirectCtrl() && inst->isUncondCtrl()) {
+
+ inst->setNextPC(inst->branchTarget());
+
+ if (inst->mispredicted()) {
+ ++decodeBranchMispred;
+ // Might want to set some sort of boolean and just do
+ // a check at the end
+ squash(inst);
+ break;
+ }
+ }
+
+ // Normally can check if a direct branch has the right target
+ // addr (either the immediate, or the branch PC + 4) and redirect
+ // fetch if it's incorrect.
+
+ // Increment which instruction we're looking at.
+ ++numInst;
+ ++to_rename_index;
+ ++decodeDecodedInsts;
+
+ --insts_available;
+ }
+
+ numInst = 0;
+}
diff --git a/src/cpu/o3/fetch.cc b/src/cpu/o3/fetch.cc
new file mode 100644
index 000000000..8ad5e6565
--- /dev/null
+++ b/src/cpu/o3/fetch.cc
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "cpu/o3/alpha_dyn_inst.hh"
+#include "cpu/o3/alpha_impl.hh"
+#include "cpu/o3/fetch_impl.hh"
+
+template class SimpleFetch<AlphaSimpleImpl>;
diff --git a/src/cpu/o3/fetch.hh b/src/cpu/o3/fetch.hh
new file mode 100644
index 000000000..cc64800d9
--- /dev/null
+++ b/src/cpu/o3/fetch.hh
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Todo: SMT fetch,
+// Add a way to get a stage's current status.
+
+#ifndef __CPU_O3_CPU_SIMPLE_FETCH_HH__
+#define __CPU_O3_CPU_SIMPLE_FETCH_HH__
+
+#include "base/statistics.hh"
+#include "base/timebuf.hh"
+#include "cpu/pc_event.hh"
+#include "mem/mem_interface.hh"
+#include "sim/eventq.hh"
+
+/**
+ * SimpleFetch class to fetch a single instruction each cycle. SimpleFetch
+ * will stall if there's an Icache miss, but otherwise assumes a one cycle
+ * Icache hit.
+ */
+
+template <class Impl>
+class SimpleFetch
+{
+ public:
+ /** Typedefs from Impl. */
+ typedef typename Impl::CPUPol CPUPol;
+ typedef typename Impl::DynInst DynInst;
+ typedef typename Impl::DynInstPtr DynInstPtr;
+ typedef typename Impl::FullCPU FullCPU;
+ typedef typename Impl::Params Params;
+
+ typedef typename CPUPol::BPredUnit BPredUnit;
+ typedef typename CPUPol::FetchStruct FetchStruct;
+ typedef typename CPUPol::TimeStruct TimeStruct;
+
+ /** Typedefs from ISA. */
+ typedef TheISA::MachInst MachInst;
+
+ public:
+ enum Status {
+ Running,
+ Idle,
+ Squashing,
+ Blocked,
+ IcacheMissStall,
+ IcacheMissComplete
+ };
+
+ // May eventually need statuses on a per thread basis.
+ Status _status;
+
+ bool stalled;
+
+ public:
+ class CacheCompletionEvent : public Event
+ {
+ private:
+ SimpleFetch *fetch;
+
+ public:
+ CacheCompletionEvent(SimpleFetch *_fetch);
+
+ virtual void process();
+ virtual const char *description();
+ };
+
+ public:
+ /** SimpleFetch constructor. */
+ SimpleFetch(Params &params);
+
+ void regStats();
+
+ void setCPU(FullCPU *cpu_ptr);
+
+ void setTimeBuffer(TimeBuffer<TimeStruct> *time_buffer);
+
+ void setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr);
+
+ void processCacheCompletion();
+
+ private:
+ /**
+ * Looks up in the branch predictor to see if the next PC should be
+ * either next PC+=MachInst or a branch target.
+ * @param next_PC Next PC variable passed in by reference. It is
+ * expected to be set to the current PC; it will be updated with what
+ * the next PC will be.
+ * @return Whether or not a branch was predicted as taken.
+ */
+ bool lookupAndUpdateNextPC(DynInstPtr &inst, Addr &next_PC);
+
+ /**
+ * Fetches the cache line that contains fetch_PC. Returns any
+ * fault that happened. Puts the data into the class variable
+ * cacheData.
+ * @param fetch_PC The PC address that is being fetched from.
+ * @return Any fault that occured.
+ */
+ Fault fetchCacheLine(Addr fetch_PC);
+
+ inline void doSquash(const Addr &new_PC);
+
+ void squashFromDecode(const Addr &new_PC, const InstSeqNum &seq_num);
+
+ public:
+ // Figure out PC vs next PC and how it should be updated
+ void squash(const Addr &new_PC);
+
+ void tick();
+
+ void fetch();
+
+ // Align an address (typically a PC) to the start of an I-cache block.
+ // We fold in the PISA 64- to 32-bit conversion here as well.
+ Addr icacheBlockAlignPC(Addr addr)
+ {
+ addr = TheISA::realPCToFetchPC(addr);
+ return (addr & ~(cacheBlkMask));
+ }
+
+ private:
+ /** Pointer to the FullCPU. */
+ FullCPU *cpu;
+
+ /** Time buffer interface. */
+ TimeBuffer<TimeStruct> *timeBuffer;
+
+ /** Wire to get decode's information from backwards time buffer. */
+ typename TimeBuffer<TimeStruct>::wire fromDecode;
+
+ /** Wire to get rename's information from backwards time buffer. */
+ typename TimeBuffer<TimeStruct>::wire fromRename;
+
+ /** Wire to get iew's information from backwards time buffer. */
+ typename TimeBuffer<TimeStruct>::wire fromIEW;
+
+ /** Wire to get commit's information from backwards time buffer. */
+ typename TimeBuffer<TimeStruct>::wire fromCommit;
+
+ /** Internal fetch instruction queue. */
+ TimeBuffer<FetchStruct> *fetchQueue;
+
+ //Might be annoying how this name is different than the queue.
+ /** Wire used to write any information heading to decode. */
+ typename TimeBuffer<FetchStruct>::wire toDecode;
+
+ /** Icache interface. */
+ MemInterface *icacheInterface;
+
+ /** BPredUnit. */
+ BPredUnit branchPred;
+
+ /** Memory request used to access cache. */
+ MemReqPtr memReq;
+
+ /** Decode to fetch delay, in ticks. */
+ unsigned decodeToFetchDelay;
+
+ /** Rename to fetch delay, in ticks. */
+ unsigned renameToFetchDelay;
+
+ /** IEW to fetch delay, in ticks. */
+ unsigned iewToFetchDelay;
+
+ /** Commit to fetch delay, in ticks. */
+ unsigned commitToFetchDelay;
+
+ /** The width of fetch in instructions. */
+ unsigned fetchWidth;
+
+ /** Cache block size. */
+ int cacheBlkSize;
+
+ /** Mask to get a cache block's address. */
+ Addr cacheBlkMask;
+
+ /** The cache line being fetched. */
+ uint8_t *cacheData;
+
+ /** Size of instructions. */
+ int instSize;
+
+ /** Icache stall statistics. */
+ Counter lastIcacheStall;
+
+ Stats::Scalar<> icacheStallCycles;
+ Stats::Scalar<> fetchedInsts;
+ Stats::Scalar<> predictedBranches;
+ Stats::Scalar<> fetchCycles;
+ Stats::Scalar<> fetchSquashCycles;
+ Stats::Scalar<> fetchBlockedCycles;
+ Stats::Scalar<> fetchedCacheLines;
+
+ Stats::Distribution<> fetch_nisn_dist;
+};
+
+#endif //__CPU_O3_CPU_SIMPLE_FETCH_HH__
diff --git a/src/cpu/o3/fetch_impl.hh b/src/cpu/o3/fetch_impl.hh
new file mode 100644
index 000000000..8029fc732
--- /dev/null
+++ b/src/cpu/o3/fetch_impl.hh
@@ -0,0 +1,617 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Remove this later; used only for debugging.
+#define OPCODE(X) (X >> 26) & 0x3f
+
+#include "arch/isa_traits.hh"
+#include "sim/byteswap.hh"
+#include "cpu/exetrace.hh"
+#include "mem/base_mem.hh"
+#include "mem/mem_interface.hh"
+#include "mem/mem_req.hh"
+#include "cpu/o3/fetch.hh"
+
+#include "sim/root.hh"
+
+template<class Impl>
+SimpleFetch<Impl>::CacheCompletionEvent
+::CacheCompletionEvent(SimpleFetch *_fetch)
+ : Event(&mainEventQueue),
+ fetch(_fetch)
+{
+}
+
+template<class Impl>
+void
+SimpleFetch<Impl>::CacheCompletionEvent::process()
+{
+ fetch->processCacheCompletion();
+}
+
+template<class Impl>
+const char *
+SimpleFetch<Impl>::CacheCompletionEvent::description()
+{
+ return "SimpleFetch cache completion event";
+}
+
+template<class Impl>
+SimpleFetch<Impl>::SimpleFetch(Params &params)
+ : icacheInterface(params.icacheInterface),
+ branchPred(params),
+ decodeToFetchDelay(params.decodeToFetchDelay),
+ renameToFetchDelay(params.renameToFetchDelay),
+ iewToFetchDelay(params.iewToFetchDelay),
+ commitToFetchDelay(params.commitToFetchDelay),
+ fetchWidth(params.fetchWidth)
+{
+ DPRINTF(Fetch, "Fetch: Fetch constructor called\n");
+
+ // Set status to idle.
+ _status = Idle;
+
+ // Create a new memory request.
+ memReq = new MemReq();
+ // Not sure of this parameter. I think it should be based on the
+ // thread number.
+#if !FULL_SYSTEM
+ memReq->asid = 0;
+#else
+ memReq->asid = 0;
+#endif // FULL_SYSTEM
+ memReq->data = new uint8_t[64];
+
+ // Size of cache block.
+ cacheBlkSize = icacheInterface ? icacheInterface->getBlockSize() : 64;
+
+ // Create mask to get rid of offset bits.
+ cacheBlkMask = (cacheBlkSize - 1);
+
+ // Get the size of an instruction.
+ instSize = sizeof(MachInst);
+
+ // Create space to store a cache line.
+ cacheData = new uint8_t[cacheBlkSize];
+}
+
+template <class Impl>
+void
+SimpleFetch<Impl>::regStats()
+{
+ icacheStallCycles
+ .name(name() + ".icacheStallCycles")
+ .desc("Number of cycles fetch is stalled on an Icache miss")
+ .prereq(icacheStallCycles);
+
+ fetchedInsts
+ .name(name() + ".fetchedInsts")
+ .desc("Number of instructions fetch has processed")
+ .prereq(fetchedInsts);
+ predictedBranches
+ .name(name() + ".predictedBranches")
+ .desc("Number of branches that fetch has predicted taken")
+ .prereq(predictedBranches);
+ fetchCycles
+ .name(name() + ".fetchCycles")
+ .desc("Number of cycles fetch has run and was not squashing or"
+ " blocked")
+ .prereq(fetchCycles);
+ fetchSquashCycles
+ .name(name() + ".fetchSquashCycles")
+ .desc("Number of cycles fetch has spent squashing")
+ .prereq(fetchSquashCycles);
+ fetchBlockedCycles
+ .name(name() + ".fetchBlockedCycles")
+ .desc("Number of cycles fetch has spent blocked")
+ .prereq(fetchBlockedCycles);
+ fetchedCacheLines
+ .name(name() + ".fetchedCacheLines")
+ .desc("Number of cache lines fetched")
+ .prereq(fetchedCacheLines);
+
+ fetch_nisn_dist
+ .init(/* base value */ 0,
+ /* last value */ fetchWidth,
+ /* bucket size */ 1)
+ .name(name() + ".FETCH:rate_dist")
+ .desc("Number of instructions fetched each cycle (Total)")
+ .flags(Stats::pdf)
+ ;
+
+ branchPred.regStats();
+}
+
+template<class Impl>
+void
+SimpleFetch<Impl>::setCPU(FullCPU *cpu_ptr)
+{
+ DPRINTF(Fetch, "Fetch: Setting the CPU pointer.\n");
+ cpu = cpu_ptr;
+ // This line will be removed eventually.
+ memReq->xc = cpu->xcBase();
+}
+
+template<class Impl>
+void
+SimpleFetch<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *time_buffer)
+{
+ DPRINTF(Fetch, "Fetch: Setting the time buffer pointer.\n");
+ timeBuffer = time_buffer;
+
+ // Create wires to get information from proper places in time buffer.
+ fromDecode = timeBuffer->getWire(-decodeToFetchDelay);
+ fromRename = timeBuffer->getWire(-renameToFetchDelay);
+ fromIEW = timeBuffer->getWire(-iewToFetchDelay);
+ fromCommit = timeBuffer->getWire(-commitToFetchDelay);
+}
+
+template<class Impl>
+void
+SimpleFetch<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr)
+{
+ DPRINTF(Fetch, "Fetch: Setting the fetch queue pointer.\n");
+ fetchQueue = fq_ptr;
+
+ // Create wire to write information to proper place in fetch queue.
+ toDecode = fetchQueue->getWire(0);
+}
+
+template<class Impl>
+void
+SimpleFetch<Impl>::processCacheCompletion()
+{
+ DPRINTF(Fetch, "Fetch: Waking up from cache miss.\n");
+
+ // Only change the status if it's still waiting on the icache access
+ // to return.
+ // Can keep track of how many cache accesses go unused due to
+ // misspeculation here.
+ if (_status == IcacheMissStall)
+ _status = IcacheMissComplete;
+}
+
+template <class Impl>
+bool
+SimpleFetch<Impl>::lookupAndUpdateNextPC(DynInstPtr &inst, Addr &next_PC)
+{
+ // Do branch prediction check here.
+ // A bit of a misnomer...next_PC is actually the current PC until
+ // this function updates it.
+ bool predict_taken;
+
+ if (!inst->isControl()) {
+ next_PC = next_PC + instSize;
+ inst->setPredTarg(next_PC);
+ return false;
+ }
+
+ predict_taken = branchPred.predict(inst, next_PC);
+
+ if (predict_taken) {
+ ++predictedBranches;
+ }
+
+ return predict_taken;
+}
+
+template <class Impl>
+Fault
+SimpleFetch<Impl>::fetchCacheLine(Addr fetch_PC)
+{
+ // Check if the instruction exists within the cache.
+ // If it does, then proceed on to read the instruction and the rest
+ // of the instructions in the cache line until either the end of the
+ // cache line or a predicted taken branch is encountered.
+
+#if FULL_SYSTEM
+ // Flag to say whether or not address is physical addr.
+ unsigned flags = cpu->inPalMode() ? PHYSICAL : 0;
+#else
+ unsigned flags = 0;
+#endif // FULL_SYSTEM
+
+ Fault fault = NoFault;
+
+ // Align the fetch PC so it's at the start of a cache block.
+ fetch_PC = icacheBlockAlignPC(fetch_PC);
+
+ // Setup the memReq to do a read of the first isntruction's address.
+ // Set the appropriate read size and flags as well.
+ memReq->cmd = Read;
+ memReq->reset(fetch_PC, cacheBlkSize, flags);
+
+ // Translate the instruction request.
+ // Should this function be
+ // in the CPU class ? Probably...ITB/DTB should exist within the
+ // CPU.
+
+ fault = cpu->translateInstReq(memReq);
+
+ // In the case of faults, the fetch stage may need to stall and wait
+ // on what caused the fetch (ITB or Icache miss).
+
+ // If translation was successful, attempt to read the first
+ // instruction.
+ if (fault == NoFault) {
+ DPRINTF(Fetch, "Fetch: Doing instruction read.\n");
+ fault = cpu->mem->read(memReq, cacheData);
+ // This read may change when the mem interface changes.
+
+ fetchedCacheLines++;
+ }
+
+ // Now do the timing access to see whether or not the instruction
+ // exists within the cache.
+ if (icacheInterface && fault == NoFault) {
+ DPRINTF(Fetch, "Fetch: Doing timing memory access.\n");
+ memReq->completionEvent = NULL;
+
+ memReq->time = curTick;
+
+ MemAccessResult result = icacheInterface->access(memReq);
+
+ // If the cache missed (in this model functional and timing
+ // memories are different), then schedule an event to wake
+ // up this stage once the cache miss completes.
+ if (result != MA_HIT && icacheInterface->doEvents()) {
+ memReq->completionEvent = new CacheCompletionEvent(this);
+
+ // How does current model work as far as individual
+ // stages scheduling/unscheduling?
+ // Perhaps have only the main CPU scheduled/unscheduled,
+ // and have it choose what stages to run appropriately.
+
+ DPRINTF(Fetch, "Fetch: Stalling due to icache miss.\n");
+ _status = IcacheMissStall;
+ }
+ }
+
+ return fault;
+}
+
+template <class Impl>
+inline void
+SimpleFetch<Impl>::doSquash(const Addr &new_PC)
+{
+ DPRINTF(Fetch, "Fetch: Squashing, setting PC to: %#x.\n", new_PC);
+
+ cpu->setNextPC(new_PC + instSize);
+ cpu->setPC(new_PC);
+
+ // Clear the icache miss if it's outstanding.
+ if (_status == IcacheMissStall && icacheInterface) {
+ DPRINTF(Fetch, "Fetch: Squashing outstanding Icache miss.\n");
+ // @todo: Use an actual thread number here.
+ icacheInterface->squash(0);
+ }
+
+ _status = Squashing;
+
+ ++fetchSquashCycles;
+}
+
+template<class Impl>
+void
+SimpleFetch<Impl>::squashFromDecode(const Addr &new_PC,
+ const InstSeqNum &seq_num)
+{
+ DPRINTF(Fetch, "Fetch: Squashing from decode.\n");
+
+ doSquash(new_PC);
+
+ // Tell the CPU to remove any instructions that are in flight between
+ // fetch and decode.
+ cpu->removeInstsUntil(seq_num);
+}
+
+template <class Impl>
+void
+SimpleFetch<Impl>::squash(const Addr &new_PC)
+{
+ DPRINTF(Fetch, "Fetch: Squash from commit.\n");
+
+ doSquash(new_PC);
+
+ // Tell the CPU to remove any instructions that are not in the ROB.
+ cpu->removeInstsNotInROB();
+}
+
+template<class Impl>
+void
+SimpleFetch<Impl>::tick()
+{
+ // Check squash signals from commit.
+ if (fromCommit->commitInfo.squash) {
+ DPRINTF(Fetch, "Fetch: Squashing instructions due to squash "
+ "from commit.\n");
+
+ // In any case, squash.
+ squash(fromCommit->commitInfo.nextPC);
+
+ // Also check if there's a mispredict that happened.
+ if (fromCommit->commitInfo.branchMispredict) {
+ branchPred.squash(fromCommit->commitInfo.doneSeqNum,
+ fromCommit->commitInfo.nextPC,
+ fromCommit->commitInfo.branchTaken);
+ } else {
+ branchPred.squash(fromCommit->commitInfo.doneSeqNum);
+ }
+
+ return;
+ } else if (fromCommit->commitInfo.doneSeqNum) {
+ // Update the branch predictor if it wasn't a squashed instruction
+ // that was braodcasted.
+ branchPred.update(fromCommit->commitInfo.doneSeqNum);
+ }
+
+ // Check ROB squash signals from commit.
+ if (fromCommit->commitInfo.robSquashing) {
+ DPRINTF(Fetch, "Fetch: ROB is still squashing.\n");
+
+ // Continue to squash.
+ _status = Squashing;
+
+ ++fetchSquashCycles;
+ return;
+ }
+
+ // Check squash signals from decode.
+ if (fromDecode->decodeInfo.squash) {
+ DPRINTF(Fetch, "Fetch: Squashing instructions due to squash "
+ "from decode.\n");
+
+ // Update the branch predictor.
+ if (fromDecode->decodeInfo.branchMispredict) {
+ branchPred.squash(fromDecode->decodeInfo.doneSeqNum,
+ fromDecode->decodeInfo.nextPC,
+ fromDecode->decodeInfo.branchTaken);
+ } else {
+ branchPred.squash(fromDecode->decodeInfo.doneSeqNum);
+ }
+
+ if (_status != Squashing) {
+ // Squash unless we're already squashing?
+ squashFromDecode(fromDecode->decodeInfo.nextPC,
+ fromDecode->decodeInfo.doneSeqNum);
+ return;
+ }
+ }
+
+ // Check if any of the stall signals are high.
+ if (fromDecode->decodeInfo.stall ||
+ fromRename->renameInfo.stall ||
+ fromIEW->iewInfo.stall ||
+ fromCommit->commitInfo.stall)
+ {
+ // Block stage, regardless of current status.
+
+ DPRINTF(Fetch, "Fetch: Stalling stage.\n");
+ DPRINTF(Fetch, "Fetch: Statuses: Decode: %i Rename: %i IEW: %i "
+ "Commit: %i\n",
+ fromDecode->decodeInfo.stall,
+ fromRename->renameInfo.stall,
+ fromIEW->iewInfo.stall,
+ fromCommit->commitInfo.stall);
+
+ _status = Blocked;
+
+ ++fetchBlockedCycles;
+ return;
+ } else if (_status == Blocked) {
+ // Unblock stage if status is currently blocked and none of the
+ // stall signals are being held high.
+ _status = Running;
+
+ ++fetchBlockedCycles;
+ return;
+ }
+
+ // If fetch has reached this point, then there are no squash signals
+ // still being held high. Check if fetch is in the squashing state;
+ // if so, fetch can switch to running.
+ // Similarly, there are no blocked signals still being held high.
+ // Check if fetch is in the blocked state; if so, fetch can switch to
+ // running.
+ if (_status == Squashing) {
+ DPRINTF(Fetch, "Fetch: Done squashing, switching to running.\n");
+
+ // Switch status to running
+ _status = Running;
+
+ ++fetchCycles;
+
+ fetch();
+ } else if (_status != IcacheMissStall) {
+ DPRINTF(Fetch, "Fetch: Running stage.\n");
+
+ ++fetchCycles;
+
+ fetch();
+ }
+}
+
+template<class Impl>
+void
+SimpleFetch<Impl>::fetch()
+{
+ //////////////////////////////////////////
+ // Start actual fetch
+ //////////////////////////////////////////
+
+ // The current PC.
+ Addr fetch_PC = cpu->readPC();
+
+ // Fault code for memory access.
+ Fault fault = NoFault;
+
+ // If returning from the delay of a cache miss, then update the status
+ // to running, otherwise do the cache access. Possibly move this up
+ // to tick() function.
+ if (_status == IcacheMissComplete) {
+ DPRINTF(Fetch, "Fetch: Icache miss is complete.\n");
+
+ // Reset the completion event to NULL.
+ memReq->completionEvent = NULL;
+
+ _status = Running;
+ } else {
+ DPRINTF(Fetch, "Fetch: Attempting to translate and read "
+ "instruction, starting at PC %08p.\n",
+ fetch_PC);
+
+ fault = fetchCacheLine(fetch_PC);
+ }
+
+ // If we had a stall due to an icache miss, then return. It'd
+ // be nicer if this were handled through the kind of fault that
+ // is returned by the function.
+ if (_status == IcacheMissStall) {
+ return;
+ }
+
+ // As far as timing goes, the CPU will need to send an event through
+ // the MemReq in order to be woken up once the memory access completes.
+ // Probably have a status on a per thread basis so each thread can
+ // block independently and be woken up independently.
+
+ Addr next_PC = fetch_PC;
+ InstSeqNum inst_seq;
+ MachInst inst;
+ unsigned offset = fetch_PC & cacheBlkMask;
+ unsigned fetched;
+
+ if (fault == NoFault) {
+ // If the read of the first instruction was successful, then grab the
+ // instructions from the rest of the cache line and put them into the
+ // queue heading to decode.
+
+ DPRINTF(Fetch, "Fetch: Adding instructions to queue to decode.\n");
+
+ //////////////////////////
+ // Fetch first instruction
+ //////////////////////////
+
+ // Need to keep track of whether or not a predicted branch
+ // ended this fetch block.
+ bool predicted_branch = false;
+
+ for (fetched = 0;
+ offset < cacheBlkSize &&
+ fetched < fetchWidth &&
+ !predicted_branch;
+ ++fetched)
+ {
+
+ // Get a sequence number.
+ inst_seq = cpu->getAndIncrementInstSeq();
+
+ // Make sure this is a valid index.
+ assert(offset <= cacheBlkSize - instSize);
+
+ // Get the instruction from the array of the cache line.
+ inst = gtoh(*reinterpret_cast<MachInst *>
+ (&cacheData[offset]));
+
+ // Create a new DynInst from the instruction fetched.
+ DynInstPtr instruction = new DynInst(inst, fetch_PC, next_PC,
+ inst_seq, cpu);
+
+ DPRINTF(Fetch, "Fetch: Instruction %i created, with PC %#x\n",
+ inst_seq, instruction->readPC());
+
+ DPRINTF(Fetch, "Fetch: Instruction opcode is: %03p\n",
+ OPCODE(inst));
+
+ instruction->traceData =
+ Trace::getInstRecord(curTick, cpu->xcBase(), cpu,
+ instruction->staticInst,
+ instruction->readPC(), 0);
+
+ predicted_branch = lookupAndUpdateNextPC(instruction, next_PC);
+
+ // Add instruction to the CPU's list of instructions.
+ cpu->addInst(instruction);
+
+ // Write the instruction to the first slot in the queue
+ // that heads to decode.
+ toDecode->insts[fetched] = instruction;
+
+ toDecode->size++;
+
+ // Increment stat of fetched instructions.
+ ++fetchedInsts;
+
+ // Move to the next instruction, unless we have a branch.
+ fetch_PC = next_PC;
+
+ offset+= instSize;
+ }
+
+ fetch_nisn_dist.sample(fetched);
+ }
+
+ // Now that fetching is completed, update the PC to signify what the next
+ // cycle will be. Might want to move this to the beginning of this
+ // function so that the PC updates at the beginning of everything.
+ // Or might want to leave setting the PC to the main CPU, with fetch
+ // only changing the nextPC (will require correct determination of
+ // next PC).
+ if (fault == NoFault) {
+ DPRINTF(Fetch, "Fetch: Setting PC to %08p.\n", next_PC);
+ cpu->setPC(next_PC);
+ cpu->setNextPC(next_PC + instSize);
+ } else {
+ // If the issue was an icache miss, then we can just return and
+ // wait until it is handled.
+ if (_status == IcacheMissStall) {
+ return;
+ }
+
+ // Handle the fault.
+ // This stage will not be able to continue until all the ROB
+ // slots are empty, at which point the fault can be handled.
+ // The only other way it can wake up is if a squash comes along
+ // and changes the PC. Not sure how to handle that case...perhaps
+ // have it handled by the upper level CPU class which peeks into the
+ // time buffer and sees if a squash comes along, in which case it
+ // changes the status.
+
+ DPRINTF(Fetch, "Fetch: Blocked, need to handle the trap.\n");
+
+ _status = Blocked;
+#if FULL_SYSTEM
+// cpu->trap(fault);
+ // Send a signal to the ROB indicating that there's a trap from the
+ // fetch stage that needs to be handled. Need to indicate that
+ // there's a fault, and the fault type.
+#else // !FULL_SYSTEM
+ fatal("fault (%d) detected @ PC %08p", fault, cpu->readPC());
+#endif // FULL_SYSTEM
+ }
+}
diff --git a/src/cpu/o3/free_list.cc b/src/cpu/o3/free_list.cc
new file mode 100644
index 000000000..6f0b4be1e
--- /dev/null
+++ b/src/cpu/o3/free_list.cc
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "base/trace.hh"
+
+#include "cpu/o3/free_list.hh"
+
+SimpleFreeList::SimpleFreeList(unsigned _numLogicalIntRegs,
+ unsigned _numPhysicalIntRegs,
+ unsigned _numLogicalFloatRegs,
+ unsigned _numPhysicalFloatRegs)
+ : numLogicalIntRegs(_numLogicalIntRegs),
+ numPhysicalIntRegs(_numPhysicalIntRegs),
+ numLogicalFloatRegs(_numLogicalFloatRegs),
+ numPhysicalFloatRegs(_numPhysicalFloatRegs),
+ numPhysicalRegs(numPhysicalIntRegs + numPhysicalFloatRegs)
+{
+ DPRINTF(FreeList, "FreeList: Creating new free list object.\n");
+
+ // DEBUG stuff.
+ freeIntRegsScoreboard.resize(numPhysicalIntRegs);
+
+ freeFloatRegsScoreboard.resize(numPhysicalRegs);
+
+ for (PhysRegIndex i = 0; i < numLogicalIntRegs; ++i) {
+ freeIntRegsScoreboard[i] = 0;
+ }
+
+ // Put all of the extra physical registers onto the free list. This
+ // means excluding all of the base logical registers.
+ for (PhysRegIndex i = numLogicalIntRegs;
+ i < numPhysicalIntRegs; ++i)
+ {
+ freeIntRegs.push(i);
+
+ freeIntRegsScoreboard[i] = 1;
+ }
+
+ for (PhysRegIndex i = 0; i < numPhysicalIntRegs + numLogicalFloatRegs;
+ ++i)
+ {
+ freeFloatRegsScoreboard[i] = 0;
+ }
+
+ // Put all of the extra physical registers onto the free list. This
+ // means excluding all of the base logical registers. Because the
+ // float registers' indices start where the physical registers end,
+ // some math must be done to determine where the free registers start.
+ for (PhysRegIndex i = numPhysicalIntRegs + numLogicalFloatRegs;
+ i < numPhysicalRegs; ++i)
+ {
+ freeFloatRegs.push(i);
+
+ freeFloatRegsScoreboard[i] = 1;
+ }
+}
+
diff --git a/src/cpu/o3/free_list.hh b/src/cpu/o3/free_list.hh
new file mode 100644
index 000000000..0b85dba1e
--- /dev/null
+++ b/src/cpu/o3/free_list.hh
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPU_O3_CPU_FREE_LIST_HH__
+#define __CPU_O3_CPU_FREE_LIST_HH__
+
+#include <iostream>
+#include <queue>
+
+#include "arch/isa_traits.hh"
+#include "base/trace.hh"
+#include "base/traceflags.hh"
+#include "cpu/o3/comm.hh"
+
+/**
+ * FreeList class that simply holds the list of free integer and floating
+ * point registers. Can request for a free register of either type, and
+ * also send back free registers of either type. This is a very simple
+ * class, but it should be sufficient for most implementations. Like all
+ * other classes, it assumes that the indices for the floating point
+ * registers starts after the integer registers end. Hence the variable
+ * numPhysicalIntRegs is logically equivalent to the baseFP dependency.
+ * Note that
+ * while this most likely should be called FreeList, the name "FreeList"
+ * is used in a typedef within the CPU Policy, and therefore no class
+ * can be named simply "FreeList".
+ * @todo: Give a better name to the base FP dependency.
+ */
+class SimpleFreeList
+{
+ private:
+ /** The list of free integer registers. */
+ std::queue<PhysRegIndex> freeIntRegs;
+
+ /** The list of free floating point registers. */
+ std::queue<PhysRegIndex> freeFloatRegs;
+
+ /** Number of logical integer registers. */
+ int numLogicalIntRegs;
+
+ /** Number of physical integer registers. */
+ int numPhysicalIntRegs;
+
+ /** Number of logical floating point registers. */
+ int numLogicalFloatRegs;
+
+ /** Number of physical floating point registers. */
+ int numPhysicalFloatRegs;
+
+ /** Total number of physical registers. */
+ int numPhysicalRegs;
+
+ /** DEBUG stuff below. */
+ std::vector<int> freeIntRegsScoreboard;
+
+ std::vector<bool> freeFloatRegsScoreboard;
+
+ public:
+ SimpleFreeList(unsigned _numLogicalIntRegs,
+ unsigned _numPhysicalIntRegs,
+ unsigned _numLogicalFloatRegs,
+ unsigned _numPhysicalFloatRegs);
+
+ inline PhysRegIndex getIntReg();
+
+ inline PhysRegIndex getFloatReg();
+
+ inline void addReg(PhysRegIndex freed_reg);
+
+ inline void addIntReg(PhysRegIndex freed_reg);
+
+ inline void addFloatReg(PhysRegIndex freed_reg);
+
+ bool hasFreeIntRegs()
+ { return !freeIntRegs.empty(); }
+
+ bool hasFreeFloatRegs()
+ { return !freeFloatRegs.empty(); }
+
+ int numFreeIntRegs()
+ { return freeIntRegs.size(); }
+
+ int numFreeFloatRegs()
+ { return freeFloatRegs.size(); }
+};
+
+inline PhysRegIndex
+SimpleFreeList::getIntReg()
+{
+ DPRINTF(Rename, "FreeList: Trying to get free integer register.\n");
+ if (freeIntRegs.empty()) {
+ panic("No free integer registers!");
+ }
+
+ PhysRegIndex free_reg = freeIntRegs.front();
+
+ freeIntRegs.pop();
+
+ // DEBUG
+ assert(freeIntRegsScoreboard[free_reg]);
+ freeIntRegsScoreboard[free_reg] = 0;
+
+ return(free_reg);
+}
+
+inline PhysRegIndex
+SimpleFreeList::getFloatReg()
+{
+ DPRINTF(Rename, "FreeList: Trying to get free float register.\n");
+ if (freeFloatRegs.empty()) {
+ panic("No free integer registers!");
+ }
+
+ PhysRegIndex free_reg = freeFloatRegs.front();
+
+ freeFloatRegs.pop();
+
+ // DEBUG
+ assert(freeFloatRegsScoreboard[free_reg]);
+ freeFloatRegsScoreboard[free_reg] = 0;
+
+ return(free_reg);
+}
+
+inline void
+SimpleFreeList::addReg(PhysRegIndex freed_reg)
+{
+ DPRINTF(Rename, "Freelist: Freeing register %i.\n", freed_reg);
+ //Might want to add in a check for whether or not this register is
+ //already in there. A bit vector or something similar would be useful.
+ if (freed_reg < numPhysicalIntRegs) {
+ freeIntRegs.push(freed_reg);
+
+ // DEBUG
+ assert(freeIntRegsScoreboard[freed_reg] == false);
+ freeIntRegsScoreboard[freed_reg] = 1;
+ } else if (freed_reg < numPhysicalRegs) {
+ freeFloatRegs.push(freed_reg);
+
+ // DEBUG
+ assert(freeFloatRegsScoreboard[freed_reg] == false);
+ freeFloatRegsScoreboard[freed_reg] = 1;
+ }
+}
+
+inline void
+SimpleFreeList::addIntReg(PhysRegIndex freed_reg)
+{
+ DPRINTF(Rename, "Freelist: Freeing int register %i.\n", freed_reg);
+
+ // DEBUG
+ assert(!freeIntRegsScoreboard[freed_reg]);
+ freeIntRegsScoreboard[freed_reg] = 1;
+
+ freeIntRegs.push(freed_reg);
+}
+
+inline void
+SimpleFreeList::addFloatReg(PhysRegIndex freed_reg)
+{
+ DPRINTF(Rename, "Freelist: Freeing float register %i.\n", freed_reg);
+
+ // DEBUG
+ assert(!freeFloatRegsScoreboard[freed_reg]);
+ freeFloatRegsScoreboard[freed_reg] = 1;
+
+ freeFloatRegs.push(freed_reg);
+}
+
+#endif // __CPU_O3_CPU_FREE_LIST_HH__
diff --git a/src/cpu/o3/iew.cc b/src/cpu/o3/iew.cc
new file mode 100644
index 000000000..45b5610e7
--- /dev/null
+++ b/src/cpu/o3/iew.cc
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "cpu/o3/alpha_dyn_inst.hh"
+#include "cpu/o3/alpha_impl.hh"
+#include "cpu/o3/iew_impl.hh"
+#include "cpu/o3/inst_queue.hh"
+
+template class SimpleIEW<AlphaSimpleImpl>;
diff --git a/src/cpu/o3/iew.hh b/src/cpu/o3/iew.hh
new file mode 100644
index 000000000..1e370d4e6
--- /dev/null
+++ b/src/cpu/o3/iew.hh
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//Todo: Update with statuses.
+//Need to handle delaying writes to the writeback bus if it's full at the
+//given time.
+
+#ifndef __CPU_O3_CPU_SIMPLE_IEW_HH__
+#define __CPU_O3_CPU_SIMPLE_IEW_HH__
+
+#include <queue>
+
+#include "config/full_system.hh"
+#include "base/statistics.hh"
+#include "base/timebuf.hh"
+#include "cpu/o3/comm.hh"
+
+template<class Impl>
+class SimpleIEW
+{
+ private:
+ //Typedefs from Impl
+ typedef typename Impl::CPUPol CPUPol;
+ typedef typename Impl::DynInstPtr DynInstPtr;
+ typedef typename Impl::FullCPU FullCPU;
+ typedef typename Impl::Params Params;
+
+ typedef typename CPUPol::IQ IQ;
+ typedef typename CPUPol::RenameMap RenameMap;
+ typedef typename CPUPol::LDSTQ LDSTQ;
+
+ typedef typename CPUPol::TimeStruct TimeStruct;
+ typedef typename CPUPol::IEWStruct IEWStruct;
+ typedef typename CPUPol::RenameStruct RenameStruct;
+ typedef typename CPUPol::IssueStruct IssueStruct;
+
+ friend class Impl::FullCPU;
+ public:
+ enum Status {
+ Running,
+ Blocked,
+ Idle,
+ Squashing,
+ Unblocking
+ };
+
+ private:
+ Status _status;
+ Status _issueStatus;
+ Status _exeStatus;
+ Status _wbStatus;
+
+ public:
+ class WritebackEvent : public Event {
+ private:
+ DynInstPtr inst;
+ SimpleIEW<Impl> *iewStage;
+
+ public:
+ WritebackEvent(DynInstPtr &_inst, SimpleIEW<Impl> *_iew);
+
+ virtual void process();
+ virtual const char *description();
+ };
+
+ public:
+ SimpleIEW(Params &params);
+
+ void regStats();
+
+ void setCPU(FullCPU *cpu_ptr);
+
+ void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr);
+
+ void setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr);
+
+ void setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr);
+
+ void setRenameMap(RenameMap *rm_ptr);
+
+ void squash();
+
+ void squashDueToBranch(DynInstPtr &inst);
+
+ void squashDueToMem(DynInstPtr &inst);
+
+ void block();
+
+ inline void unblock();
+
+ void wakeDependents(DynInstPtr &inst);
+
+ void instToCommit(DynInstPtr &inst);
+
+ private:
+ void dispatchInsts();
+
+ void executeInsts();
+
+ public:
+ void tick();
+
+ void iew();
+
+ //Interfaces to objects inside and outside of IEW.
+ /** Time buffer interface. */
+ TimeBuffer<TimeStruct> *timeBuffer;
+
+ /** Wire to get commit's output from backwards time buffer. */
+ typename TimeBuffer<TimeStruct>::wire fromCommit;
+
+ /** Wire to write information heading to previous stages. */
+ typename TimeBuffer<TimeStruct>::wire toRename;
+
+ /** Rename instruction queue interface. */
+ TimeBuffer<RenameStruct> *renameQueue;
+
+ /** Wire to get rename's output from rename queue. */
+ typename TimeBuffer<RenameStruct>::wire fromRename;
+
+ /** Issue stage queue. */
+ TimeBuffer<IssueStruct> issueToExecQueue;
+
+ /** Wire to read information from the issue stage time queue. */
+ typename TimeBuffer<IssueStruct>::wire fromIssue;
+
+ /**
+ * IEW stage time buffer. Holds ROB indices of instructions that
+ * can be marked as completed.
+ */
+ TimeBuffer<IEWStruct> *iewQueue;
+
+ /** Wire to write infromation heading to commit. */
+ typename TimeBuffer<IEWStruct>::wire toCommit;
+
+ //Will need internal queue to hold onto instructions coming from
+ //the rename stage in case of a stall.
+ /** Skid buffer between rename and IEW. */
+ std::queue<RenameStruct> skidBuffer;
+
+ protected:
+ /** Instruction queue. */
+ IQ instQueue;
+
+ LDSTQ ldstQueue;
+
+#if !FULL_SYSTEM
+ public:
+ void lsqWriteback();
+#endif
+
+ private:
+ /** Pointer to rename map. Might not want this stage to directly
+ * access this though...
+ */
+ RenameMap *renameMap;
+
+ /** CPU interface. */
+ FullCPU *cpu;
+
+ private:
+ /** Commit to IEW delay, in ticks. */
+ unsigned commitToIEWDelay;
+
+ /** Rename to IEW delay, in ticks. */
+ unsigned renameToIEWDelay;
+
+ /**
+ * Issue to execute delay, in ticks. What this actually represents is
+ * the amount of time it takes for an instruction to wake up, be
+ * scheduled, and sent to a FU for execution.
+ */
+ unsigned issueToExecuteDelay;
+
+ /** Width of issue's read path, in instructions. The read path is both
+ * the skid buffer and the rename instruction queue.
+ * Note to self: is this really different than issueWidth?
+ */
+ unsigned issueReadWidth;
+
+ /** Width of issue, in instructions. */
+ unsigned issueWidth;
+
+ /** Width of execute, in instructions. Might make more sense to break
+ * down into FP vs int.
+ */
+ unsigned executeWidth;
+
+ /** Number of cycles stage has been squashing. Used so that the stage
+ * knows when it can start unblocking, which is when the previous stage
+ * has received the stall signal and clears up its outputs.
+ */
+ unsigned cyclesSquashing;
+
+ Stats::Scalar<> iewIdleCycles;
+ Stats::Scalar<> iewSquashCycles;
+ Stats::Scalar<> iewBlockCycles;
+ Stats::Scalar<> iewUnblockCycles;
+// Stats::Scalar<> iewWBInsts;
+ Stats::Scalar<> iewDispatchedInsts;
+ Stats::Scalar<> iewDispSquashedInsts;
+ Stats::Scalar<> iewDispLoadInsts;
+ Stats::Scalar<> iewDispStoreInsts;
+ Stats::Scalar<> iewDispNonSpecInsts;
+ Stats::Scalar<> iewIQFullEvents;
+ Stats::Scalar<> iewExecutedInsts;
+ Stats::Scalar<> iewExecLoadInsts;
+ Stats::Scalar<> iewExecStoreInsts;
+ Stats::Scalar<> iewExecSquashedInsts;
+ Stats::Scalar<> memOrderViolationEvents;
+ Stats::Scalar<> predictedTakenIncorrect;
+};
+
+#endif // __CPU_O3_CPU_IEW_HH__
diff --git a/src/cpu/o3/iew_impl.hh b/src/cpu/o3/iew_impl.hh
new file mode 100644
index 000000000..85217dd10
--- /dev/null
+++ b/src/cpu/o3/iew_impl.hh
@@ -0,0 +1,736 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// @todo: Fix the instantaneous communication among all the stages within
+// iew. There's a clear delay between issue and execute, yet backwards
+// communication happens simultaneously.
+// Update the statuses for each stage.
+
+#include <queue>
+
+#include "base/timebuf.hh"
+#include "cpu/o3/iew.hh"
+
+template<class Impl>
+SimpleIEW<Impl>::WritebackEvent::WritebackEvent(DynInstPtr &_inst,
+ SimpleIEW<Impl> *_iew)
+ : Event(&mainEventQueue, CPU_Tick_Pri), inst(_inst), iewStage(_iew)
+{
+ this->setFlags(Event::AutoDelete);
+}
+
+template<class Impl>
+void
+SimpleIEW<Impl>::WritebackEvent::process()
+{
+ DPRINTF(IEW, "IEW: WRITEBACK EVENT!!!!\n");
+
+ // Need to insert instruction into queue to commit
+ iewStage->instToCommit(inst);
+ // Need to execute second half of the instruction, do actual writing to
+ // registers and such
+ inst->execute();
+}
+
+template<class Impl>
+const char *
+SimpleIEW<Impl>::WritebackEvent::description()
+{
+ return "LSQ writeback event";
+}
+
+template<class Impl>
+SimpleIEW<Impl>::SimpleIEW(Params &params)
+ : // Just make this time buffer really big for now
+ issueToExecQueue(5, 5),
+ instQueue(params),
+ ldstQueue(params),
+ commitToIEWDelay(params.commitToIEWDelay),
+ renameToIEWDelay(params.renameToIEWDelay),
+ issueToExecuteDelay(params.issueToExecuteDelay),
+ issueReadWidth(params.issueWidth),
+ issueWidth(params.issueWidth),
+ executeWidth(params.executeWidth)
+{
+ DPRINTF(IEW, "IEW: executeIntWidth: %i.\n", params.executeIntWidth);
+ _status = Idle;
+ _issueStatus = Idle;
+ _exeStatus = Idle;
+ _wbStatus = Idle;
+
+ // Setup wire to read instructions coming from issue.
+ fromIssue = issueToExecQueue.getWire(-issueToExecuteDelay);
+
+ // Instruction queue needs the queue between issue and execute.
+ instQueue.setIssueToExecuteQueue(&issueToExecQueue);
+
+ ldstQueue.setIEW(this);
+}
+
+template <class Impl>
+void
+SimpleIEW<Impl>::regStats()
+{
+ instQueue.regStats();
+
+ iewIdleCycles
+ .name(name() + ".iewIdleCycles")
+ .desc("Number of cycles IEW is idle");
+
+ iewSquashCycles
+ .name(name() + ".iewSquashCycles")
+ .desc("Number of cycles IEW is squashing");
+
+ iewBlockCycles
+ .name(name() + ".iewBlockCycles")
+ .desc("Number of cycles IEW is blocking");
+
+ iewUnblockCycles
+ .name(name() + ".iewUnblockCycles")
+ .desc("Number of cycles IEW is unblocking");
+
+// iewWBInsts;
+
+ iewDispatchedInsts
+ .name(name() + ".iewDispatchedInsts")
+ .desc("Number of instructions dispatched to IQ");
+
+ iewDispSquashedInsts
+ .name(name() + ".iewDispSquashedInsts")
+ .desc("Number of squashed instructions skipped by dispatch");
+
+ iewDispLoadInsts
+ .name(name() + ".iewDispLoadInsts")
+ .desc("Number of dispatched load instructions");
+
+ iewDispStoreInsts
+ .name(name() + ".iewDispStoreInsts")
+ .desc("Number of dispatched store instructions");
+
+ iewDispNonSpecInsts
+ .name(name() + ".iewDispNonSpecInsts")
+ .desc("Number of dispatched non-speculative instructions");
+
+ iewIQFullEvents
+ .name(name() + ".iewIQFullEvents")
+ .desc("Number of times the IQ has become full, causing a stall");
+
+ iewExecutedInsts
+ .name(name() + ".iewExecutedInsts")
+ .desc("Number of executed instructions");
+
+ iewExecLoadInsts
+ .name(name() + ".iewExecLoadInsts")
+ .desc("Number of load instructions executed");
+
+ iewExecStoreInsts
+ .name(name() + ".iewExecStoreInsts")
+ .desc("Number of store instructions executed");
+
+ iewExecSquashedInsts
+ .name(name() + ".iewExecSquashedInsts")
+ .desc("Number of squashed instructions skipped in execute");
+
+ memOrderViolationEvents
+ .name(name() + ".memOrderViolationEvents")
+ .desc("Number of memory order violations");
+
+ predictedTakenIncorrect
+ .name(name() + ".predictedTakenIncorrect")
+ .desc("Number of branches that were predicted taken incorrectly");
+}
+
+template<class Impl>
+void
+SimpleIEW<Impl>::setCPU(FullCPU *cpu_ptr)
+{
+ DPRINTF(IEW, "IEW: Setting CPU pointer.\n");
+ cpu = cpu_ptr;
+
+ instQueue.setCPU(cpu_ptr);
+ ldstQueue.setCPU(cpu_ptr);
+}
+
+template<class Impl>
+void
+SimpleIEW<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
+{
+ DPRINTF(IEW, "IEW: Setting time buffer pointer.\n");
+ timeBuffer = tb_ptr;
+
+ // Setup wire to read information from time buffer, from commit.
+ fromCommit = timeBuffer->getWire(-commitToIEWDelay);
+
+ // Setup wire to write information back to previous stages.
+ toRename = timeBuffer->getWire(0);
+
+ // Instruction queue also needs main time buffer.
+ instQueue.setTimeBuffer(tb_ptr);
+}
+
+template<class Impl>
+void
+SimpleIEW<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr)
+{
+ DPRINTF(IEW, "IEW: Setting rename queue pointer.\n");
+ renameQueue = rq_ptr;
+
+ // Setup wire to read information from rename queue.
+ fromRename = renameQueue->getWire(-renameToIEWDelay);
+}
+
+template<class Impl>
+void
+SimpleIEW<Impl>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr)
+{
+ DPRINTF(IEW, "IEW: Setting IEW queue pointer.\n");
+ iewQueue = iq_ptr;
+
+ // Setup wire to write instructions to commit.
+ toCommit = iewQueue->getWire(0);
+}
+
+template<class Impl>
+void
+SimpleIEW<Impl>::setRenameMap(RenameMap *rm_ptr)
+{
+ DPRINTF(IEW, "IEW: Setting rename map pointer.\n");
+ renameMap = rm_ptr;
+}
+
+template<class Impl>
+void
+SimpleIEW<Impl>::squash()
+{
+ DPRINTF(IEW, "IEW: Squashing all instructions.\n");
+ _status = Squashing;
+
+ // Tell the IQ to start squashing.
+ instQueue.squash();
+
+ // Tell the LDSTQ to start squashing.
+ ldstQueue.squash(fromCommit->commitInfo.doneSeqNum);
+}
+
+template<class Impl>
+void
+SimpleIEW<Impl>::squashDueToBranch(DynInstPtr &inst)
+{
+ DPRINTF(IEW, "IEW: Squashing from a specific instruction, PC: %#x.\n",
+ inst->PC);
+ // Perhaps leave the squashing up to the ROB stage to tell it when to
+ // squash?
+ _status = Squashing;
+
+ // Tell rename to squash through the time buffer.
+ toCommit->squash = true;
+ // Also send PC update information back to prior stages.
+ toCommit->squashedSeqNum = inst->seqNum;
+ toCommit->mispredPC = inst->readPC();
+ toCommit->nextPC = inst->readNextPC();
+ toCommit->branchMispredict = true;
+ // Prediction was incorrect, so send back inverse.
+ toCommit->branchTaken = inst->readNextPC() !=
+ (inst->readPC() + sizeof(TheISA::MachInst));
+}
+
+template<class Impl>
+void
+SimpleIEW<Impl>::squashDueToMem(DynInstPtr &inst)
+{
+ DPRINTF(IEW, "IEW: Squashing from a specific instruction, PC: %#x.\n",
+ inst->PC);
+ // Perhaps leave the squashing up to the ROB stage to tell it when to
+ // squash?
+ _status = Squashing;
+
+ // Tell rename to squash through the time buffer.
+ toCommit->squash = true;
+ // Also send PC update information back to prior stages.
+ toCommit->squashedSeqNum = inst->seqNum;
+ toCommit->nextPC = inst->readNextPC();
+}
+
+template<class Impl>
+void
+SimpleIEW<Impl>::block()
+{
+ DPRINTF(IEW, "IEW: Blocking.\n");
+ // Set the status to Blocked.
+ _status = Blocked;
+
+ // Add the current inputs to the skid buffer so they can be
+ // reprocessed when this stage unblocks.
+ skidBuffer.push(*fromRename);
+
+ // Note that this stage only signals previous stages to stall when
+ // it is the cause of the stall originates at this stage. Otherwise
+ // the previous stages are expected to check all possible stall signals.
+}
+
+template<class Impl>
+inline void
+SimpleIEW<Impl>::unblock()
+{
+ // Check if there's information in the skid buffer. If there is, then
+ // set status to unblocking, otherwise set it directly to running.
+ DPRINTF(IEW, "IEW: Reading instructions out of the skid "
+ "buffer.\n");
+ // Remove the now processed instructions from the skid buffer.
+ skidBuffer.pop();
+
+ // If there's still information in the skid buffer, then
+ // continue to tell previous stages to stall. They will be
+ // able to restart once the skid buffer is empty.
+ if (!skidBuffer.empty()) {
+ toRename->iewInfo.stall = true;
+ } else {
+ DPRINTF(IEW, "IEW: Stage is done unblocking.\n");
+ _status = Running;
+ }
+}
+
+template<class Impl>
+void
+SimpleIEW<Impl>::wakeDependents(DynInstPtr &inst)
+{
+ instQueue.wakeDependents(inst);
+}
+
+
+template<class Impl>
+void
+SimpleIEW<Impl>::instToCommit(DynInstPtr &inst)
+{
+
+}
+
+template <class Impl>
+void
+SimpleIEW<Impl>::dispatchInsts()
+{
+ ////////////////////////////////////////
+ // DISPATCH/ISSUE stage
+ ////////////////////////////////////////
+
+ //Put into its own function?
+ //Add instructions to IQ if there are any instructions there
+
+ // Check if there are any instructions coming from rename, and we're.
+ // not squashing.
+ if (fromRename->size > 0) {
+ int insts_to_add = fromRename->size;
+
+ // Loop through the instructions, putting them in the instruction
+ // queue.
+ for (int inst_num = 0; inst_num < insts_to_add; ++inst_num)
+ {
+ DynInstPtr inst = fromRename->insts[inst_num];
+
+ // Make sure there's a valid instruction there.
+ assert(inst);
+
+ DPRINTF(IEW, "IEW: Issue: Adding PC %#x to IQ.\n",
+ inst->readPC());
+
+ // Be sure to mark these instructions as ready so that the
+ // commit stage can go ahead and execute them, and mark
+ // them as issued so the IQ doesn't reprocess them.
+ if (inst->isSquashed()) {
+ ++iewDispSquashedInsts;
+ continue;
+ } else if (instQueue.isFull()) {
+ DPRINTF(IEW, "IEW: Issue: IQ has become full.\n");
+ // Call function to start blocking.
+ block();
+ // Tell previous stage to stall.
+ toRename->iewInfo.stall = true;
+
+ ++iewIQFullEvents;
+ break;
+ } else if (inst->isLoad()) {
+ DPRINTF(IEW, "IEW: Issue: Memory instruction "
+ "encountered, adding to LDSTQ.\n");
+
+ // Reserve a spot in the load store queue for this
+ // memory access.
+ ldstQueue.insertLoad(inst);
+
+ ++iewDispLoadInsts;
+ } else if (inst->isStore()) {
+ ldstQueue.insertStore(inst);
+
+ ++iewDispStoreInsts;
+ } else if (inst->isNonSpeculative()) {
+ DPRINTF(IEW, "IEW: Issue: Nonspeculative instruction "
+ "encountered, skipping.\n");
+
+ // Same hack as with stores.
+ inst->setCanCommit();
+
+ // Specificall insert it as nonspeculative.
+ instQueue.insertNonSpec(inst);
+
+ ++iewDispNonSpecInsts;
+
+ continue;
+ } else if (inst->isNop()) {
+ DPRINTF(IEW, "IEW: Issue: Nop instruction encountered "
+ ", skipping.\n");
+
+ inst->setIssued();
+ inst->setExecuted();
+ inst->setCanCommit();
+
+ instQueue.advanceTail(inst);
+
+ continue;
+ } else if (inst->isExecuted()) {
+ assert(0 && "Instruction shouldn't be executed.\n");
+ DPRINTF(IEW, "IEW: Issue: Executed branch encountered, "
+ "skipping.\n");
+
+ inst->setIssued();
+ inst->setCanCommit();
+
+ instQueue.advanceTail(inst);
+
+ continue;
+ }
+
+ // If the instruction queue is not full, then add the
+ // instruction.
+ instQueue.insert(fromRename->insts[inst_num]);
+
+ ++iewDispatchedInsts;
+ }
+ }
+}
+
+template <class Impl>
+void
+SimpleIEW<Impl>::executeInsts()
+{
+ ////////////////////////////////////////
+ //EXECUTE/WRITEBACK stage
+ ////////////////////////////////////////
+
+ //Put into its own function?
+ //Similarly should probably have separate execution for int vs FP.
+ // Above comment is handled by the issue queue only issuing a valid
+ // mix of int/fp instructions.
+ //Actually okay to just have one execution, buuuuuut will need
+ //somewhere that defines the execution latency of all instructions.
+ // @todo: Move to the FU pool used in the current full cpu.
+
+ int fu_usage = 0;
+ bool fetch_redirect = false;
+ int inst_slot = 0;
+ int time_slot = 0;
+
+ // Execute/writeback any instructions that are available.
+ for (int inst_num = 0;
+ fu_usage < executeWidth && /* Haven't exceeded available FU's. */
+ inst_num < issueWidth &&
+ fromIssue->insts[inst_num];
+ ++inst_num) {
+
+ DPRINTF(IEW, "IEW: Execute: Executing instructions from IQ.\n");
+
+ // Get instruction from issue's queue.
+ DynInstPtr inst = fromIssue->insts[inst_num];
+
+ DPRINTF(IEW, "IEW: Execute: Processing PC %#x.\n", inst->readPC());
+
+ // Check if the instruction is squashed; if so then skip it
+ // and don't count it towards the FU usage.
+ if (inst->isSquashed()) {
+ DPRINTF(IEW, "IEW: Execute: Instruction was squashed.\n");
+
+ // Consider this instruction executed so that commit can go
+ // ahead and retire the instruction.
+ inst->setExecuted();
+
+ toCommit->insts[inst_num] = inst;
+
+ ++iewExecSquashedInsts;
+
+ continue;
+ }
+
+ inst->setExecuted();
+
+ // If an instruction is executed, then count it towards FU usage.
+ ++fu_usage;
+
+ // Execute instruction.
+ // Note that if the instruction faults, it will be handled
+ // at the commit stage.
+ if (inst->isMemRef()) {
+ DPRINTF(IEW, "IEW: Execute: Calculating address for memory "
+ "reference.\n");
+
+ // Tell the LDSTQ to execute this instruction (if it is a load).
+ if (inst->isLoad()) {
+ ldstQueue.executeLoad(inst);
+
+ ++iewExecLoadInsts;
+ } else if (inst->isStore()) {
+ ldstQueue.executeStore(inst);
+
+ ++iewExecStoreInsts;
+ } else {
+ panic("IEW: Unexpected memory type!\n");
+ }
+
+ } else {
+ inst->execute();
+
+ ++iewExecutedInsts;
+ }
+
+ // First check the time slot that this instruction will write
+ // to. If there are free write ports at the time, then go ahead
+ // and write the instruction to that time. If there are not,
+ // keep looking back to see where's the first time there's a
+ // free slot. What happens if you run out of free spaces?
+ // For now naively assume that all instructions take one cycle.
+ // Otherwise would have to look into the time buffer based on the
+ // latency of the instruction.
+ (*iewQueue)[time_slot].insts[inst_slot];
+ while ((*iewQueue)[time_slot].insts[inst_slot]) {
+ if (inst_slot < issueWidth) {
+ ++inst_slot;
+ } else {
+ ++time_slot;
+ inst_slot = 0;
+ }
+
+ assert(time_slot < 5);
+ }
+
+ // May actually have to work this out, especially with loads and stores
+
+ // Add finished instruction to queue to commit.
+ (*iewQueue)[time_slot].insts[inst_slot] = inst;
+ (*iewQueue)[time_slot].size++;
+
+ // Check if branch was correct. This check happens after the
+ // instruction is added to the queue because even if the branch
+ // is mispredicted, the branch instruction itself is still valid.
+ // Only handle this if there hasn't already been something that
+ // redirects fetch in this group of instructions.
+ if (!fetch_redirect) {
+ if (inst->mispredicted()) {
+ fetch_redirect = true;
+
+ DPRINTF(IEW, "IEW: Execute: Branch mispredict detected.\n");
+ DPRINTF(IEW, "IEW: Execute: Redirecting fetch to PC: %#x.\n",
+ inst->nextPC);
+
+ // If incorrect, then signal the ROB that it must be squashed.
+ squashDueToBranch(inst);
+
+ if (inst->predTaken()) {
+ predictedTakenIncorrect++;
+ }
+ } else if (ldstQueue.violation()) {
+ fetch_redirect = true;
+
+ // Get the DynInst that caused the violation.
+ DynInstPtr violator = ldstQueue.getMemDepViolator();
+
+ DPRINTF(IEW, "IEW: LDSTQ detected a violation. Violator PC: "
+ "%#x, inst PC: %#x. Addr is: %#x.\n",
+ violator->readPC(), inst->readPC(), inst->physEffAddr);
+
+ // Tell the instruction queue that a violation has occured.
+ instQueue.violation(inst, violator);
+
+ // Squash.
+ squashDueToMem(inst);
+
+ ++memOrderViolationEvents;
+ }
+ }
+ }
+}
+
+template<class Impl>
+void
+SimpleIEW<Impl>::tick()
+{
+ // Considering putting all the state-determining stuff in this section.
+
+ // Try to fill up issue queue with as many instructions as bandwidth
+ // allows.
+ // Decode should try to execute as many instructions as its bandwidth
+ // will allow, as long as it is not currently blocked.
+
+ // Check if the stage is in a running status.
+ if (_status != Blocked && _status != Squashing) {
+ DPRINTF(IEW, "IEW: Status is not blocked, attempting to run "
+ "stage.\n");
+ iew();
+
+ // If it's currently unblocking, check to see if it should switch
+ // to running.
+ if (_status == Unblocking) {
+ unblock();
+
+ ++iewUnblockCycles;
+ }
+ } else if (_status == Squashing) {
+
+ DPRINTF(IEW, "IEW: Still squashing.\n");
+
+ // Check if stage should remain squashing. Stop squashing if the
+ // squash signal clears.
+ if (!fromCommit->commitInfo.squash &&
+ !fromCommit->commitInfo.robSquashing) {
+ DPRINTF(IEW, "IEW: Done squashing, changing status to "
+ "running.\n");
+
+ _status = Running;
+ instQueue.stopSquash();
+ } else {
+ instQueue.doSquash();
+ }
+
+ ++iewSquashCycles;
+ } else if (_status == Blocked) {
+ // Continue to tell previous stage to stall.
+ toRename->iewInfo.stall = true;
+
+ // Check if possible stall conditions have cleared.
+ if (!fromCommit->commitInfo.stall &&
+ !instQueue.isFull()) {
+ DPRINTF(IEW, "IEW: Stall signals cleared, going to unblock.\n");
+ _status = Unblocking;
+ }
+
+ // If there's still instructions coming from rename, continue to
+ // put them on the skid buffer.
+ if (fromRename->size == 0) {
+ block();
+ }
+
+ if (fromCommit->commitInfo.squash ||
+ fromCommit->commitInfo.robSquashing) {
+ squash();
+ }
+
+ ++iewBlockCycles;
+ }
+
+ // @todo: Maybe put these at the beginning, so if it's idle it can
+ // return early.
+ // Write back number of free IQ entries here.
+ toRename->iewInfo.freeIQEntries = instQueue.numFreeEntries();
+
+ ldstQueue.writebackStores();
+
+ // Check the committed load/store signals to see if there's a load
+ // or store to commit. Also check if it's being told to execute a
+ // nonspeculative instruction.
+ // This is pretty inefficient...
+ if (!fromCommit->commitInfo.squash &&
+ !fromCommit->commitInfo.robSquashing) {
+ ldstQueue.commitStores(fromCommit->commitInfo.doneSeqNum);
+ ldstQueue.commitLoads(fromCommit->commitInfo.doneSeqNum);
+ }
+
+ if (fromCommit->commitInfo.nonSpecSeqNum != 0) {
+ instQueue.scheduleNonSpec(fromCommit->commitInfo.nonSpecSeqNum);
+ }
+
+ DPRINTF(IEW, "IEW: IQ has %i free entries.\n",
+ instQueue.numFreeEntries());
+}
+
+template<class Impl>
+void
+SimpleIEW<Impl>::iew()
+{
+ // Might want to put all state checks in the tick() function.
+ // Check if being told to stall from commit.
+ if (fromCommit->commitInfo.stall) {
+ block();
+ return;
+ } else if (fromCommit->commitInfo.squash ||
+ fromCommit->commitInfo.robSquashing) {
+ // Also check if commit is telling this stage to squash.
+ squash();
+ return;
+ }
+
+ dispatchInsts();
+
+ // Have the instruction queue try to schedule any ready instructions.
+ instQueue.scheduleReadyInsts();
+
+ executeInsts();
+
+ // Loop through the head of the time buffer and wake any dependents.
+ // These instructions are about to write back. In the simple model
+ // this loop can really happen within the previous loop, but when
+ // instructions have actual latencies, this loop must be separate.
+ // Also mark scoreboard that this instruction is finally complete.
+ // Either have IEW have direct access to rename map, or have this as
+ // part of backwards communication.
+ for (int inst_num = 0; inst_num < issueWidth &&
+ toCommit->insts[inst_num]; inst_num++)
+ {
+ DynInstPtr inst = toCommit->insts[inst_num];
+
+ DPRINTF(IEW, "IEW: Sending instructions to commit, PC %#x.\n",
+ inst->readPC());
+
+ if(!inst->isSquashed()) {
+ instQueue.wakeDependents(inst);
+
+ for (int i = 0; i < inst->numDestRegs(); i++)
+ {
+ renameMap->markAsReady(inst->renamedDestRegIdx(i));
+ }
+ }
+ }
+
+ // Also should advance its own time buffers if the stage ran.
+ // Not the best place for it, but this works (hopefully).
+ issueToExecQueue.advance();
+}
+
+#if !FULL_SYSTEM
+template<class Impl>
+void
+SimpleIEW<Impl>::lsqWriteback()
+{
+ ldstQueue.writebackAllInsts();
+}
+#endif
diff --git a/src/cpu/o3/inst_queue.cc b/src/cpu/o3/inst_queue.cc
new file mode 100644
index 000000000..2ff2282b4
--- /dev/null
+++ b/src/cpu/o3/inst_queue.cc
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "cpu/o3/alpha_dyn_inst.hh"
+#include "cpu/o3/alpha_impl.hh"
+#include "cpu/o3/inst_queue_impl.hh"
+
+// Force instantiation of InstructionQueue.
+template class InstructionQueue<AlphaSimpleImpl>;
+
+template<>
+unsigned
+InstructionQueue<AlphaSimpleImpl>::DependencyEntry::mem_alloc_counter = 0;
diff --git a/src/cpu/o3/inst_queue.hh b/src/cpu/o3/inst_queue.hh
new file mode 100644
index 000000000..43fe96c49
--- /dev/null
+++ b/src/cpu/o3/inst_queue.hh
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPU_O3_CPU_INST_QUEUE_HH__
+#define __CPU_O3_CPU_INST_QUEUE_HH__
+
+#include <list>
+#include <map>
+#include <queue>
+#include <vector>
+
+#include "base/statistics.hh"
+#include "base/timebuf.hh"
+#include "cpu/inst_seq.hh"
+#include "sim/host.hh"
+
+/**
+ * A standard instruction queue class. It holds ready instructions, in
+ * order, in seperate priority queues to facilitate the scheduling of
+ * instructions. The IQ uses a separate linked list to track dependencies.
+ * Similar to the rename map and the free list, it expects that
+ * floating point registers have their indices start after the integer
+ * registers (ie with 96 int and 96 fp registers, regs 0-95 are integer
+ * and 96-191 are fp). This remains true even for both logical and
+ * physical register indices.
+ */
+template <class Impl>
+class InstructionQueue
+{
+ public:
+ //Typedefs from the Impl.
+ typedef typename Impl::FullCPU FullCPU;
+ typedef typename Impl::DynInstPtr DynInstPtr;
+ typedef typename Impl::Params Params;
+
+ typedef typename Impl::CPUPol::MemDepUnit MemDepUnit;
+ typedef typename Impl::CPUPol::IssueStruct IssueStruct;
+ typedef typename Impl::CPUPol::TimeStruct TimeStruct;
+
+ // Typedef of iterator through the list of instructions. Might be
+ // better to untie this from the FullCPU or pass its information to
+ // the stages.
+ typedef typename std::list<DynInstPtr>::iterator ListIt;
+
+ /**
+ * Struct for comparing entries to be added to the priority queue. This
+ * gives reverse ordering to the instructions in terms of sequence
+ * numbers: the instructions with smaller sequence numbers (and hence
+ * are older) will be at the top of the priority queue.
+ */
+ struct pqCompare
+ {
+ bool operator() (const DynInstPtr &lhs, const DynInstPtr &rhs) const
+ {
+ return lhs->seqNum > rhs->seqNum;
+ }
+ };
+
+ /**
+ * Struct for comparing entries to be added to the set. This gives
+ * standard ordering in terms of sequence numbers.
+ */
+ struct setCompare
+ {
+ bool operator() (const DynInstPtr &lhs, const DynInstPtr &rhs) const
+ {
+ return lhs->seqNum < rhs->seqNum;
+ }
+ };
+
+ typedef std::priority_queue<DynInstPtr, vector<DynInstPtr>, pqCompare>
+ ReadyInstQueue;
+
+ InstructionQueue(Params &params);
+
+ void regStats();
+
+ void setCPU(FullCPU *cpu);
+
+ void setIssueToExecuteQueue(TimeBuffer<IssueStruct> *i2eQueue);
+
+ void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr);
+
+ unsigned numFreeEntries();
+
+ bool isFull();
+
+ void insert(DynInstPtr &new_inst);
+
+ void insertNonSpec(DynInstPtr &new_inst);
+
+ void advanceTail(DynInstPtr &inst);
+
+ void scheduleReadyInsts();
+
+ void scheduleNonSpec(const InstSeqNum &inst);
+
+ void wakeDependents(DynInstPtr &completed_inst);
+
+ void violation(DynInstPtr &store, DynInstPtr &faulting_load);
+
+ // Change this to take in the sequence number
+ void squash();
+
+ void doSquash();
+
+ void stopSquash();
+
+ private:
+ /** Pointer to the CPU. */
+ FullCPU *cpu;
+
+ /** The memory dependence unit, which tracks/predicts memory dependences
+ * between instructions.
+ */
+ MemDepUnit memDepUnit;
+
+ /** The queue to the execute stage. Issued instructions will be written
+ * into it.
+ */
+ TimeBuffer<IssueStruct> *issueToExecuteQueue;
+
+ /** The backwards time buffer. */
+ TimeBuffer<TimeStruct> *timeBuffer;
+
+ /** Wire to read information from timebuffer. */
+ typename TimeBuffer<TimeStruct>::wire fromCommit;
+
+ enum InstList {
+ Int,
+ Float,
+ Branch,
+ Memory,
+ Misc,
+ Squashed,
+ None
+ };
+
+ /** List of ready int instructions. Used to keep track of the order in
+ * which instructions should issue.
+ */
+ ReadyInstQueue readyIntInsts;
+
+ /** List of ready floating point instructions. */
+ ReadyInstQueue readyFloatInsts;
+
+ /** List of ready branch instructions. */
+ ReadyInstQueue readyBranchInsts;
+
+ /** List of ready miscellaneous instructions. */
+ ReadyInstQueue readyMiscInsts;
+
+ /** List of squashed instructions (which are still valid and in IQ).
+ * Implemented using a priority queue; the entries must contain both
+ * the IQ index and sequence number of each instruction so that
+ * ordering based on sequence numbers can be used.
+ */
+ ReadyInstQueue squashedInsts;
+
+ /** List of non-speculative instructions that will be scheduled
+ * once the IQ gets a signal from commit. While it's redundant to
+ * have the key be a part of the value (the sequence number is stored
+ * inside of DynInst), when these instructions are woken up only
+ * the sequence number will be available. Thus it is most efficient to be
+ * able to search by the sequence number alone.
+ */
+ std::map<InstSeqNum, DynInstPtr> nonSpecInsts;
+
+ typedef typename std::map<InstSeqNum, DynInstPtr>::iterator non_spec_it_t;
+
+ /** Number of free IQ entries left. */
+ unsigned freeEntries;
+
+ /** The number of entries in the instruction queue. */
+ unsigned numEntries;
+
+ /** The number of integer instructions that can be issued in one
+ * cycle.
+ */
+ unsigned intWidth;
+
+ /** The number of floating point instructions that can be issued
+ * in one cycle.
+ */
+ unsigned floatWidth;
+
+ /** The number of branches that can be issued in one cycle. */
+ unsigned branchWidth;
+
+ /** The number of memory instructions that can be issued in one cycle. */
+ unsigned memoryWidth;
+
+ /** The total number of instructions that can be issued in one cycle. */
+ unsigned totalWidth;
+
+ //The number of physical registers in the CPU.
+ unsigned numPhysRegs;
+
+ /** The number of physical integer registers in the CPU. */
+ unsigned numPhysIntRegs;
+
+ /** The number of floating point registers in the CPU. */
+ unsigned numPhysFloatRegs;
+
+ /** Delay between commit stage and the IQ.
+ * @todo: Make there be a distinction between the delays within IEW.
+ */
+ unsigned commitToIEWDelay;
+
+ //////////////////////////////////
+ // Variables needed for squashing
+ //////////////////////////////////
+
+ /** The sequence number of the squashed instruction. */
+ InstSeqNum squashedSeqNum;
+
+ /** Iterator that points to the youngest instruction in the IQ. */
+ ListIt tail;
+
+ /** Iterator that points to the last instruction that has been squashed.
+ * This will not be valid unless the IQ is in the process of squashing.
+ */
+ ListIt squashIt;
+
+ ///////////////////////////////////
+ // Dependency graph stuff
+ ///////////////////////////////////
+
+ class DependencyEntry
+ {
+ public:
+ DynInstPtr inst;
+ //Might want to include data about what arch. register the
+ //dependence is waiting on.
+ DependencyEntry *next;
+
+ //This function, and perhaps this whole class, stand out a little
+ //bit as they don't fit a classification well. I want access
+ //to the underlying structure of the linked list, yet at
+ //the same time it feels like this should be something abstracted
+ //away. So for now it will sit here, within the IQ, until
+ //a better implementation is decided upon.
+ // This function probably shouldn't be within the entry...
+ void insert(DynInstPtr &new_inst);
+
+ void remove(DynInstPtr &inst_to_remove);
+
+ // Debug variable, remove when done testing.
+ static unsigned mem_alloc_counter;
+ };
+
+ /** Array of linked lists. Each linked list is a list of all the
+ * instructions that depend upon a given register. The actual
+ * register's index is used to index into the graph; ie all
+ * instructions in flight that are dependent upon r34 will be
+ * in the linked list of dependGraph[34].
+ */
+ DependencyEntry *dependGraph;
+
+ /** A cache of the recently woken registers. It is 1 if the register
+ * has been woken up recently, and 0 if the register has been added
+ * to the dependency graph and has not yet received its value. It
+ * is basically a secondary scoreboard, and should pretty much mirror
+ * the scoreboard that exists in the rename map.
+ */
+ vector<bool> regScoreboard;
+
+ bool addToDependents(DynInstPtr &new_inst);
+ void insertDependency(DynInstPtr &new_inst);
+ void createDependency(DynInstPtr &new_inst);
+
+ void addIfReady(DynInstPtr &inst);
+
+ private:
+ /** Debugging function to count how many entries are in the IQ. It does
+ * a linear walk through the instructions, so do not call this function
+ * during normal execution.
+ */
+ int countInsts();
+
+ /** Debugging function to dump out the dependency graph.
+ */
+ void dumpDependGraph();
+
+ /** Debugging function to dump all the list sizes, as well as print
+ * out the list of nonspeculative instructions. Should not be used
+ * in any other capacity, but it has no harmful sideaffects.
+ */
+ void dumpLists();
+
+ Stats::Scalar<> iqInstsAdded;
+ Stats::Scalar<> iqNonSpecInstsAdded;
+// Stats::Scalar<> iqIntInstsAdded;
+ Stats::Scalar<> iqIntInstsIssued;
+// Stats::Scalar<> iqFloatInstsAdded;
+ Stats::Scalar<> iqFloatInstsIssued;
+// Stats::Scalar<> iqBranchInstsAdded;
+ Stats::Scalar<> iqBranchInstsIssued;
+// Stats::Scalar<> iqMemInstsAdded;
+ Stats::Scalar<> iqMemInstsIssued;
+// Stats::Scalar<> iqMiscInstsAdded;
+ Stats::Scalar<> iqMiscInstsIssued;
+ Stats::Scalar<> iqSquashedInstsIssued;
+ Stats::Scalar<> iqLoopSquashStalls;
+ Stats::Scalar<> iqSquashedInstsExamined;
+ Stats::Scalar<> iqSquashedOperandsExamined;
+ Stats::Scalar<> iqSquashedNonSpecRemoved;
+
+};
+
+#endif //__CPU_O3_CPU_INST_QUEUE_HH__
diff --git a/src/cpu/o3/inst_queue_impl.hh b/src/cpu/o3/inst_queue_impl.hh
new file mode 100644
index 000000000..048dc7c00
--- /dev/null
+++ b/src/cpu/o3/inst_queue_impl.hh
@@ -0,0 +1,1136 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Todo:
+// Current ordering allows for 0 cycle added-to-scheduled. Could maybe fake
+// it; either do in reverse order, or have added instructions put into a
+// different ready queue that, in scheduleRreadyInsts(), gets put onto the
+// normal ready queue. This would however give only a one cycle delay,
+// but probably is more flexible to actually add in a delay parameter than
+// just running it backwards.
+
+#include <limits>
+#include <vector>
+
+#include "sim/root.hh"
+
+#include "cpu/o3/inst_queue.hh"
+
+// Either compile error or max int due to sign extension.
+// Hack to avoid compile warnings.
+const InstSeqNum MaxInstSeqNum = std::numeric_limits<InstSeqNum>::max();
+
+template <class Impl>
+InstructionQueue<Impl>::InstructionQueue(Params &params)
+ : memDepUnit(params),
+ numEntries(params.numIQEntries),
+ intWidth(params.executeIntWidth),
+ floatWidth(params.executeFloatWidth),
+ branchWidth(params.executeBranchWidth),
+ memoryWidth(params.executeMemoryWidth),
+ totalWidth(params.issueWidth),
+ numPhysIntRegs(params.numPhysIntRegs),
+ numPhysFloatRegs(params.numPhysFloatRegs),
+ commitToIEWDelay(params.commitToIEWDelay)
+{
+ // Initialize the number of free IQ entries.
+ freeEntries = numEntries;
+
+ // Set the number of physical registers as the number of int + float
+ numPhysRegs = numPhysIntRegs + numPhysFloatRegs;
+
+ DPRINTF(IQ, "IQ: There are %i physical registers.\n", numPhysRegs);
+
+ //Create an entry for each physical register within the
+ //dependency graph.
+ dependGraph = new DependencyEntry[numPhysRegs];
+
+ // Resize the register scoreboard.
+ regScoreboard.resize(numPhysRegs);
+
+ // Initialize all the head pointers to point to NULL, and all the
+ // entries as unready.
+ // Note that in actuality, the registers corresponding to the logical
+ // registers start off as ready. However this doesn't matter for the
+ // IQ as the instruction should have been correctly told if those
+ // registers are ready in rename. Thus it can all be initialized as
+ // unready.
+ for (int i = 0; i < numPhysRegs; ++i)
+ {
+ dependGraph[i].next = NULL;
+ dependGraph[i].inst = NULL;
+ regScoreboard[i] = false;
+ }
+
+}
+
+template <class Impl>
+void
+InstructionQueue<Impl>::regStats()
+{
+ iqInstsAdded
+ .name(name() + ".iqInstsAdded")
+ .desc("Number of instructions added to the IQ (excludes non-spec)")
+ .prereq(iqInstsAdded);
+
+ iqNonSpecInstsAdded
+ .name(name() + ".iqNonSpecInstsAdded")
+ .desc("Number of non-speculative instructions added to the IQ")
+ .prereq(iqNonSpecInstsAdded);
+
+// iqIntInstsAdded;
+
+ iqIntInstsIssued
+ .name(name() + ".iqIntInstsIssued")
+ .desc("Number of integer instructions issued")
+ .prereq(iqIntInstsIssued);
+
+// iqFloatInstsAdded;
+
+ iqFloatInstsIssued
+ .name(name() + ".iqFloatInstsIssued")
+ .desc("Number of float instructions issued")
+ .prereq(iqFloatInstsIssued);
+
+// iqBranchInstsAdded;
+
+ iqBranchInstsIssued
+ .name(name() + ".iqBranchInstsIssued")
+ .desc("Number of branch instructions issued")
+ .prereq(iqBranchInstsIssued);
+
+// iqMemInstsAdded;
+
+ iqMemInstsIssued
+ .name(name() + ".iqMemInstsIssued")
+ .desc("Number of memory instructions issued")
+ .prereq(iqMemInstsIssued);
+
+// iqMiscInstsAdded;
+
+ iqMiscInstsIssued
+ .name(name() + ".iqMiscInstsIssued")
+ .desc("Number of miscellaneous instructions issued")
+ .prereq(iqMiscInstsIssued);
+
+ iqSquashedInstsIssued
+ .name(name() + ".iqSquashedInstsIssued")
+ .desc("Number of squashed instructions issued")
+ .prereq(iqSquashedInstsIssued);
+
+ iqLoopSquashStalls
+ .name(name() + ".iqLoopSquashStalls")
+ .desc("Number of times issue loop had to restart due to squashed "
+ "inst; mainly for profiling")
+ .prereq(iqLoopSquashStalls);
+
+ iqSquashedInstsExamined
+ .name(name() + ".iqSquashedInstsExamined")
+ .desc("Number of squashed instructions iterated over during squash;"
+ " mainly for profiling")
+ .prereq(iqSquashedInstsExamined);
+
+ iqSquashedOperandsExamined
+ .name(name() + ".iqSquashedOperandsExamined")
+ .desc("Number of squashed operands that are examined and possibly "
+ "removed from graph")
+ .prereq(iqSquashedOperandsExamined);
+
+ iqSquashedNonSpecRemoved
+ .name(name() + ".iqSquashedNonSpecRemoved")
+ .desc("Number of squashed non-spec instructions that were removed")
+ .prereq(iqSquashedNonSpecRemoved);
+
+ // Tell mem dependence unit to reg stats as well.
+ memDepUnit.regStats();
+}
+
+template <class Impl>
+void
+InstructionQueue<Impl>::setCPU(FullCPU *cpu_ptr)
+{
+ cpu = cpu_ptr;
+
+ tail = cpu->instList.begin();
+}
+
+template <class Impl>
+void
+InstructionQueue<Impl>::setIssueToExecuteQueue(
+ TimeBuffer<IssueStruct> *i2e_ptr)
+{
+ DPRINTF(IQ, "IQ: Set the issue to execute queue.\n");
+ issueToExecuteQueue = i2e_ptr;
+}
+
+template <class Impl>
+void
+InstructionQueue<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
+{
+ DPRINTF(IQ, "IQ: Set the time buffer.\n");
+ timeBuffer = tb_ptr;
+
+ fromCommit = timeBuffer->getWire(-commitToIEWDelay);
+}
+
+template <class Impl>
+unsigned
+InstructionQueue<Impl>::numFreeEntries()
+{
+ return freeEntries;
+}
+
+// Might want to do something more complex if it knows how many instructions
+// will be issued this cycle.
+template <class Impl>
+bool
+InstructionQueue<Impl>::isFull()
+{
+ if (freeEntries == 0) {
+ return(true);
+ } else {
+ return(false);
+ }
+}
+
+template <class Impl>
+void
+InstructionQueue<Impl>::insert(DynInstPtr &new_inst)
+{
+ // Make sure the instruction is valid
+ assert(new_inst);
+
+ DPRINTF(IQ, "IQ: Adding instruction PC %#x to the IQ.\n",
+ new_inst->readPC());
+
+ // Check if there are any free entries. Panic if there are none.
+ // Might want to have this return a fault in the future instead of
+ // panicing.
+ assert(freeEntries != 0);
+
+ // If the IQ currently has nothing in it, then there's a possibility
+ // that the tail iterator is invalid (might have been pointing at an
+ // instruction that was retired). Reset the tail iterator.
+ if (freeEntries == numEntries) {
+ tail = cpu->instList.begin();
+ }
+
+ // Move the tail iterator. Instructions may not have been issued
+ // to the IQ, so we may have to increment the iterator more than once.
+ while ((*tail) != new_inst) {
+ tail++;
+
+ // Make sure the tail iterator points at something legal.
+ assert(tail != cpu->instList.end());
+ }
+
+
+ // Decrease the number of free entries.
+ --freeEntries;
+
+ // Look through its source registers (physical regs), and mark any
+ // dependencies.
+ addToDependents(new_inst);
+
+ // Have this instruction set itself as the producer of its destination
+ // register(s).
+ createDependency(new_inst);
+
+ // If it's a memory instruction, add it to the memory dependency
+ // unit.
+ if (new_inst->isMemRef()) {
+ memDepUnit.insert(new_inst);
+ // Uh..forgot to look it up and put it on the proper dependency list
+ // if the instruction should not go yet.
+ } else {
+ // If the instruction is ready then add it to the ready list.
+ addIfReady(new_inst);
+ }
+
+ ++iqInstsAdded;
+
+ assert(freeEntries == (numEntries - countInsts()));
+}
+
+template <class Impl>
+void
+InstructionQueue<Impl>::insertNonSpec(DynInstPtr &inst)
+{
+ nonSpecInsts[inst->seqNum] = inst;
+
+ // @todo: Clean up this code; can do it by setting inst as unable
+ // to issue, then calling normal insert on the inst.
+
+ // Make sure the instruction is valid
+ assert(inst);
+
+ DPRINTF(IQ, "IQ: Adding instruction PC %#x to the IQ.\n",
+ inst->readPC());
+
+ // Check if there are any free entries. Panic if there are none.
+ // Might want to have this return a fault in the future instead of
+ // panicing.
+ assert(freeEntries != 0);
+
+ // If the IQ currently has nothing in it, then there's a possibility
+ // that the tail iterator is invalid (might have been pointing at an
+ // instruction that was retired). Reset the tail iterator.
+ if (freeEntries == numEntries) {
+ tail = cpu->instList.begin();
+ }
+
+ // Move the tail iterator. Instructions may not have been issued
+ // to the IQ, so we may have to increment the iterator more than once.
+ while ((*tail) != inst) {
+ tail++;
+
+ // Make sure the tail iterator points at something legal.
+ assert(tail != cpu->instList.end());
+ }
+
+ // Decrease the number of free entries.
+ --freeEntries;
+
+ // Have this instruction set itself as the producer of its destination
+ // register(s).
+ createDependency(inst);
+
+ // If it's a memory instruction, add it to the memory dependency
+ // unit.
+ if (inst->isMemRef()) {
+ memDepUnit.insertNonSpec(inst);
+ }
+
+ ++iqNonSpecInstsAdded;
+}
+
+// Slightly hack function to advance the tail iterator in the case that
+// the IEW stage issues an instruction that is not added to the IQ. This
+// is needed in case a long chain of such instructions occurs.
+// I don't think this is used anymore.
+template <class Impl>
+void
+InstructionQueue<Impl>::advanceTail(DynInstPtr &inst)
+{
+ // Make sure the instruction is valid
+ assert(inst);
+
+ DPRINTF(IQ, "IQ: Adding instruction PC %#x to the IQ.\n",
+ inst->readPC());
+
+ // Check if there are any free entries. Panic if there are none.
+ // Might want to have this return a fault in the future instead of
+ // panicing.
+ assert(freeEntries != 0);
+
+ // If the IQ currently has nothing in it, then there's a possibility
+ // that the tail iterator is invalid (might have been pointing at an
+ // instruction that was retired). Reset the tail iterator.
+ if (freeEntries == numEntries) {
+ tail = cpu->instList.begin();
+ }
+
+ // Move the tail iterator. Instructions may not have been issued
+ // to the IQ, so we may have to increment the iterator more than once.
+ while ((*tail) != inst) {
+ tail++;
+
+ // Make sure the tail iterator points at something legal.
+ assert(tail != cpu->instList.end());
+ }
+
+ assert(freeEntries <= numEntries);
+
+ // Have this instruction set itself as the producer of its destination
+ // register(s).
+ createDependency(inst);
+}
+
+// Need to make sure the number of float and integer instructions
+// issued does not exceed the total issue bandwidth.
+// @todo: Figure out a better way to remove the squashed items from the
+// lists. Checking the top item of each list to see if it's squashed
+// wastes time and forces jumps.
+template <class Impl>
+void
+InstructionQueue<Impl>::scheduleReadyInsts()
+{
+ DPRINTF(IQ, "IQ: Attempting to schedule ready instructions from "
+ "the IQ.\n");
+
+ int int_issued = 0;
+ int float_issued = 0;
+ int branch_issued = 0;
+ int memory_issued = 0;
+ int squashed_issued = 0;
+ int total_issued = 0;
+
+ IssueStruct *i2e_info = issueToExecuteQueue->access(0);
+
+ bool insts_available = !readyBranchInsts.empty() ||
+ !readyIntInsts.empty() ||
+ !readyFloatInsts.empty() ||
+ !memDepUnit.empty() ||
+ !readyMiscInsts.empty() ||
+ !squashedInsts.empty();
+
+ // Note: Requires a globally defined constant.
+ InstSeqNum oldest_inst = MaxInstSeqNum;
+ InstList list_with_oldest = None;
+
+ // Temporary values.
+ DynInstPtr int_head_inst;
+ DynInstPtr float_head_inst;
+ DynInstPtr branch_head_inst;
+ DynInstPtr mem_head_inst;
+ DynInstPtr misc_head_inst;
+ DynInstPtr squashed_head_inst;
+
+ // Somewhat nasty code to look at all of the lists where issuable
+ // instructions are located, and choose the oldest instruction among
+ // those lists. Consider a rewrite in the future.
+ while (insts_available && total_issued < totalWidth)
+ {
+ // Set this to false. Each if-block is required to set it to true
+ // if there were instructions available this check. This will cause
+ // this loop to run once more than necessary, but avoids extra calls.
+ insts_available = false;
+
+ oldest_inst = MaxInstSeqNum;
+
+ list_with_oldest = None;
+
+ if (!readyIntInsts.empty() &&
+ int_issued < intWidth) {
+
+ insts_available = true;
+
+ int_head_inst = readyIntInsts.top();
+
+ if (int_head_inst->isSquashed()) {
+ readyIntInsts.pop();
+
+ ++iqLoopSquashStalls;
+
+ continue;
+ }
+
+ oldest_inst = int_head_inst->seqNum;
+
+ list_with_oldest = Int;
+ }
+
+ if (!readyFloatInsts.empty() &&
+ float_issued < floatWidth) {
+
+ insts_available = true;
+
+ float_head_inst = readyFloatInsts.top();
+
+ if (float_head_inst->isSquashed()) {
+ readyFloatInsts.pop();
+
+ ++iqLoopSquashStalls;
+
+ continue;
+ } else if (float_head_inst->seqNum < oldest_inst) {
+ oldest_inst = float_head_inst->seqNum;
+
+ list_with_oldest = Float;
+ }
+ }
+
+ if (!readyBranchInsts.empty() &&
+ branch_issued < branchWidth) {
+
+ insts_available = true;
+
+ branch_head_inst = readyBranchInsts.top();
+
+ if (branch_head_inst->isSquashed()) {
+ readyBranchInsts.pop();
+
+ ++iqLoopSquashStalls;
+
+ continue;
+ } else if (branch_head_inst->seqNum < oldest_inst) {
+ oldest_inst = branch_head_inst->seqNum;
+
+ list_with_oldest = Branch;
+ }
+
+ }
+
+ if (!memDepUnit.empty() &&
+ memory_issued < memoryWidth) {
+
+ insts_available = true;
+
+ mem_head_inst = memDepUnit.top();
+
+ if (mem_head_inst->isSquashed()) {
+ memDepUnit.pop();
+
+ ++iqLoopSquashStalls;
+
+ continue;
+ } else if (mem_head_inst->seqNum < oldest_inst) {
+ oldest_inst = mem_head_inst->seqNum;
+
+ list_with_oldest = Memory;
+ }
+ }
+
+ if (!readyMiscInsts.empty()) {
+
+ insts_available = true;
+
+ misc_head_inst = readyMiscInsts.top();
+
+ if (misc_head_inst->isSquashed()) {
+ readyMiscInsts.pop();
+
+ ++iqLoopSquashStalls;
+
+ continue;
+ } else if (misc_head_inst->seqNum < oldest_inst) {
+ oldest_inst = misc_head_inst->seqNum;
+
+ list_with_oldest = Misc;
+ }
+ }
+
+ if (!squashedInsts.empty()) {
+
+ insts_available = true;
+
+ squashed_head_inst = squashedInsts.top();
+
+ if (squashed_head_inst->seqNum < oldest_inst) {
+ list_with_oldest = Squashed;
+ }
+
+ }
+
+ DynInstPtr issuing_inst = NULL;
+
+ switch (list_with_oldest) {
+ case None:
+ DPRINTF(IQ, "IQ: Not able to schedule any instructions. Issuing "
+ "inst is %#x.\n", issuing_inst);
+ break;
+
+ case Int:
+ issuing_inst = int_head_inst;
+ readyIntInsts.pop();
+ ++int_issued;
+ DPRINTF(IQ, "IQ: Issuing integer instruction PC %#x.\n",
+ issuing_inst->readPC());
+ break;
+
+ case Float:
+ issuing_inst = float_head_inst;
+ readyFloatInsts.pop();
+ ++float_issued;
+ DPRINTF(IQ, "IQ: Issuing float instruction PC %#x.\n",
+ issuing_inst->readPC());
+ break;
+
+ case Branch:
+ issuing_inst = branch_head_inst;
+ readyBranchInsts.pop();
+ ++branch_issued;
+ DPRINTF(IQ, "IQ: Issuing branch instruction PC %#x.\n",
+ issuing_inst->readPC());
+ break;
+
+ case Memory:
+ issuing_inst = mem_head_inst;
+
+ memDepUnit.pop();
+ ++memory_issued;
+ DPRINTF(IQ, "IQ: Issuing memory instruction PC %#x.\n",
+ issuing_inst->readPC());
+ break;
+
+ case Misc:
+ issuing_inst = misc_head_inst;
+ readyMiscInsts.pop();
+
+ ++iqMiscInstsIssued;
+
+ DPRINTF(IQ, "IQ: Issuing a miscellaneous instruction PC %#x.\n",
+ issuing_inst->readPC());
+ break;
+
+ case Squashed:
+ assert(0 && "Squashed insts should not issue any more!");
+ squashedInsts.pop();
+ // Set the squashed instruction as able to commit so that commit
+ // can just drop it from the ROB. This is a bit faked.
+ ++squashed_issued;
+ ++freeEntries;
+
+ DPRINTF(IQ, "IQ: Issuing squashed instruction PC %#x.\n",
+ squashed_head_inst->readPC());
+ break;
+ }
+
+ if (list_with_oldest != None && list_with_oldest != Squashed) {
+ i2e_info->insts[total_issued] = issuing_inst;
+ i2e_info->size++;
+
+ issuing_inst->setIssued();
+
+ ++freeEntries;
+ ++total_issued;
+ }
+
+ assert(freeEntries == (numEntries - countInsts()));
+ }
+
+ iqIntInstsIssued += int_issued;
+ iqFloatInstsIssued += float_issued;
+ iqBranchInstsIssued += branch_issued;
+ iqMemInstsIssued += memory_issued;
+ iqSquashedInstsIssued += squashed_issued;
+}
+
+template <class Impl>
+void
+InstructionQueue<Impl>::scheduleNonSpec(const InstSeqNum &inst)
+{
+ DPRINTF(IQ, "IQ: Marking nonspeculative instruction with sequence "
+ "number %i as ready to execute.\n", inst);
+
+ non_spec_it_t inst_it = nonSpecInsts.find(inst);
+
+ assert(inst_it != nonSpecInsts.end());
+
+ // Mark this instruction as ready to issue.
+ (*inst_it).second->setCanIssue();
+
+ // Now schedule the instruction.
+ if (!(*inst_it).second->isMemRef()) {
+ addIfReady((*inst_it).second);
+ } else {
+ memDepUnit.nonSpecInstReady((*inst_it).second);
+ }
+
+ nonSpecInsts.erase(inst_it);
+}
+
+template <class Impl>
+void
+InstructionQueue<Impl>::wakeDependents(DynInstPtr &completed_inst)
+{
+ DPRINTF(IQ, "IQ: Waking dependents of completed instruction.\n");
+ //Look at the physical destination register of the DynInst
+ //and look it up on the dependency graph. Then mark as ready
+ //any instructions within the instruction queue.
+ DependencyEntry *curr;
+
+ // Tell the memory dependence unit to wake any dependents on this
+ // instruction if it is a memory instruction.
+
+ if (completed_inst->isMemRef()) {
+ memDepUnit.wakeDependents(completed_inst);
+ }
+
+ for (int dest_reg_idx = 0;
+ dest_reg_idx < completed_inst->numDestRegs();
+ dest_reg_idx++)
+ {
+ PhysRegIndex dest_reg =
+ completed_inst->renamedDestRegIdx(dest_reg_idx);
+
+ // Special case of uniq or control registers. They are not
+ // handled by the IQ and thus have no dependency graph entry.
+ // @todo Figure out a cleaner way to handle this.
+ if (dest_reg >= numPhysRegs) {
+ continue;
+ }
+
+ DPRINTF(IQ, "IQ: Waking any dependents on register %i.\n",
+ (int) dest_reg);
+
+ //Maybe abstract this part into a function.
+ //Go through the dependency chain, marking the registers as ready
+ //within the waiting instructions.
+ while (dependGraph[dest_reg].next) {
+
+ curr = dependGraph[dest_reg].next;
+
+ DPRINTF(IQ, "IQ: Waking up a dependent instruction, PC%#x.\n",
+ curr->inst->readPC());
+
+ // Might want to give more information to the instruction
+ // so that it knows which of its source registers is ready.
+ // However that would mean that the dependency graph entries
+ // would need to hold the src_reg_idx.
+ curr->inst->markSrcRegReady();
+
+ addIfReady(curr->inst);
+
+ dependGraph[dest_reg].next = curr->next;
+
+ DependencyEntry::mem_alloc_counter--;
+
+ curr->inst = NULL;
+
+ delete curr;
+ }
+
+ // Reset the head node now that all of its dependents have been woken
+ // up.
+ dependGraph[dest_reg].next = NULL;
+ dependGraph[dest_reg].inst = NULL;
+
+ // Mark the scoreboard as having that register ready.
+ regScoreboard[dest_reg] = true;
+ }
+}
+
+template <class Impl>
+void
+InstructionQueue<Impl>::violation(DynInstPtr &store,
+ DynInstPtr &faulting_load)
+{
+ memDepUnit.violation(store, faulting_load);
+}
+
+template <class Impl>
+void
+InstructionQueue<Impl>::squash()
+{
+ DPRINTF(IQ, "IQ: Starting to squash instructions in the IQ.\n");
+
+ // Read instruction sequence number of last instruction out of the
+ // time buffer.
+ squashedSeqNum = fromCommit->commitInfo.doneSeqNum;
+
+ // Setup the squash iterator to point to the tail.
+ squashIt = tail;
+
+ // Call doSquash if there are insts in the IQ
+ if (freeEntries != numEntries) {
+ doSquash();
+ }
+
+ // Also tell the memory dependence unit to squash.
+ memDepUnit.squash(squashedSeqNum);
+}
+
+template <class Impl>
+void
+InstructionQueue<Impl>::doSquash()
+{
+ // Make sure the squash iterator isn't pointing to nothing.
+ assert(squashIt != cpu->instList.end());
+ // Make sure the squashed sequence number is valid.
+ assert(squashedSeqNum != 0);
+
+ DPRINTF(IQ, "IQ: Squashing instructions in the IQ.\n");
+
+ // Squash any instructions younger than the squashed sequence number
+ // given.
+ while ((*squashIt)->seqNum > squashedSeqNum) {
+ DynInstPtr squashed_inst = (*squashIt);
+
+ // Only handle the instruction if it actually is in the IQ and
+ // hasn't already been squashed in the IQ.
+ if (!squashed_inst->isIssued() &&
+ !squashed_inst->isSquashedInIQ()) {
+
+ // Remove the instruction from the dependency list.
+ // Hack for now: These below don't add themselves to the
+ // dependency list, so don't try to remove them.
+ if (!squashed_inst->isNonSpeculative()/* &&
+ !squashed_inst->isStore()*/
+ ) {
+
+ for (int src_reg_idx = 0;
+ src_reg_idx < squashed_inst->numSrcRegs();
+ src_reg_idx++)
+ {
+ PhysRegIndex src_reg =
+ squashed_inst->renamedSrcRegIdx(src_reg_idx);
+
+ // Only remove it from the dependency graph if it was
+ // placed there in the first place.
+ // HACK: This assumes that instructions woken up from the
+ // dependency chain aren't informed that a specific src
+ // register has become ready. This may not always be true
+ // in the future.
+ if (!squashed_inst->isReadySrcRegIdx(src_reg_idx) &&
+ src_reg < numPhysRegs) {
+ dependGraph[src_reg].remove(squashed_inst);
+ }
+
+ ++iqSquashedOperandsExamined;
+ }
+
+ // Might want to remove producers as well.
+ } else {
+ nonSpecInsts[squashed_inst->seqNum] = NULL;
+
+ nonSpecInsts.erase(squashed_inst->seqNum);
+
+ ++iqSquashedNonSpecRemoved;
+ }
+
+ // Might want to also clear out the head of the dependency graph.
+
+ // Mark it as squashed within the IQ.
+ squashed_inst->setSquashedInIQ();
+
+// squashedInsts.push(squashed_inst);
+ squashed_inst->setIssued();
+ squashed_inst->setCanCommit();
+
+ ++freeEntries;
+
+ DPRINTF(IQ, "IQ: Instruction PC %#x squashed.\n",
+ squashed_inst->readPC());
+ }
+
+ --squashIt;
+ ++iqSquashedInstsExamined;
+ }
+
+ assert(freeEntries <= numEntries);
+
+ if (freeEntries == numEntries) {
+ tail = cpu->instList.end();
+ }
+
+}
+
+template <class Impl>
+void
+InstructionQueue<Impl>::stopSquash()
+{
+ // Clear up the squash variables to ensure that squashing doesn't
+ // get called improperly.
+ squashedSeqNum = 0;
+
+ squashIt = cpu->instList.end();
+}
+
+template <class Impl>
+void
+InstructionQueue<Impl>::DependencyEntry::insert(DynInstPtr &new_inst)
+{
+ //Add this new, dependent instruction at the head of the dependency
+ //chain.
+
+ // First create the entry that will be added to the head of the
+ // dependency chain.
+ DependencyEntry *new_entry = new DependencyEntry;
+ new_entry->next = this->next;
+ new_entry->inst = new_inst;
+
+ // Then actually add it to the chain.
+ this->next = new_entry;
+
+ ++mem_alloc_counter;
+}
+
+template <class Impl>
+void
+InstructionQueue<Impl>::DependencyEntry::remove(DynInstPtr &inst_to_remove)
+{
+ DependencyEntry *prev = this;
+ DependencyEntry *curr = this->next;
+
+ // Make sure curr isn't NULL. Because this instruction is being
+ // removed from a dependency list, it must have been placed there at
+ // an earlier time. The dependency chain should not be empty,
+ // unless the instruction dependent upon it is already ready.
+ if (curr == NULL) {
+ return;
+ }
+
+ // Find the instruction to remove within the dependency linked list.
+ while(curr->inst != inst_to_remove)
+ {
+ prev = curr;
+ curr = curr->next;
+
+ assert(curr != NULL);
+ }
+
+ // Now remove this instruction from the list.
+ prev->next = curr->next;
+
+ --mem_alloc_counter;
+
+ // Could push this off to the destructor of DependencyEntry
+ curr->inst = NULL;
+
+ delete curr;
+}
+
+template <class Impl>
+bool
+InstructionQueue<Impl>::addToDependents(DynInstPtr &new_inst)
+{
+ // Loop through the instruction's source registers, adding
+ // them to the dependency list if they are not ready.
+ int8_t total_src_regs = new_inst->numSrcRegs();
+ bool return_val = false;
+
+ for (int src_reg_idx = 0;
+ src_reg_idx < total_src_regs;
+ src_reg_idx++)
+ {
+ // Only add it to the dependency graph if it's not ready.
+ if (!new_inst->isReadySrcRegIdx(src_reg_idx)) {
+ PhysRegIndex src_reg = new_inst->renamedSrcRegIdx(src_reg_idx);
+
+ // Check the IQ's scoreboard to make sure the register
+ // hasn't become ready while the instruction was in flight
+ // between stages. Only if it really isn't ready should
+ // it be added to the dependency graph.
+ if (src_reg >= numPhysRegs) {
+ continue;
+ } else if (regScoreboard[src_reg] == false) {
+ DPRINTF(IQ, "IQ: Instruction PC %#x has src reg %i that "
+ "is being added to the dependency chain.\n",
+ new_inst->readPC(), src_reg);
+
+ dependGraph[src_reg].insert(new_inst);
+
+ // Change the return value to indicate that something
+ // was added to the dependency graph.
+ return_val = true;
+ } else {
+ DPRINTF(IQ, "IQ: Instruction PC %#x has src reg %i that "
+ "became ready before it reached the IQ.\n",
+ new_inst->readPC(), src_reg);
+ // Mark a register ready within the instruction.
+ new_inst->markSrcRegReady();
+ }
+ }
+ }
+
+ return return_val;
+}
+
+template <class Impl>
+void
+InstructionQueue<Impl>::createDependency(DynInstPtr &new_inst)
+{
+ //Actually nothing really needs to be marked when an
+ //instruction becomes the producer of a register's value,
+ //but for convenience a ptr to the producing instruction will
+ //be placed in the head node of the dependency links.
+ int8_t total_dest_regs = new_inst->numDestRegs();
+
+ for (int dest_reg_idx = 0;
+ dest_reg_idx < total_dest_regs;
+ dest_reg_idx++)
+ {
+ PhysRegIndex dest_reg = new_inst->renamedDestRegIdx(dest_reg_idx);
+
+ // Instructions that use the misc regs will have a reg number
+ // higher than the normal physical registers. In this case these
+ // registers are not renamed, and there is no need to track
+ // dependencies as these instructions must be executed at commit.
+ if (dest_reg >= numPhysRegs) {
+ continue;
+ }
+
+ dependGraph[dest_reg].inst = new_inst;
+
+ if (dependGraph[dest_reg].next) {
+ dumpDependGraph();
+ panic("IQ: Dependency graph not empty!");
+ }
+
+ // Mark the scoreboard to say it's not yet ready.
+ regScoreboard[dest_reg] = false;
+ }
+}
+
+template <class Impl>
+void
+InstructionQueue<Impl>::addIfReady(DynInstPtr &inst)
+{
+ //If the instruction now has all of its source registers
+ // available, then add it to the list of ready instructions.
+ if (inst->readyToIssue()) {
+
+ //Add the instruction to the proper ready list.
+ if (inst->isControl()) {
+
+ DPRINTF(IQ, "IQ: Branch instruction is ready to issue, "
+ "putting it onto the ready list, PC %#x.\n",
+ inst->readPC());
+ readyBranchInsts.push(inst);
+
+ } else if (inst->isMemRef()) {
+
+ DPRINTF(IQ, "IQ: Checking if memory instruction can issue.\n");
+
+ // Message to the mem dependence unit that this instruction has
+ // its registers ready.
+
+ memDepUnit.regsReady(inst);
+
+#if 0
+ if (memDepUnit.readyToIssue(inst)) {
+ DPRINTF(IQ, "IQ: Memory instruction is ready to issue, "
+ "putting it onto the ready list, PC %#x.\n",
+ inst->readPC());
+ readyMemInsts.push(inst);
+ } else {
+ // Make dependent on the store.
+ // Will need some way to get the store instruction it should
+ // be dependent upon; then when the store issues it can
+ // put the instruction on the ready list.
+ // Yet another tree?
+ assert(0 && "Instruction has no way to actually issue");
+ }
+#endif
+
+ } else if (inst->isInteger()) {
+
+ DPRINTF(IQ, "IQ: Integer instruction is ready to issue, "
+ "putting it onto the ready list, PC %#x.\n",
+ inst->readPC());
+ readyIntInsts.push(inst);
+
+ } else if (inst->isFloating()) {
+
+ DPRINTF(IQ, "IQ: Floating instruction is ready to issue, "
+ "putting it onto the ready list, PC %#x.\n",
+ inst->readPC());
+ readyFloatInsts.push(inst);
+
+ } else {
+ DPRINTF(IQ, "IQ: Miscellaneous instruction is ready to issue, "
+ "putting it onto the ready list, PC %#x..\n",
+ inst->readPC());
+
+ readyMiscInsts.push(inst);
+ }
+ }
+}
+
+/*
+ * Caution, this function must not be called prior to tail being updated at
+ * least once, otherwise it will fail the assertion. This is because
+ * instList.begin() actually changes upon the insertion of an element into the
+ * list when the list is empty.
+ */
+template <class Impl>
+int
+InstructionQueue<Impl>::countInsts()
+{
+ ListIt count_it = cpu->instList.begin();
+ int total_insts = 0;
+
+ if (tail == cpu->instList.end())
+ return 0;
+
+ while (count_it != tail) {
+ if (!(*count_it)->isIssued()) {
+ ++total_insts;
+ }
+
+ ++count_it;
+
+ assert(count_it != cpu->instList.end());
+ }
+
+ // Need to count the tail iterator as well.
+ if (count_it != cpu->instList.end() &&
+ (*count_it) &&
+ !(*count_it)->isIssued()) {
+ ++total_insts;
+ }
+
+ return total_insts;
+}
+
+template <class Impl>
+void
+InstructionQueue<Impl>::dumpDependGraph()
+{
+ DependencyEntry *curr;
+
+ for (int i = 0; i < numPhysRegs; ++i)
+ {
+ curr = &dependGraph[i];
+
+ if (curr->inst) {
+ cprintf("dependGraph[%i]: producer: %#x consumer: ", i,
+ curr->inst->readPC());
+ } else {
+ cprintf("dependGraph[%i]: No producer. consumer: ", i);
+ }
+
+ while (curr->next != NULL) {
+ curr = curr->next;
+
+ cprintf("%#x ", curr->inst->readPC());
+ }
+
+ cprintf("\n");
+ }
+}
+
+template <class Impl>
+void
+InstructionQueue<Impl>::dumpLists()
+{
+ cprintf("Ready integer list size: %i\n", readyIntInsts.size());
+
+ cprintf("Ready float list size: %i\n", readyFloatInsts.size());
+
+ cprintf("Ready branch list size: %i\n", readyBranchInsts.size());
+
+ cprintf("Ready misc list size: %i\n", readyMiscInsts.size());
+
+ cprintf("Squashed list size: %i\n", squashedInsts.size());
+
+ cprintf("Non speculative list size: %i\n", nonSpecInsts.size());
+
+ non_spec_it_t non_spec_it = nonSpecInsts.begin();
+
+ cprintf("Non speculative list: ");
+
+ while (non_spec_it != nonSpecInsts.end()) {
+ cprintf("%#x ", (*non_spec_it).second->readPC());
+ ++non_spec_it;
+ }
+
+ cprintf("\n");
+
+}
diff --git a/src/cpu/o3/mem_dep_unit.cc b/src/cpu/o3/mem_dep_unit.cc
new file mode 100644
index 000000000..9c1e7f9d8
--- /dev/null
+++ b/src/cpu/o3/mem_dep_unit.cc
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "cpu/o3/alpha_dyn_inst.hh"
+#include "cpu/o3/alpha_impl.hh"
+#include "cpu/o3/store_set.hh"
+#include "cpu/o3/mem_dep_unit_impl.hh"
+
+// Force instantation of memory dependency unit using store sets and
+// AlphaSimpleImpl.
+template class MemDepUnit<StoreSet, AlphaSimpleImpl>;
diff --git a/src/cpu/o3/mem_dep_unit.hh b/src/cpu/o3/mem_dep_unit.hh
new file mode 100644
index 000000000..ca63577a1
--- /dev/null
+++ b/src/cpu/o3/mem_dep_unit.hh
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPU_O3_CPU_MEM_DEP_UNIT_HH__
+#define __CPU_O3_CPU_MEM_DEP_UNIT_HH__
+
+#include <map>
+#include <set>
+
+#include "base/statistics.hh"
+#include "cpu/inst_seq.hh"
+
+/**
+ * Memory dependency unit class. This holds the memory dependence predictor.
+ * As memory operations are issued to the IQ, they are also issued to this
+ * unit, which then looks up the prediction as to what they are dependent
+ * upon. This unit must be checked prior to a memory operation being able
+ * to issue. Although this is templated, it's somewhat hard to make a generic
+ * memory dependence unit. This one is mostly for store sets; it will be
+ * quite limited in what other memory dependence predictions it can also
+ * utilize. Thus this class should be most likely be rewritten for other
+ * dependence prediction schemes.
+ */
+template <class MemDepPred, class Impl>
+class MemDepUnit {
+ public:
+ typedef typename Impl::Params Params;
+ typedef typename Impl::DynInstPtr DynInstPtr;
+
+ public:
+ MemDepUnit(Params &params);
+
+ void regStats();
+
+ void insert(DynInstPtr &inst);
+
+ void insertNonSpec(DynInstPtr &inst);
+
+ // Will want to make this operation relatively fast. Right now it
+ // is somewhat slow.
+ DynInstPtr &top();
+
+ void pop();
+
+ void regsReady(DynInstPtr &inst);
+
+ void nonSpecInstReady(DynInstPtr &inst);
+
+ void issue(DynInstPtr &inst);
+
+ void wakeDependents(DynInstPtr &inst);
+
+ void squash(const InstSeqNum &squashed_num);
+
+ void violation(DynInstPtr &store_inst, DynInstPtr &violating_load);
+
+ inline bool empty()
+ { return readyInsts.empty(); }
+
+ private:
+ typedef typename std::set<InstSeqNum>::iterator sn_it_t;
+ typedef typename std::map<InstSeqNum, DynInstPtr>::iterator dyn_it_t;
+
+ // Forward declarations so that the following two typedefs work.
+ class Dependency;
+ class ltDependency;
+
+ typedef typename std::set<Dependency, ltDependency>::iterator dep_it_t;
+ typedef typename std::map<InstSeqNum, vector<dep_it_t> >::iterator
+ sd_it_t;
+
+ struct Dependency {
+ Dependency(const InstSeqNum &_seqNum)
+ : seqNum(_seqNum), regsReady(0), memDepReady(0)
+ { }
+
+ Dependency(const InstSeqNum &_seqNum, bool _regsReady,
+ bool _memDepReady)
+ : seqNum(_seqNum), regsReady(_regsReady),
+ memDepReady(_memDepReady)
+ { }
+
+ InstSeqNum seqNum;
+ mutable bool regsReady;
+ mutable bool memDepReady;
+ mutable sd_it_t storeDep;
+ };
+
+ struct ltDependency {
+ bool operator() (const Dependency &lhs, const Dependency &rhs)
+ {
+ return lhs.seqNum < rhs.seqNum;
+ }
+ };
+
+ inline void moveToReady(dep_it_t &woken_inst);
+
+ /** List of instructions that have passed through rename, yet are still
+ * waiting on either a memory dependence to resolve or source registers to
+ * become available before they can issue.
+ */
+ std::set<Dependency, ltDependency> waitingInsts;
+
+ /** List of instructions that have all their predicted memory dependences
+ * resolved and their source registers ready.
+ */
+ std::set<InstSeqNum> readyInsts;
+
+ // Change this to hold a vector of iterators, which will point to the
+ // entry of the waiting instructions.
+ /** List of stores' sequence numbers, each of which has a vector of
+ * iterators. The iterators point to the appropriate node within
+ * waitingInsts that has the depenendent instruction.
+ */
+ std::map<InstSeqNum, vector<dep_it_t> > storeDependents;
+
+ // For now will implement this as a map...hash table might not be too
+ // bad, or could move to something that mimics the current dependency
+ // graph.
+ std::map<InstSeqNum, DynInstPtr> memInsts;
+
+ // Iterator pointer to the top instruction which has is ready.
+ // Is set by the top() call.
+ dyn_it_t topInst;
+
+ /** The memory dependence predictor. It is accessed upon new
+ * instructions being added to the IQ, and responds by telling
+ * this unit what instruction the newly added instruction is dependent
+ * upon.
+ */
+ MemDepPred depPred;
+
+ Stats::Scalar<> insertedLoads;
+ Stats::Scalar<> insertedStores;
+ Stats::Scalar<> conflictingLoads;
+ Stats::Scalar<> conflictingStores;
+};
+
+#endif // __CPU_O3_CPU_MEM_DEP_UNIT_HH__
diff --git a/src/cpu/o3/mem_dep_unit_impl.hh b/src/cpu/o3/mem_dep_unit_impl.hh
new file mode 100644
index 000000000..296db4c4e
--- /dev/null
+++ b/src/cpu/o3/mem_dep_unit_impl.hh
@@ -0,0 +1,419 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <map>
+
+#include "cpu/o3/mem_dep_unit.hh"
+
+template <class MemDepPred, class Impl>
+MemDepUnit<MemDepPred, Impl>::MemDepUnit(Params &params)
+ : depPred(params.SSITSize, params.LFSTSize)
+{
+ DPRINTF(MemDepUnit, "MemDepUnit: Creating MemDepUnit object.\n");
+}
+
+template <class MemDepPred, class Impl>
+void
+MemDepUnit<MemDepPred, Impl>::regStats()
+{
+ insertedLoads
+ .name(name() + ".memDep.insertedLoads")
+ .desc("Number of loads inserted to the mem dependence unit.");
+
+ insertedStores
+ .name(name() + ".memDep.insertedStores")
+ .desc("Number of stores inserted to the mem dependence unit.");
+
+ conflictingLoads
+ .name(name() + ".memDep.conflictingLoads")
+ .desc("Number of conflicting loads.");
+
+ conflictingStores
+ .name(name() + ".memDep.conflictingStores")
+ .desc("Number of conflicting stores.");
+}
+
+template <class MemDepPred, class Impl>
+void
+MemDepUnit<MemDepPred, Impl>::insert(DynInstPtr &inst)
+{
+ InstSeqNum inst_seq_num = inst->seqNum;
+
+ Dependency unresolved_dependencies(inst_seq_num);
+
+ InstSeqNum producing_store = depPred.checkInst(inst->readPC());
+
+ if (producing_store == 0 ||
+ storeDependents.find(producing_store) == storeDependents.end()) {
+
+ DPRINTF(MemDepUnit, "MemDepUnit: No dependency for inst PC "
+ "%#x.\n", inst->readPC());
+
+ unresolved_dependencies.storeDep = storeDependents.end();
+
+ if (inst->readyToIssue()) {
+ readyInsts.insert(inst_seq_num);
+ } else {
+ unresolved_dependencies.memDepReady = true;
+
+ waitingInsts.insert(unresolved_dependencies);
+ }
+ } else {
+ DPRINTF(MemDepUnit, "MemDepUnit: Adding to dependency list; "
+ "inst PC %#x is dependent on seq num %i.\n",
+ inst->readPC(), producing_store);
+
+ if (inst->readyToIssue()) {
+ unresolved_dependencies.regsReady = true;
+ }
+
+ // Find the store that this instruction is dependent on.
+ sd_it_t store_loc = storeDependents.find(producing_store);
+
+ assert(store_loc != storeDependents.end());
+
+ // Record the location of the store that this instruction is
+ // dependent on.
+ unresolved_dependencies.storeDep = store_loc;
+
+ // If it's not already ready, then add it to the renamed
+ // list and the dependencies.
+ dep_it_t inst_loc =
+ (waitingInsts.insert(unresolved_dependencies)).first;
+
+ // Add this instruction to the list of dependents.
+ (*store_loc).second.push_back(inst_loc);
+
+ assert(!(*store_loc).second.empty());
+
+ if (inst->isLoad()) {
+ ++conflictingLoads;
+ } else {
+ ++conflictingStores;
+ }
+ }
+
+ if (inst->isStore()) {
+ DPRINTF(MemDepUnit, "MemDepUnit: Inserting store PC %#x.\n",
+ inst->readPC());
+
+ depPred.insertStore(inst->readPC(), inst_seq_num);
+
+ // Make sure this store isn't already in this list.
+ assert(storeDependents.find(inst_seq_num) == storeDependents.end());
+
+ // Put a dependency entry in at the store's sequence number.
+ // Uh, not sure how this works...I want to create an entry but
+ // I don't have anything to put into the value yet.
+ storeDependents[inst_seq_num];
+
+ assert(storeDependents.size() != 0);
+
+ ++insertedStores;
+
+ } else if (inst->isLoad()) {
+ ++insertedLoads;
+ } else {
+ panic("MemDepUnit: Unknown type! (most likely a barrier).");
+ }
+
+ memInsts[inst_seq_num] = inst;
+}
+
+template <class MemDepPred, class Impl>
+void
+MemDepUnit<MemDepPred, Impl>::insertNonSpec(DynInstPtr &inst)
+{
+ InstSeqNum inst_seq_num = inst->seqNum;
+
+ Dependency non_spec_inst(inst_seq_num);
+
+ non_spec_inst.storeDep = storeDependents.end();
+
+ waitingInsts.insert(non_spec_inst);
+
+ // Might want to turn this part into an inline function or something.
+ // It's shared between both insert functions.
+ if (inst->isStore()) {
+ DPRINTF(MemDepUnit, "MemDepUnit: Inserting store PC %#x.\n",
+ inst->readPC());
+
+ depPred.insertStore(inst->readPC(), inst_seq_num);
+
+ // Make sure this store isn't already in this list.
+ assert(storeDependents.find(inst_seq_num) == storeDependents.end());
+
+ // Put a dependency entry in at the store's sequence number.
+ // Uh, not sure how this works...I want to create an entry but
+ // I don't have anything to put into the value yet.
+ storeDependents[inst_seq_num];
+
+ assert(storeDependents.size() != 0);
+
+ ++insertedStores;
+
+ } else if (inst->isLoad()) {
+ ++insertedLoads;
+ } else {
+ panic("MemDepUnit: Unknown type! (most likely a barrier).");
+ }
+
+ memInsts[inst_seq_num] = inst;
+}
+
+template <class MemDepPred, class Impl>
+typename Impl::DynInstPtr &
+MemDepUnit<MemDepPred, Impl>::top()
+{
+ topInst = memInsts.find( (*readyInsts.begin()) );
+
+ DPRINTF(MemDepUnit, "MemDepUnit: Top instruction is PC %#x.\n",
+ (*topInst).second->readPC());
+
+ return (*topInst).second;
+}
+
+template <class MemDepPred, class Impl>
+void
+MemDepUnit<MemDepPred, Impl>::pop()
+{
+ DPRINTF(MemDepUnit, "MemDepUnit: Removing instruction PC %#x.\n",
+ (*topInst).second->readPC());
+
+ wakeDependents((*topInst).second);
+
+ issue((*topInst).second);
+
+ memInsts.erase(topInst);
+
+ topInst = memInsts.end();
+}
+
+template <class MemDepPred, class Impl>
+void
+MemDepUnit<MemDepPred, Impl>::regsReady(DynInstPtr &inst)
+{
+ DPRINTF(MemDepUnit, "MemDepUnit: Marking registers as ready for "
+ "instruction PC %#x.\n",
+ inst->readPC());
+
+ InstSeqNum inst_seq_num = inst->seqNum;
+
+ Dependency inst_to_find(inst_seq_num);
+
+ dep_it_t waiting_inst = waitingInsts.find(inst_to_find);
+
+ assert(waiting_inst != waitingInsts.end());
+
+ if ((*waiting_inst).memDepReady) {
+ DPRINTF(MemDepUnit, "MemDepUnit: Instruction has its memory "
+ "dependencies resolved, adding it to the ready list.\n");
+
+ moveToReady(waiting_inst);
+ } else {
+ DPRINTF(MemDepUnit, "MemDepUnit: Instruction still waiting on "
+ "memory dependency.\n");
+
+ (*waiting_inst).regsReady = true;
+ }
+}
+
+template <class MemDepPred, class Impl>
+void
+MemDepUnit<MemDepPred, Impl>::nonSpecInstReady(DynInstPtr &inst)
+{
+ DPRINTF(MemDepUnit, "MemDepUnit: Marking non speculative "
+ "instruction PC %#x as ready.\n",
+ inst->readPC());
+
+ InstSeqNum inst_seq_num = inst->seqNum;
+
+ Dependency inst_to_find(inst_seq_num);
+
+ dep_it_t waiting_inst = waitingInsts.find(inst_to_find);
+
+ assert(waiting_inst != waitingInsts.end());
+
+ moveToReady(waiting_inst);
+}
+
+template <class MemDepPred, class Impl>
+void
+MemDepUnit<MemDepPred, Impl>::issue(DynInstPtr &inst)
+{
+ assert(readyInsts.find(inst->seqNum) != readyInsts.end());
+
+ DPRINTF(MemDepUnit, "MemDepUnit: Issuing instruction PC %#x.\n",
+ inst->readPC());
+
+ // Remove the instruction from the ready list.
+ readyInsts.erase(inst->seqNum);
+
+ depPred.issued(inst->readPC(), inst->seqNum, inst->isStore());
+}
+
+template <class MemDepPred, class Impl>
+void
+MemDepUnit<MemDepPred, Impl>::wakeDependents(DynInstPtr &inst)
+{
+ // Only stores have dependents.
+ if (!inst->isStore()) {
+ return;
+ }
+
+ // Wake any dependencies.
+ sd_it_t sd_it = storeDependents.find(inst->seqNum);
+
+ // If there's no entry, then return. Really there should only be
+ // no entry if the instruction is a load.
+ if (sd_it == storeDependents.end()) {
+ DPRINTF(MemDepUnit, "MemDepUnit: Instruction PC %#x, sequence "
+ "number %i has no dependents.\n",
+ inst->readPC(), inst->seqNum);
+
+ return;
+ }
+
+ for (int i = 0; i < (*sd_it).second.size(); ++i ) {
+ dep_it_t woken_inst = (*sd_it).second[i];
+
+ DPRINTF(MemDepUnit, "MemDepUnit: Waking up a dependent inst, "
+ "sequence number %i.\n",
+ (*woken_inst).seqNum);
+#if 0
+ // Should we have reached instructions that are actually squashed,
+ // there will be no more useful instructions in this dependency
+ // list. Break out early.
+ if (waitingInsts.find(woken_inst) == waitingInsts.end()) {
+ DPRINTF(MemDepUnit, "MemDepUnit: Dependents on inst PC %#x "
+ "are squashed, starting at SN %i. Breaking early.\n",
+ inst->readPC(), woken_inst);
+ break;
+ }
+#endif
+
+ if ((*woken_inst).regsReady) {
+ moveToReady(woken_inst);
+ } else {
+ (*woken_inst).memDepReady = true;
+ }
+ }
+
+ storeDependents.erase(sd_it);
+}
+
+template <class MemDepPred, class Impl>
+void
+MemDepUnit<MemDepPred, Impl>::squash(const InstSeqNum &squashed_num)
+{
+
+ if (!waitingInsts.empty()) {
+ dep_it_t waiting_it = waitingInsts.end();
+
+ --waiting_it;
+
+ // Remove entries from the renamed list as long as we haven't reached
+ // the end and the entries continue to be younger than the squashed.
+ while (!waitingInsts.empty() &&
+ (*waiting_it).seqNum > squashed_num)
+ {
+ if (!(*waiting_it).memDepReady &&
+ (*waiting_it).storeDep != storeDependents.end()) {
+ sd_it_t sd_it = (*waiting_it).storeDep;
+
+ // Make sure the iterator that the store has pointing
+ // back is actually to this instruction.
+ assert((*sd_it).second.back() == waiting_it);
+
+ // Now remove this from the store's list of dependent
+ // instructions.
+ (*sd_it).second.pop_back();
+ }
+
+ waitingInsts.erase(waiting_it--);
+ }
+ }
+
+ if (!readyInsts.empty()) {
+ sn_it_t ready_it = readyInsts.end();
+
+ --ready_it;
+
+ // Same for the ready list.
+ while (!readyInsts.empty() &&
+ (*ready_it) > squashed_num)
+ {
+ readyInsts.erase(ready_it--);
+ }
+ }
+
+ if (!storeDependents.empty()) {
+ sd_it_t dep_it = storeDependents.end();
+
+ --dep_it;
+
+ // Same for the dependencies list.
+ while (!storeDependents.empty() &&
+ (*dep_it).first > squashed_num)
+ {
+ // This store's list of dependent instructions should be empty.
+ assert((*dep_it).second.empty());
+
+ storeDependents.erase(dep_it--);
+ }
+ }
+
+ // Tell the dependency predictor to squash as well.
+ depPred.squash(squashed_num);
+}
+
+template <class MemDepPred, class Impl>
+void
+MemDepUnit<MemDepPred, Impl>::violation(DynInstPtr &store_inst,
+ DynInstPtr &violating_load)
+{
+ DPRINTF(MemDepUnit, "MemDepUnit: Passing violating PCs to store sets,"
+ " load: %#x, store: %#x\n", violating_load->readPC(),
+ store_inst->readPC());
+ // Tell the memory dependence unit of the violation.
+ depPred.violation(violating_load->readPC(), store_inst->readPC());
+}
+
+template <class MemDepPred, class Impl>
+inline void
+MemDepUnit<MemDepPred, Impl>::moveToReady(dep_it_t &woken_inst)
+{
+ DPRINTF(MemDepUnit, "MemDepUnit: Adding instruction sequence number %i "
+ "to the ready list.\n", (*woken_inst).seqNum);
+
+ // Add it to the ready list.
+ readyInsts.insert((*woken_inst).seqNum);
+
+ // Remove it from the waiting instructions.
+ waitingInsts.erase(woken_inst);
+}
diff --git a/src/cpu/o3/ras.cc b/src/cpu/o3/ras.cc
new file mode 100644
index 000000000..0a7d6ca63
--- /dev/null
+++ b/src/cpu/o3/ras.cc
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "cpu/o3/ras.hh"
+
+ReturnAddrStack::ReturnAddrStack(unsigned _numEntries)
+ : numEntries(_numEntries), usedEntries(0),
+ tos(0)
+{
+ addrStack = new Addr[numEntries];
+
+ for (int i = 0; i < numEntries; ++i)
+ addrStack[i] = 0;
+}
+
+void
+ReturnAddrStack::push(const Addr &return_addr)
+{
+ incrTos();
+
+ addrStack[tos] = return_addr;
+
+ if (usedEntries != numEntries) {
+ ++usedEntries;
+ }
+}
+
+void
+ReturnAddrStack::pop()
+{
+ // Not sure it's possible to really track usedEntries properly.
+// assert(usedEntries > 0);
+
+ if (usedEntries > 0) {
+ --usedEntries;
+ }
+
+ decrTos();
+}
+
+void
+ReturnAddrStack::restore(unsigned top_entry_idx,
+ const Addr &restored_target)
+{
+ tos = top_entry_idx;
+
+ addrStack[tos] = restored_target;
+}
diff --git a/src/cpu/o3/ras.hh b/src/cpu/o3/ras.hh
new file mode 100644
index 000000000..46d98181e
--- /dev/null
+++ b/src/cpu/o3/ras.hh
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPU_O3_CPU_RAS_HH__
+#define __CPU_O3_CPU_RAS_HH__
+
+// For Addr type.
+#include "arch/isa_traits.hh"
+
+class ReturnAddrStack
+{
+ public:
+ ReturnAddrStack(unsigned numEntries);
+
+ Addr top()
+ { return addrStack[tos]; }
+
+ unsigned topIdx()
+ { return tos; }
+
+ void push(const Addr &return_addr);
+
+ void pop();
+
+ void restore(unsigned top_entry_idx, const Addr &restored_target);
+
+ private:
+ inline void incrTos()
+ { if (++tos == numEntries) tos = 0; }
+
+ inline void decrTos()
+ { tos = (tos == 0 ? numEntries - 1 : tos - 1); }
+
+ Addr *addrStack;
+
+ unsigned numEntries;
+
+ unsigned usedEntries;
+
+ unsigned tos;
+};
+
+#endif // __CPU_O3_CPU_RAS_HH__
diff --git a/src/cpu/o3/regfile.hh b/src/cpu/o3/regfile.hh
new file mode 100644
index 000000000..a5cfa8f3c
--- /dev/null
+++ b/src/cpu/o3/regfile.hh
@@ -0,0 +1,299 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPU_O3_CPU_REGFILE_HH__
+#define __CPU_O3_CPU_REGFILE_HH__
+
+// @todo: Destructor
+
+#include "arch/isa_traits.hh"
+#include "arch/faults.hh"
+#include "base/trace.hh"
+#include "config/full_system.hh"
+#include "cpu/o3/comm.hh"
+
+#if FULL_SYSTEM
+#include "kern/kernel_stats.hh"
+
+#endif
+
+// This really only depends on the ISA, and not the Impl. It might be nicer
+// to see if I can make it depend on nothing...
+// Things that are in the ifdef FULL_SYSTEM are pretty dependent on the ISA,
+// and should go in the AlphaFullCPU.
+
+template <class Impl>
+class PhysRegFile
+{
+ protected:
+ typedef TheISA::IntReg IntReg;
+ typedef TheISA::FloatReg FloatReg;
+ typedef TheISA::MiscRegFile MiscRegFile;
+ typedef TheISA::MiscReg MiscReg;
+
+ //Note that most of the definitions of the IntReg, FloatReg, etc. exist
+ //within the Impl/ISA class and not within this PhysRegFile class.
+
+ //Will need some way to allow stuff like swap_palshadow to access the
+ //correct registers. Might require code changes to swap_palshadow and
+ //other execution contexts.
+
+ //Will make these registers public for now, but they probably should
+ //be private eventually with some accessor functions.
+ public:
+ typedef typename Impl::FullCPU FullCPU;
+
+ PhysRegFile(unsigned _numPhysicalIntRegs,
+ unsigned _numPhysicalFloatRegs);
+
+ //Everything below should be pretty well identical to the normal
+ //register file that exists within AlphaISA class.
+ //The duplication is unfortunate but it's better than having
+ //different ways to access certain registers.
+
+ //Add these in later when everything else is in place
+// void serialize(std::ostream &os);
+// void unserialize(Checkpoint *cp, const std::string &section);
+
+ uint64_t readIntReg(PhysRegIndex reg_idx)
+ {
+ assert(reg_idx < numPhysicalIntRegs);
+
+ DPRINTF(IEW, "RegFile: Access to int register %i, has data "
+ "%i\n", int(reg_idx), intRegFile[reg_idx]);
+ return intRegFile[reg_idx];
+ }
+
+ FloatReg readFloatReg(PhysRegIndex reg_idx, int width)
+ {
+ // Remove the base Float reg dependency.
+ reg_idx = reg_idx - numPhysicalIntRegs;
+
+ assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs);
+
+ FloatReg floatReg = floatRegFile.readReg(reg_idx, width);
+
+ DPRINTF(IEW, "RegFile: Access to %d byte float register %i, has "
+ "data %8.8d\n", int(reg_idx), (double)floatReg);
+
+ return floatReg;
+ }
+
+ FloatReg readFloatReg(PhysRegIndex reg_idx)
+ {
+ // Remove the base Float reg dependency.
+ reg_idx = reg_idx - numPhysicalIntRegs;
+
+ assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs);
+
+ FloatReg floatReg = floatRegFile.readReg(reg_idx);
+
+ DPRINTF(IEW, "RegFile: Access to float register %i, has "
+ "data %8.8d\n", int(reg_idx), (double)floatReg);
+
+ return floatReg;
+ }
+
+ FloatRegBits readFloatRegBits(PhysRegIndex reg_idx, int width)
+ {
+ // Remove the base Float reg dependency.
+ reg_idx = reg_idx - numPhysicalIntRegs;
+
+ assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs);
+
+ FloatRegBits floatRegBits = floatRegFile.readRegBits(reg_idx, width);
+
+ DPRINTF(IEW, "RegFile: Access to %d byte float register %i as int, "
+ "has data %lli\n", int(reg_idx), (uint64_t)floatRegBits);
+
+ return floatRegBits;
+ }
+
+ FloatRegBits readFloatRegBits(PhysRegIndex reg_idx)
+ {
+ // Remove the base Float reg dependency.
+ reg_idx = reg_idx - numPhysicalIntRegs;
+
+ assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs);
+
+ FloatRegBits floatRegBits = floatRegFile.readRegBits(reg_idx);
+
+ DPRINTF(IEW, "RegFile: Access to float register %i as int, "
+ "has data %lli\n", int(reg_idx), (uint64_t)floatRegBits);
+
+ return floatRegBits;
+ }
+
+ void setIntReg(PhysRegIndex reg_idx, uint64_t val)
+ {
+ assert(reg_idx < numPhysicalIntRegs);
+
+ DPRINTF(IEW, "RegFile: Setting int register %i to %lli\n",
+ int(reg_idx), val);
+
+ intRegFile[reg_idx] = val;
+ }
+
+ void setFloatReg(PhysRegIndex reg_idx, FloatReg val, int width)
+ {
+ // Remove the base Float reg dependency.
+ reg_idx = reg_idx - numPhysicalIntRegs;
+
+ assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs);
+
+ DPRINTF(IEW, "RegFile: Setting float register %i to %8.8d\n",
+ int(reg_idx), (double)val);
+
+ floatRegFile.setReg(reg_idx, val, width);
+ }
+
+ void setFloatReg(PhysRegIndex reg_idx, FloatReg val)
+ {
+ // Remove the base Float reg dependency.
+ reg_idx = reg_idx - numPhysicalIntRegs;
+
+ assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs);
+
+ DPRINTF(IEW, "RegFile: Setting float register %i to %8.8d\n",
+ int(reg_idx), (double)val);
+
+ floatRegFile.setReg(reg_idx, val);
+ }
+
+ void setFloatRegBits(PhysRegIndex reg_idx, FloatRegBits val, int width)
+ {
+ // Remove the base Float reg dependency.
+ reg_idx = reg_idx - numPhysicalIntRegs;
+
+ assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs);
+
+ DPRINTF(IEW, "RegFile: Setting float register %i to %lli\n",
+ int(reg_idx), (uint64_t)val);
+
+ floatRegFile.setRegBits(reg_idx, val, width);
+ }
+
+ void setFloatRegBits(PhysRegIndex reg_idx, FloatRegBits val)
+ {
+ // Remove the base Float reg dependency.
+ reg_idx = reg_idx - numPhysicalIntRegs;
+
+ assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs);
+
+ DPRINTF(IEW, "RegFile: Setting float register %i to %lli\n",
+ int(reg_idx), (uint64_t)val);
+
+ floatRegFile.setRegBits(reg_idx, val);
+ }
+
+ uint64_t readPC()
+ {
+ return pc;
+ }
+
+ void setPC(uint64_t val)
+ {
+ pc = val;
+ }
+
+ void setNextPC(uint64_t val)
+ {
+ npc = val;
+ }
+
+ //Consider leaving this stuff and below in some implementation specific
+ //file as opposed to the general register file. Or have a derived class.
+ MiscReg readMiscReg(int misc_reg)
+ {
+ // Dummy function for now.
+ // @todo: Fix this once proxy XC is used.
+ return 0;
+ }
+
+ Fault setMiscReg(int misc_reg, const MiscReg &val)
+ {
+ // Dummy function for now.
+ // @todo: Fix this once proxy XC is used.
+ return NoFault;
+ }
+
+#if FULL_SYSTEM
+ int readIntrFlag() { return intrflag; }
+ void setIntrFlag(int val) { intrflag = val; }
+#endif
+
+ // These should be private eventually, but will be public for now
+ // so that I can hack around the initregs issue.
+ public:
+ /** (signed) integer register file. */
+ IntReg *intRegFile;
+
+ /** Floating point register file. */
+ FloatReg *floatRegFile;
+
+ /** Miscellaneous register file. */
+ MiscRegFile miscRegs;
+
+ /** Program counter. */
+ Addr pc;
+
+ /** Next-cycle program counter. */
+ Addr npc;
+
+#if FULL_SYSTEM
+ private:
+ // This is ISA specifc stuff; remove it eventually once ISAImpl is used
+// IntReg palregs[NumIntRegs]; // PAL shadow registers
+ int intrflag; // interrupt flag
+ bool pal_shadow; // using pal_shadow registers
+#endif
+
+ private:
+ FullCPU *cpu;
+
+ public:
+ void setCPU(FullCPU *cpu_ptr) { cpu = cpu_ptr; }
+
+ unsigned numPhysicalIntRegs;
+ unsigned numPhysicalFloatRegs;
+};
+
+template <class Impl>
+PhysRegFile<Impl>::PhysRegFile(unsigned _numPhysicalIntRegs,
+ unsigned _numPhysicalFloatRegs)
+ : numPhysicalIntRegs(_numPhysicalIntRegs),
+ numPhysicalFloatRegs(_numPhysicalFloatRegs)
+{
+ intRegFile = new IntReg[numPhysicalIntRegs];
+ floatRegFile = new FloatReg[numPhysicalFloatRegs];
+
+ memset(intRegFile, 0, sizeof(*intRegFile));
+ memset(floatRegFile, 0, sizeof(*floatRegFile));
+}
+
+#endif // __CPU_O3_CPU_REGFILE_HH__
diff --git a/src/cpu/o3/rename.cc b/src/cpu/o3/rename.cc
new file mode 100644
index 000000000..6e9ee23da
--- /dev/null
+++ b/src/cpu/o3/rename.cc
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "cpu/o3/alpha_dyn_inst.hh"
+#include "cpu/o3/alpha_impl.hh"
+#include "cpu/o3/rename_impl.hh"
+
+template class SimpleRename<AlphaSimpleImpl>;
diff --git a/src/cpu/o3/rename.hh b/src/cpu/o3/rename.hh
new file mode 100644
index 000000000..07b442964
--- /dev/null
+++ b/src/cpu/o3/rename.hh
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Todo:
+// Fix up trap and barrier handling.
+// May want to have different statuses to differentiate the different stall
+// conditions.
+
+#ifndef __CPU_O3_CPU_SIMPLE_RENAME_HH__
+#define __CPU_O3_CPU_SIMPLE_RENAME_HH__
+
+#include <list>
+
+#include "base/statistics.hh"
+#include "base/timebuf.hh"
+
+// Will need rename maps for both the int reg file and fp reg file.
+// Or change rename map class to handle both. (RegFile handles both.)
+template<class Impl>
+class SimpleRename
+{
+ public:
+ // Typedefs from the Impl.
+ typedef typename Impl::CPUPol CPUPol;
+ typedef typename Impl::DynInstPtr DynInstPtr;
+ typedef typename Impl::FullCPU FullCPU;
+ typedef typename Impl::Params Params;
+
+ typedef typename CPUPol::FetchStruct FetchStruct;
+ typedef typename CPUPol::DecodeStruct DecodeStruct;
+ typedef typename CPUPol::RenameStruct RenameStruct;
+ typedef typename CPUPol::TimeStruct TimeStruct;
+
+ // Typedefs from the CPUPol
+ typedef typename CPUPol::FreeList FreeList;
+ typedef typename CPUPol::RenameMap RenameMap;
+
+ // Typedefs from the ISA.
+ typedef TheISA::RegIndex RegIndex;
+
+ public:
+ // Rename will block if ROB becomes full or issue queue becomes full,
+ // or there are no free registers to rename to.
+ // Only case where rename squashes is if IEW squashes.
+ enum Status {
+ Running,
+ Idle,
+ Squashing,
+ Blocked,
+ Unblocking,
+ BarrierStall
+ };
+
+ private:
+ Status _status;
+
+ public:
+ SimpleRename(Params &params);
+
+ void regStats();
+
+ void setCPU(FullCPU *cpu_ptr);
+
+ void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr);
+
+ void setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr);
+
+ void setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr);
+
+ void setRenameMap(RenameMap *rm_ptr);
+
+ void setFreeList(FreeList *fl_ptr);
+
+ void dumpHistory();
+
+ void tick();
+
+ void rename();
+
+ void squash();
+
+ private:
+ void block();
+
+ inline void unblock();
+
+ void doSquash();
+
+ void removeFromHistory(InstSeqNum inst_seq_num);
+
+ inline void renameSrcRegs(DynInstPtr &inst);
+
+ inline void renameDestRegs(DynInstPtr &inst);
+
+ inline int calcFreeROBEntries();
+
+ inline int calcFreeIQEntries();
+
+ /** Holds the previous information for each rename.
+ * Note that often times the inst may have been deleted, so only access
+ * the pointer for the address and do not dereference it.
+ */
+ struct RenameHistory {
+ RenameHistory(InstSeqNum _instSeqNum, RegIndex _archReg,
+ PhysRegIndex _newPhysReg, PhysRegIndex _prevPhysReg)
+ : instSeqNum(_instSeqNum), archReg(_archReg),
+ newPhysReg(_newPhysReg), prevPhysReg(_prevPhysReg),
+ placeHolder(false)
+ {
+ }
+
+ /** Constructor used specifically for cases where a place holder
+ * rename history entry is being made.
+ */
+ RenameHistory(InstSeqNum _instSeqNum)
+ : instSeqNum(_instSeqNum), archReg(0), newPhysReg(0),
+ prevPhysReg(0), placeHolder(true)
+ {
+ }
+
+ InstSeqNum instSeqNum;
+ RegIndex archReg;
+ PhysRegIndex newPhysReg;
+ PhysRegIndex prevPhysReg;
+ bool placeHolder;
+ };
+
+ std::list<RenameHistory> historyBuffer;
+
+ /** CPU interface. */
+ FullCPU *cpu;
+
+ // Interfaces to objects outside of rename.
+ /** Time buffer interface. */
+ TimeBuffer<TimeStruct> *timeBuffer;
+
+ /** Wire to get IEW's output from backwards time buffer. */
+ typename TimeBuffer<TimeStruct>::wire fromIEW;
+
+ /** Wire to get commit's output from backwards time buffer. */
+ typename TimeBuffer<TimeStruct>::wire fromCommit;
+
+ /** Wire to write infromation heading to previous stages. */
+ // Might not be the best name as not only decode will read it.
+ typename TimeBuffer<TimeStruct>::wire toDecode;
+
+ /** Rename instruction queue. */
+ TimeBuffer<RenameStruct> *renameQueue;
+
+ /** Wire to write any information heading to IEW. */
+ typename TimeBuffer<RenameStruct>::wire toIEW;
+
+ /** Decode instruction queue interface. */
+ TimeBuffer<DecodeStruct> *decodeQueue;
+
+ /** Wire to get decode's output from decode queue. */
+ typename TimeBuffer<DecodeStruct>::wire fromDecode;
+
+ /** Skid buffer between rename and decode. */
+ std::queue<DecodeStruct> skidBuffer;
+
+ /** Rename map interface. */
+ SimpleRenameMap *renameMap;
+
+ /** Free list interface. */
+ FreeList *freeList;
+
+ /** Delay between iew and rename, in ticks. */
+ int iewToRenameDelay;
+
+ /** Delay between decode and rename, in ticks. */
+ int decodeToRenameDelay;
+
+ /** Delay between commit and rename, in ticks. */
+ unsigned commitToRenameDelay;
+
+ /** Rename width, in instructions. */
+ unsigned renameWidth;
+
+ /** Commit width, in instructions. Used so rename knows how many
+ * instructions might have freed registers in the previous cycle.
+ */
+ unsigned commitWidth;
+
+ /** The instruction that rename is currently on. It needs to have
+ * persistent state so that when a stall occurs in the middle of a
+ * group of instructions, it can restart at the proper instruction.
+ */
+ unsigned numInst;
+
+ Stats::Scalar<> renameSquashCycles;
+ Stats::Scalar<> renameIdleCycles;
+ Stats::Scalar<> renameBlockCycles;
+ Stats::Scalar<> renameUnblockCycles;
+ Stats::Scalar<> renameRenamedInsts;
+ Stats::Scalar<> renameSquashedInsts;
+ Stats::Scalar<> renameROBFullEvents;
+ Stats::Scalar<> renameIQFullEvents;
+ Stats::Scalar<> renameFullRegistersEvents;
+ Stats::Scalar<> renameRenamedOperands;
+ Stats::Scalar<> renameRenameLookups;
+ Stats::Scalar<> renameHBPlaceHolders;
+ Stats::Scalar<> renameCommittedMaps;
+ Stats::Scalar<> renameUndoneMaps;
+ Stats::Scalar<> renameValidUndoneMaps;
+};
+
+#endif // __CPU_O3_CPU_SIMPLE_RENAME_HH__
diff --git a/src/cpu/o3/rename_impl.hh b/src/cpu/o3/rename_impl.hh
new file mode 100644
index 000000000..2068b36ab
--- /dev/null
+++ b/src/cpu/o3/rename_impl.hh
@@ -0,0 +1,754 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <list>
+
+#include "config/full_system.hh"
+#include "cpu/o3/rename.hh"
+
+template <class Impl>
+SimpleRename<Impl>::SimpleRename(Params &params)
+ : iewToRenameDelay(params.iewToRenameDelay),
+ decodeToRenameDelay(params.decodeToRenameDelay),
+ commitToRenameDelay(params.commitToRenameDelay),
+ renameWidth(params.renameWidth),
+ commitWidth(params.commitWidth),
+ numInst(0)
+{
+ _status = Idle;
+}
+
+template <class Impl>
+void
+SimpleRename<Impl>::regStats()
+{
+ renameSquashCycles
+ .name(name() + ".renameSquashCycles")
+ .desc("Number of cycles rename is squashing")
+ .prereq(renameSquashCycles);
+ renameIdleCycles
+ .name(name() + ".renameIdleCycles")
+ .desc("Number of cycles rename is idle")
+ .prereq(renameIdleCycles);
+ renameBlockCycles
+ .name(name() + ".renameBlockCycles")
+ .desc("Number of cycles rename is blocking")
+ .prereq(renameBlockCycles);
+ renameUnblockCycles
+ .name(name() + ".renameUnblockCycles")
+ .desc("Number of cycles rename is unblocking")
+ .prereq(renameUnblockCycles);
+ renameRenamedInsts
+ .name(name() + ".renameRenamedInsts")
+ .desc("Number of instructions processed by rename")
+ .prereq(renameRenamedInsts);
+ renameSquashedInsts
+ .name(name() + ".renameSquashedInsts")
+ .desc("Number of squashed instructions processed by rename")
+ .prereq(renameSquashedInsts);
+ renameROBFullEvents
+ .name(name() + ".renameROBFullEvents")
+ .desc("Number of times rename has considered the ROB 'full'")
+ .prereq(renameROBFullEvents);
+ renameIQFullEvents
+ .name(name() + ".renameIQFullEvents")
+ .desc("Number of times rename has considered the IQ 'full'")
+ .prereq(renameIQFullEvents);
+ renameFullRegistersEvents
+ .name(name() + ".renameFullRegisterEvents")
+ .desc("Number of times there has been no free registers")
+ .prereq(renameFullRegistersEvents);
+ renameRenamedOperands
+ .name(name() + ".renameRenamedOperands")
+ .desc("Number of destination operands rename has renamed")
+ .prereq(renameRenamedOperands);
+ renameRenameLookups
+ .name(name() + ".renameRenameLookups")
+ .desc("Number of register rename lookups that rename has made")
+ .prereq(renameRenameLookups);
+ renameHBPlaceHolders
+ .name(name() + ".renameHBPlaceHolders")
+ .desc("Number of place holders added to the history buffer")
+ .prereq(renameHBPlaceHolders);
+ renameCommittedMaps
+ .name(name() + ".renameCommittedMaps")
+ .desc("Number of HB maps that are committed")
+ .prereq(renameCommittedMaps);
+ renameUndoneMaps
+ .name(name() + ".renameUndoneMaps")
+ .desc("Number of HB maps that are undone due to squashing")
+ .prereq(renameUndoneMaps);
+ renameValidUndoneMaps
+ .name(name() + ".renameValidUndoneMaps")
+ .desc("Number of HB maps that are undone, and are not place holders")
+ .prereq(renameValidUndoneMaps);
+}
+
+template <class Impl>
+void
+SimpleRename<Impl>::setCPU(FullCPU *cpu_ptr)
+{
+ DPRINTF(Rename, "Rename: Setting CPU pointer.\n");
+ cpu = cpu_ptr;
+}
+
+template <class Impl>
+void
+SimpleRename<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
+{
+ DPRINTF(Rename, "Rename: Setting time buffer pointer.\n");
+ timeBuffer = tb_ptr;
+
+ // Setup wire to read information from time buffer, from IEW stage.
+ fromIEW = timeBuffer->getWire(-iewToRenameDelay);
+
+ // Setup wire to read infromation from time buffer, from commit stage.
+ fromCommit = timeBuffer->getWire(-commitToRenameDelay);
+
+ // Setup wire to write information to previous stages.
+ toDecode = timeBuffer->getWire(0);
+}
+
+template <class Impl>
+void
+SimpleRename<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr)
+{
+ DPRINTF(Rename, "Rename: Setting rename queue pointer.\n");
+ renameQueue = rq_ptr;
+
+ // Setup wire to write information to future stages.
+ toIEW = renameQueue->getWire(0);
+}
+
+template <class Impl>
+void
+SimpleRename<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr)
+{
+ DPRINTF(Rename, "Rename: Setting decode queue pointer.\n");
+ decodeQueue = dq_ptr;
+
+ // Setup wire to get information from decode.
+ fromDecode = decodeQueue->getWire(-decodeToRenameDelay);
+}
+
+template <class Impl>
+void
+SimpleRename<Impl>::setRenameMap(RenameMap *rm_ptr)
+{
+ DPRINTF(Rename, "Rename: Setting rename map pointer.\n");
+ renameMap = rm_ptr;
+}
+
+template <class Impl>
+void
+SimpleRename<Impl>::setFreeList(FreeList *fl_ptr)
+{
+ DPRINTF(Rename, "Rename: Setting free list pointer.\n");
+ freeList = fl_ptr;
+}
+
+template <class Impl>
+void
+SimpleRename<Impl>::dumpHistory()
+{
+ typename list<RenameHistory>::iterator buf_it = historyBuffer.begin();
+
+ while (buf_it != historyBuffer.end())
+ {
+ cprintf("Seq num: %i\nArch reg: %i New phys reg: %i Old phys "
+ "reg: %i\n", (*buf_it).instSeqNum, (int)(*buf_it).archReg,
+ (int)(*buf_it).newPhysReg, (int)(*buf_it).prevPhysReg);
+
+ buf_it++;
+ }
+}
+
+template <class Impl>
+void
+SimpleRename<Impl>::block()
+{
+ DPRINTF(Rename, "Rename: Blocking.\n");
+ // Set status to Blocked.
+ _status = Blocked;
+
+ // Add the current inputs onto the skid buffer, so they can be
+ // reprocessed when this stage unblocks.
+ skidBuffer.push(*fromDecode);
+
+ // Note that this stage only signals previous stages to stall when
+ // it is the cause of the stall originates at this stage. Otherwise
+ // the previous stages are expected to check all possible stall signals.
+}
+
+template <class Impl>
+inline void
+SimpleRename<Impl>::unblock()
+{
+ DPRINTF(Rename, "Rename: Read instructions out of skid buffer this "
+ "cycle.\n");
+ // Remove the now processed instructions from the skid buffer.
+ skidBuffer.pop();
+
+ // If there's still information in the skid buffer, then
+ // continue to tell previous stages to stall. They will be
+ // able to restart once the skid buffer is empty.
+ if (!skidBuffer.empty()) {
+ toDecode->renameInfo.stall = true;
+ } else {
+ DPRINTF(Rename, "Rename: Done unblocking.\n");
+ _status = Running;
+ }
+}
+
+template <class Impl>
+void
+SimpleRename<Impl>::doSquash()
+{
+ typename list<RenameHistory>::iterator hb_it = historyBuffer.begin();
+
+ InstSeqNum squashed_seq_num = fromCommit->commitInfo.doneSeqNum;
+
+#if FULL_SYSTEM
+ assert(!historyBuffer.empty());
+#else
+ // After a syscall squashes everything, the history buffer may be empty
+ // but the ROB may still be squashing instructions.
+ if (historyBuffer.empty()) {
+ return;
+ }
+#endif // FULL_SYSTEM
+
+ // Go through the most recent instructions, undoing the mappings
+ // they did and freeing up the registers.
+ while ((*hb_it).instSeqNum > squashed_seq_num)
+ {
+ assert(hb_it != historyBuffer.end());
+
+ DPRINTF(Rename, "Rename: Removing history entry with sequence "
+ "number %i.\n", (*hb_it).instSeqNum);
+
+ // If it's not simply a place holder, then add the registers.
+ if (!(*hb_it).placeHolder) {
+ // Tell the rename map to set the architected register to the
+ // previous physical register that it was renamed to.
+ renameMap->setEntry(hb_it->archReg, hb_it->prevPhysReg);
+
+ // Put the renamed physical register back on the free list.
+ freeList->addReg(hb_it->newPhysReg);
+
+ ++renameValidUndoneMaps;
+ }
+
+ historyBuffer.erase(hb_it++);
+
+ ++renameUndoneMaps;
+ }
+}
+
+template <class Impl>
+void
+SimpleRename<Impl>::squash()
+{
+ DPRINTF(Rename, "Rename: Squashing instructions.\n");
+ // Set the status to Squashing.
+ _status = Squashing;
+
+ numInst = 0;
+
+ // Clear the skid buffer in case it has any data in it.
+ while (!skidBuffer.empty())
+ {
+ skidBuffer.pop();
+ }
+
+ doSquash();
+}
+
+template<class Impl>
+void
+SimpleRename<Impl>::removeFromHistory(InstSeqNum inst_seq_num)
+{
+ DPRINTF(Rename, "Rename: Removing a committed instruction from the "
+ "history buffer, until sequence number %lli.\n", inst_seq_num);
+ typename list<RenameHistory>::iterator hb_it = historyBuffer.end();
+
+ --hb_it;
+
+ if (hb_it->instSeqNum > inst_seq_num) {
+ DPRINTF(Rename, "Rename: Old sequence number encountered. Ensure "
+ "that a syscall happened recently.\n");
+ return;
+ }
+
+ while ((*hb_it).instSeqNum != inst_seq_num)
+ {
+ // Make sure we haven't gone off the end of the list.
+ assert(hb_it != historyBuffer.end());
+
+ // In theory instructions at the end of the history buffer
+ // should be older than the instruction being removed, which
+ // means they will have a lower sequence number. Also the
+ // instruction being removed from the history really should
+ // be the last instruction in the list, as it is the instruction
+ // that was just committed that is being removed.
+ assert(hb_it->instSeqNum < inst_seq_num);
+ DPRINTF(Rename, "Rename: Freeing up older rename of reg %i, sequence"
+ " number %i.\n",
+ (*hb_it).prevPhysReg, (*hb_it).instSeqNum);
+
+ if (!(*hb_it).placeHolder) {
+ freeList->addReg((*hb_it).prevPhysReg);
+ ++renameCommittedMaps;
+ }
+
+ historyBuffer.erase(hb_it--);
+ }
+
+ // Finally free up the previous register of the finished instruction
+ // itself.
+ if (!(*hb_it).placeHolder) {
+ freeList->addReg(hb_it->prevPhysReg);
+ ++renameCommittedMaps;
+ }
+
+ historyBuffer.erase(hb_it);
+}
+
+template <class Impl>
+inline void
+SimpleRename<Impl>::renameSrcRegs(DynInstPtr &inst)
+{
+ unsigned num_src_regs = inst->numSrcRegs();
+
+ // Get the architectual register numbers from the source and
+ // destination operands, and redirect them to the right register.
+ // Will need to mark dependencies though.
+ for (int src_idx = 0; src_idx < num_src_regs; src_idx++)
+ {
+ RegIndex src_reg = inst->srcRegIdx(src_idx);
+
+ // Look up the source registers to get the phys. register they've
+ // been renamed to, and set the sources to those registers.
+ PhysRegIndex renamed_reg = renameMap->lookup(src_reg);
+
+ DPRINTF(Rename, "Rename: Looking up arch reg %i, got "
+ "physical reg %i.\n", (int)src_reg, (int)renamed_reg);
+
+ inst->renameSrcReg(src_idx, renamed_reg);
+
+ // Either incorporate it into the info passed back,
+ // or make another function call to see if that register is
+ // ready or not.
+ if (renameMap->isReady(renamed_reg)) {
+ DPRINTF(Rename, "Rename: Register is ready.\n");
+
+ inst->markSrcRegReady(src_idx);
+ }
+
+ ++renameRenameLookups;
+ }
+}
+
+template <class Impl>
+inline void
+SimpleRename<Impl>::renameDestRegs(DynInstPtr &inst)
+{
+ typename SimpleRenameMap::RenameInfo rename_result;
+
+ unsigned num_dest_regs = inst->numDestRegs();
+
+ // If it's an instruction with no destination registers, then put
+ // a placeholder within the history buffer. It might be better
+ // to not put it in the history buffer at all (other than branches,
+ // which always need at least a place holder), and differentiate
+ // between instructions with and without destination registers
+ // when getting from commit the instructions that committed.
+ if (num_dest_regs == 0) {
+ RenameHistory hb_entry(inst->seqNum);
+
+ historyBuffer.push_front(hb_entry);
+
+ DPRINTF(Rename, "Rename: Adding placeholder instruction to "
+ "history buffer, sequence number %lli.\n",
+ inst->seqNum);
+
+ ++renameHBPlaceHolders;
+ } else {
+
+ // Rename the destination registers.
+ for (int dest_idx = 0; dest_idx < num_dest_regs; dest_idx++)
+ {
+ RegIndex dest_reg = inst->destRegIdx(dest_idx);
+
+ // Get the physical register that the destination will be
+ // renamed to.
+ rename_result = renameMap->rename(dest_reg);
+
+ DPRINTF(Rename, "Rename: Renaming arch reg %i to physical "
+ "reg %i.\n", (int)dest_reg,
+ (int)rename_result.first);
+
+ // Record the rename information so that a history can be kept.
+ RenameHistory hb_entry(inst->seqNum, dest_reg,
+ rename_result.first,
+ rename_result.second);
+
+ historyBuffer.push_front(hb_entry);
+
+ DPRINTF(Rename, "Rename: Adding instruction to history buffer, "
+ "sequence number %lli.\n",
+ (*historyBuffer.begin()).instSeqNum);
+
+ // Tell the instruction to rename the appropriate destination
+ // register (dest_idx) to the new physical register
+ // (rename_result.first), and record the previous physical
+ // register that the same logical register was renamed to
+ // (rename_result.second).
+ inst->renameDestReg(dest_idx,
+ rename_result.first,
+ rename_result.second);
+
+ ++renameRenamedOperands;
+ }
+ }
+}
+
+template <class Impl>
+inline int
+SimpleRename<Impl>::calcFreeROBEntries()
+{
+ return fromCommit->commitInfo.freeROBEntries -
+ renameWidth * iewToRenameDelay;
+}
+
+template <class Impl>
+inline int
+SimpleRename<Impl>::calcFreeIQEntries()
+{
+ return fromIEW->iewInfo.freeIQEntries - renameWidth * iewToRenameDelay;
+}
+
+template<class Impl>
+void
+SimpleRename<Impl>::tick()
+{
+ // Rename will need to try to rename as many instructions as it
+ // has bandwidth, unless it is blocked.
+
+ // Check if _status is BarrierStall. If so, then check if the number
+ // of free ROB entries is equal to the number of total ROB entries.
+ // Once equal then wake this stage up. Set status to unblocking maybe.
+
+ if (_status != Blocked && _status != Squashing) {
+ DPRINTF(Rename, "Rename: Status is not blocked, will attempt to "
+ "run stage.\n");
+ // Make sure that the skid buffer has something in it if the
+ // status is unblocking.
+ assert(_status == Unblocking ? !skidBuffer.empty() : 1);
+
+ rename();
+
+ // If the status was unblocking, then instructions from the skid
+ // buffer were used. Remove those instructions and handle
+ // the rest of unblocking.
+ if (_status == Unblocking) {
+ ++renameUnblockCycles;
+
+ if (fromDecode->size > 0) {
+ // Add the current inputs onto the skid buffer, so they can be
+ // reprocessed when this stage unblocks.
+ skidBuffer.push(*fromDecode);
+ }
+
+ unblock();
+ }
+ } else if (_status == Blocked) {
+ ++renameBlockCycles;
+
+ // If stage is blocked and still receiving valid instructions,
+ // make sure to store them in the skid buffer.
+ if (fromDecode->size > 0) {
+
+ block();
+
+ // Continue to tell previous stage to stall.
+ toDecode->renameInfo.stall = true;
+ }
+
+ if (!fromIEW->iewInfo.stall &&
+ !fromCommit->commitInfo.stall &&
+ calcFreeROBEntries() > 0 &&
+ calcFreeIQEntries() > 0 &&
+ renameMap->numFreeEntries() > 0) {
+
+ // Need to be sure to check all blocking conditions above.
+ // If they have cleared, then start unblocking.
+ DPRINTF(Rename, "Rename: Stall signals cleared, going to "
+ "unblock.\n");
+ _status = Unblocking;
+
+ // Continue to tell previous stage to block until this stage
+ // is done unblocking.
+ toDecode->renameInfo.stall = true;
+ } else {
+ // Otherwise no conditions have changed. Tell previous
+ // stage to continue blocking.
+ toDecode->renameInfo.stall = true;
+ }
+
+ if (fromCommit->commitInfo.squash ||
+ fromCommit->commitInfo.robSquashing) {
+ squash();
+ return;
+ }
+ } else if (_status == Squashing) {
+ ++renameSquashCycles;
+
+ if (fromCommit->commitInfo.squash) {
+ squash();
+ } else if (!fromCommit->commitInfo.squash &&
+ !fromCommit->commitInfo.robSquashing) {
+
+ DPRINTF(Rename, "Rename: Done squashing, going to running.\n");
+ _status = Running;
+ rename();
+ } else {
+ doSquash();
+ }
+ }
+
+ // Ugly code, revamp all of the tick() functions eventually.
+ if (fromCommit->commitInfo.doneSeqNum != 0 && _status != Squashing) {
+#if !FULL_SYSTEM
+ if (!fromCommit->commitInfo.squash) {
+ removeFromHistory(fromCommit->commitInfo.doneSeqNum);
+ }
+#else
+ removeFromHistory(fromCommit->commitInfo.doneSeqNum);
+#endif
+ }
+
+}
+
+template<class Impl>
+void
+SimpleRename<Impl>::rename()
+{
+ // Check if any of the stages ahead of rename are telling rename
+ // to squash. The squash() function will also take care of fixing up
+ // the rename map and the free list.
+ if (fromCommit->commitInfo.squash ||
+ fromCommit->commitInfo.robSquashing) {
+ DPRINTF(Rename, "Rename: Receiving signal from Commit to squash.\n");
+ squash();
+ return;
+ }
+
+ // Check if time buffer is telling this stage to stall.
+ if (fromIEW->iewInfo.stall ||
+ fromCommit->commitInfo.stall) {
+ DPRINTF(Rename, "Rename: Receiving signal from IEW/Commit to "
+ "stall.\n");
+ block();
+ return;
+ }
+
+ // Check if the current status is squashing. If so, set its status
+ // to running and resume execution the next cycle.
+ if (_status == Squashing) {
+ DPRINTF(Rename, "Rename: Done squashing.\n");
+ _status = Running;
+ return;
+ }
+
+ // Check the decode queue to see if instructions are available.
+ // If there are no available instructions to rename, then do nothing.
+ // Or, if the stage is currently unblocking, then go ahead and run it.
+ if (fromDecode->size == 0 && _status != Unblocking) {
+ DPRINTF(Rename, "Rename: Nothing to do, breaking out early.\n");
+ // Should I change status to idle?
+ return;
+ }
+
+ ////////////////////////////////////
+ // Actual rename part.
+ ////////////////////////////////////
+
+ DynInstPtr inst;
+
+ // If we're unblocking, then we may be in the middle of an instruction
+ // group. Subtract off numInst to get the proper number of instructions
+ // left.
+ int insts_available = _status == Unblocking ?
+ skidBuffer.front().size - numInst :
+ fromDecode->size;
+
+ bool block_this_cycle = false;
+
+ // Will have to do a different calculation for the number of free
+ // entries. Number of free entries recorded on this cycle -
+ // renameWidth * renameToDecodeDelay
+ int free_rob_entries = calcFreeROBEntries();
+ int free_iq_entries = calcFreeIQEntries();
+ int min_iq_rob = min(free_rob_entries, free_iq_entries);
+
+ unsigned to_iew_index = 0;
+
+ // Check if there's any space left.
+ if (min_iq_rob <= 0) {
+ DPRINTF(Rename, "Rename: Blocking due to no free ROB or IQ "
+ "entries.\n"
+ "Rename: ROB has %d free entries.\n"
+ "Rename: IQ has %d free entries.\n",
+ free_rob_entries,
+ free_iq_entries);
+ block();
+ // Tell previous stage to stall.
+ toDecode->renameInfo.stall = true;
+
+ if (free_rob_entries <= 0) {
+ ++renameROBFullEvents;
+ } else {
+ ++renameIQFullEvents;
+ }
+
+ return;
+ } else if (min_iq_rob < insts_available) {
+ DPRINTF(Rename, "Rename: Will have to block this cycle. Only "
+ "%i insts can be renamed due to IQ/ROB limits.\n",
+ min_iq_rob);
+
+ insts_available = min_iq_rob;
+
+ block_this_cycle = true;
+
+ if (free_rob_entries < free_iq_entries) {
+ ++renameROBFullEvents;
+ } else {
+ ++renameIQFullEvents;
+ }
+ }
+
+ while (insts_available > 0) {
+ DPRINTF(Rename, "Rename: Sending instructions to iew.\n");
+
+ // Get the next instruction either from the skid buffer or the
+ // decode queue.
+ inst = _status == Unblocking ? skidBuffer.front().insts[numInst] :
+ fromDecode->insts[numInst];
+
+ if (inst->isSquashed()) {
+ DPRINTF(Rename, "Rename: instruction %i with PC %#x is "
+ "squashed, skipping.\n",
+ inst->seqNum, inst->readPC());
+
+ // Go to the next instruction.
+ ++numInst;
+
+ ++renameSquashedInsts;
+
+ // Decrement how many instructions are available.
+ --insts_available;
+
+ continue;
+ }
+
+ DPRINTF(Rename, "Rename: Processing instruction %i with PC %#x.\n",
+ inst->seqNum, inst->readPC());
+
+ // If it's a trap instruction, then it needs to wait here within
+ // rename until the ROB is empty. Needs a way to detect that the
+ // ROB is empty. Maybe an event?
+ // Would be nice if it could be avoided putting this into a
+ // specific stage and instead just put it into the AlphaFullCPU.
+ // Might not really be feasible though...
+ // (EXCB, TRAPB)
+ if (inst->isSerializing()) {
+ panic("Rename: Serializing instruction encountered.\n");
+ DPRINTF(Rename, "Rename: Serializing instruction "
+ "encountered.\n");
+
+ // Change status over to BarrierStall so that other stages know
+ // what this is blocked on.
+ _status = BarrierStall;
+
+ block_this_cycle = true;
+
+ break;
+ }
+
+ // Check here to make sure there are enough destination registers
+ // to rename to. Otherwise block.
+ if (renameMap->numFreeEntries() < inst->numDestRegs())
+ {
+ DPRINTF(Rename, "Rename: Blocking due to lack of free "
+ "physical registers to rename to.\n");
+ // Need some sort of event based on a register being freed.
+
+ block_this_cycle = true;
+
+ ++renameFullRegistersEvents;
+
+ break;
+ }
+
+ renameSrcRegs(inst);
+
+ renameDestRegs(inst);
+
+ // Put instruction in rename queue.
+ toIEW->insts[to_iew_index] = inst;
+ ++(toIEW->size);
+
+ // Decrease the number of free ROB and IQ entries.
+ --free_rob_entries;
+ --free_iq_entries;
+
+ // Increment which instruction we're on.
+ ++to_iew_index;
+ ++numInst;
+
+ ++renameRenamedInsts;
+
+ // Decrement how many instructions are available.
+ --insts_available;
+ }
+
+ // Check if there's any instructions left that haven't yet been renamed.
+ // If so then block.
+ if (block_this_cycle) {
+ block();
+
+ toDecode->renameInfo.stall = true;
+ } else {
+ // If we had a successful rename and didn't have to exit early, then
+ // reset numInst so it will refer to the correct instruction on next
+ // run.
+ numInst = 0;
+ }
+}
diff --git a/src/cpu/o3/rename_map.cc b/src/cpu/o3/rename_map.cc
new file mode 100644
index 000000000..10963f7de
--- /dev/null
+++ b/src/cpu/o3/rename_map.cc
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <vector>
+
+#include "cpu/o3/rename_map.hh"
+
+using namespace std;
+
+// Todo: Consider making functions inline. Avoid having things that are
+// using the zero register or misc registers from adding on the registers
+// to the free list. Possibly remove the direct communication between
+// this and the freelist. Considering making inline bool functions that
+// determine if the register is a logical int, logical fp, physical int,
+// physical fp, etc.
+
+SimpleRenameMap::SimpleRenameMap(unsigned _numLogicalIntRegs,
+ unsigned _numPhysicalIntRegs,
+ unsigned _numLogicalFloatRegs,
+ unsigned _numPhysicalFloatRegs,
+ unsigned _numMiscRegs,
+ RegIndex _intZeroReg,
+ RegIndex _floatZeroReg)
+ : numLogicalIntRegs(_numLogicalIntRegs),
+ numPhysicalIntRegs(_numPhysicalIntRegs),
+ numLogicalFloatRegs(_numLogicalFloatRegs),
+ numPhysicalFloatRegs(_numPhysicalFloatRegs),
+ numMiscRegs(_numMiscRegs),
+ intZeroReg(_intZeroReg),
+ floatZeroReg(_floatZeroReg)
+{
+ DPRINTF(Rename, "Rename: Creating rename map. Phys: %i / %i, Float: "
+ "%i / %i.\n", numLogicalIntRegs, numPhysicalIntRegs,
+ numLogicalFloatRegs, numPhysicalFloatRegs);
+
+ numLogicalRegs = numLogicalIntRegs + numLogicalFloatRegs;
+
+ numPhysicalRegs = numPhysicalIntRegs + numPhysicalFloatRegs;
+
+ //Create the rename maps, and their scoreboards.
+ intRenameMap = new RenameEntry[numLogicalIntRegs];
+ floatRenameMap = new RenameEntry[numLogicalRegs];
+
+ // Should combine this into one scoreboard.
+ intScoreboard.resize(numPhysicalIntRegs);
+ floatScoreboard.resize(numPhysicalRegs);
+ miscScoreboard.resize(numPhysicalRegs + numMiscRegs);
+
+ // Initialize the entries in the integer rename map to point to the
+ // physical registers of the same index, and consider each register
+ // ready until the first rename occurs.
+ for (RegIndex index = 0; index < numLogicalIntRegs; ++index)
+ {
+ intRenameMap[index].physical_reg = index;
+ intScoreboard[index] = 1;
+ }
+
+ // Initialize the rest of the physical registers (the ones that don't
+ // directly map to a logical register) as unready.
+ for (PhysRegIndex index = numLogicalIntRegs;
+ index < numPhysicalIntRegs;
+ ++index)
+ {
+ intScoreboard[index] = 0;
+ }
+
+ int float_reg_idx = numPhysicalIntRegs;
+
+ // Initialize the entries in the floating point rename map to point to
+ // the physical registers of the same index, and consider each register
+ // ready until the first rename occurs.
+ // Although the index refers purely to architected registers, because
+ // the floating reg indices come after the integer reg indices, they
+ // may exceed the size of a normal RegIndex (short).
+ for (PhysRegIndex index = numLogicalIntRegs;
+ index < numLogicalRegs; ++index)
+ {
+ floatRenameMap[index].physical_reg = float_reg_idx++;
+ }
+
+ for (PhysRegIndex index = numPhysicalIntRegs;
+ index < numPhysicalIntRegs + numLogicalFloatRegs; ++index)
+ {
+ floatScoreboard[index] = 1;
+ }
+
+ // Initialize the rest of the physical registers (the ones that don't
+ // directly map to a logical register) as unready.
+ for (PhysRegIndex index = numPhysicalIntRegs + numLogicalFloatRegs;
+ index < numPhysicalRegs;
+ ++index)
+ {
+ floatScoreboard[index] = 0;
+ }
+
+ // Initialize the entries in the misc register scoreboard to be ready.
+ for (PhysRegIndex index = numPhysicalRegs;
+ index < numPhysicalRegs + numMiscRegs; ++index)
+ {
+ miscScoreboard[index] = 1;
+ }
+}
+
+SimpleRenameMap::~SimpleRenameMap()
+{
+ // Delete the rename maps as they were allocated with new.
+ delete [] intRenameMap;
+ delete [] floatRenameMap;
+}
+
+void
+SimpleRenameMap::setFreeList(SimpleFreeList *fl_ptr)
+{
+ //Setup the interface to the freelist.
+ freeList = fl_ptr;
+}
+
+
+// Don't allow this stage to fault; force that check to the rename stage.
+// Simply ask to rename a logical register and get back a new physical
+// register index.
+SimpleRenameMap::RenameInfo
+SimpleRenameMap::rename(RegIndex arch_reg)
+{
+ PhysRegIndex renamed_reg;
+ PhysRegIndex prev_reg;
+
+ if (arch_reg < numLogicalIntRegs) {
+
+ // Record the current physical register that is renamed to the
+ // requested architected register.
+ prev_reg = intRenameMap[arch_reg].physical_reg;
+
+ // If it's not referencing the zero register, then mark the register
+ // as not ready.
+ if (arch_reg != intZeroReg) {
+ // Get a free physical register to rename to.
+ renamed_reg = freeList->getIntReg();
+
+ // Update the integer rename map.
+ intRenameMap[arch_reg].physical_reg = renamed_reg;
+
+ assert(renamed_reg >= 0 && renamed_reg < numPhysicalIntRegs);
+
+ // Mark register as not ready.
+ intScoreboard[renamed_reg] = false;
+ } else {
+ // Otherwise return the zero register so nothing bad happens.
+ renamed_reg = intZeroReg;
+ }
+ } else if (arch_reg < numLogicalRegs) {
+ // Subtract off the base offset for floating point registers.
+// arch_reg = arch_reg - numLogicalIntRegs;
+
+ // Record the current physical register that is renamed to the
+ // requested architected register.
+ prev_reg = floatRenameMap[arch_reg].physical_reg;
+
+ // If it's not referencing the zero register, then mark the register
+ // as not ready.
+ if (arch_reg != floatZeroReg) {
+ // Get a free floating point register to rename to.
+ renamed_reg = freeList->getFloatReg();
+
+ // Update the floating point rename map.
+ floatRenameMap[arch_reg].physical_reg = renamed_reg;
+
+ assert(renamed_reg < numPhysicalRegs &&
+ renamed_reg >= numPhysicalIntRegs);
+
+ // Mark register as not ready.
+ floatScoreboard[renamed_reg] = false;
+ } else {
+ // Otherwise return the zero register so nothing bad happens.
+ renamed_reg = floatZeroReg;
+ }
+ } else {
+ // Subtract off the base offset for miscellaneous registers.
+ arch_reg = arch_reg - numLogicalRegs;
+
+ // No renaming happens to the misc. registers. They are simply the
+ // registers that come after all the physical registers; thus
+ // take the base architected register and add the physical registers
+ // to it.
+ renamed_reg = arch_reg + numPhysicalRegs;
+
+ // Set the previous register to the same register; mainly it must be
+ // known that the prev reg was outside the range of normal registers
+ // so the free list can avoid adding it.
+ prev_reg = renamed_reg;
+
+ assert(renamed_reg < numPhysicalRegs + numMiscRegs);
+
+ miscScoreboard[renamed_reg] = false;
+ }
+
+ return RenameInfo(renamed_reg, prev_reg);
+}
+
+//Perhaps give this a pair as a return value, of the physical register
+//and whether or not it's ready.
+PhysRegIndex
+SimpleRenameMap::lookup(RegIndex arch_reg)
+{
+ if (arch_reg < numLogicalIntRegs) {
+ return intRenameMap[arch_reg].physical_reg;
+ } else if (arch_reg < numLogicalRegs) {
+ // Subtract off the base FP offset.
+// arch_reg = arch_reg - numLogicalIntRegs;
+
+ return floatRenameMap[arch_reg].physical_reg;
+ } else {
+ // Subtract off the misc registers offset.
+ arch_reg = arch_reg - numLogicalRegs;
+
+ // Misc. regs don't rename, so simply add the base arch reg to
+ // the number of physical registers.
+ return numPhysicalRegs + arch_reg;
+ }
+}
+
+bool
+SimpleRenameMap::isReady(PhysRegIndex phys_reg)
+{
+ if (phys_reg < numPhysicalIntRegs) {
+ return intScoreboard[phys_reg];
+ } else if (phys_reg < numPhysicalRegs) {
+
+ // Subtract off the base FP offset.
+// phys_reg = phys_reg - numPhysicalIntRegs;
+
+ return floatScoreboard[phys_reg];
+ } else {
+ // Subtract off the misc registers offset.
+// phys_reg = phys_reg - numPhysicalRegs;
+
+ return miscScoreboard[phys_reg];
+ }
+}
+
+// In this implementation the miscellaneous registers do not actually rename,
+// so this function does not allow you to try to change their mappings.
+void
+SimpleRenameMap::setEntry(RegIndex arch_reg, PhysRegIndex renamed_reg)
+{
+ if (arch_reg < numLogicalIntRegs) {
+ DPRINTF(Rename, "Rename Map: Integer register %i being set to %i.\n",
+ (int)arch_reg, renamed_reg);
+
+ intRenameMap[arch_reg].physical_reg = renamed_reg;
+ } else {
+ assert(arch_reg < (numLogicalIntRegs + numLogicalFloatRegs));
+
+ DPRINTF(Rename, "Rename Map: Float register %i being set to %i.\n",
+ (int)arch_reg - numLogicalIntRegs, renamed_reg);
+
+ floatRenameMap[arch_reg].physical_reg = renamed_reg;
+ }
+}
+
+void
+SimpleRenameMap::squash(vector<RegIndex> freed_regs,
+ vector<UnmapInfo> unmaps)
+{
+ panic("Not sure this function should be called.");
+
+ // Not sure the rename map should be able to access the free list
+ // like this.
+ while (!freed_regs.empty()) {
+ RegIndex free_register = freed_regs.back();
+
+ if (free_register < numPhysicalIntRegs) {
+ freeList->addIntReg(free_register);
+ } else {
+ // Subtract off the base FP dependence tag.
+ free_register = free_register - numPhysicalIntRegs;
+ freeList->addFloatReg(free_register);
+ }
+
+ freed_regs.pop_back();
+ }
+
+ // Take unmap info and roll back the rename map.
+}
+
+void
+SimpleRenameMap::markAsReady(PhysRegIndex ready_reg)
+{
+ DPRINTF(Rename, "Rename map: Marking register %i as ready.\n",
+ (int)ready_reg);
+
+ if (ready_reg < numPhysicalIntRegs) {
+ assert(ready_reg >= 0);
+
+ intScoreboard[ready_reg] = 1;
+ } else if (ready_reg < numPhysicalRegs) {
+
+ // Subtract off the base FP offset.
+// ready_reg = ready_reg - numPhysicalIntRegs;
+
+ floatScoreboard[ready_reg] = 1;
+ } else {
+ //Subtract off the misc registers offset.
+// ready_reg = ready_reg - numPhysicalRegs;
+
+ miscScoreboard[ready_reg] = 1;
+ }
+}
+
+int
+SimpleRenameMap::numFreeEntries()
+{
+ int free_int_regs = freeList->numFreeIntRegs();
+ int free_float_regs = freeList->numFreeFloatRegs();
+
+ if (free_int_regs < free_float_regs) {
+ return free_int_regs;
+ } else {
+ return free_float_regs;
+ }
+}
diff --git a/src/cpu/o3/rename_map.hh b/src/cpu/o3/rename_map.hh
new file mode 100644
index 000000000..57be4a64a
--- /dev/null
+++ b/src/cpu/o3/rename_map.hh
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Todo: Create destructor.
+// Have it so that there's a more meaningful name given to the variable
+// that marks the beginning of the FP registers.
+
+#ifndef __CPU_O3_CPU_RENAME_MAP_HH__
+#define __CPU_O3_CPU_RENAME_MAP_HH__
+
+#include <iostream>
+#include <utility>
+#include <vector>
+
+#include "cpu/o3/free_list.hh"
+//For RegIndex
+#include "arch/isa_traits.hh"
+
+class SimpleRenameMap
+{
+ protected:
+ typedef TheISA::RegIndex RegIndex;
+ public:
+ /**
+ * Pair of a logical register and a physical register. Tells the
+ * previous mapping of a logical register to a physical register.
+ * Used to roll back the rename map to a previous state.
+ */
+ typedef std::pair<RegIndex, PhysRegIndex> UnmapInfo;
+
+ /**
+ * Pair of a physical register and a physical register. Used to
+ * return the physical register that a logical register has been
+ * renamed to, and the previous physical register that the same
+ * logical register was previously mapped to.
+ */
+ typedef std::pair<PhysRegIndex, PhysRegIndex> RenameInfo;
+
+ public:
+ //Constructor
+ SimpleRenameMap(unsigned _numLogicalIntRegs,
+ unsigned _numPhysicalIntRegs,
+ unsigned _numLogicalFloatRegs,
+ unsigned _numPhysicalFloatRegs,
+ unsigned _numMiscRegs,
+ RegIndex _intZeroReg,
+ RegIndex _floatZeroReg);
+
+ /** Destructor. */
+ ~SimpleRenameMap();
+
+ void setFreeList(SimpleFreeList *fl_ptr);
+
+ //Tell rename map to get a free physical register for a given
+ //architected register. Not sure it should have a return value,
+ //but perhaps it should have some sort of fault in case there are
+ //no free registers.
+ RenameInfo rename(RegIndex arch_reg);
+
+ PhysRegIndex lookup(RegIndex phys_reg);
+
+ bool isReady(PhysRegIndex arch_reg);
+
+ /**
+ * Marks the given register as ready, meaning that its value has been
+ * calculated and written to the register file.
+ * @param ready_reg The index of the physical register that is now ready.
+ */
+ void markAsReady(PhysRegIndex ready_reg);
+
+ void setEntry(RegIndex arch_reg, PhysRegIndex renamed_reg);
+
+ void squash(std::vector<RegIndex> freed_regs,
+ std::vector<UnmapInfo> unmaps);
+
+ int numFreeEntries();
+
+ private:
+ /** Number of logical integer registers. */
+ int numLogicalIntRegs;
+
+ /** Number of physical integer registers. */
+ int numPhysicalIntRegs;
+
+ /** Number of logical floating point registers. */
+ int numLogicalFloatRegs;
+
+ /** Number of physical floating point registers. */
+ int numPhysicalFloatRegs;
+
+ /** Number of miscellaneous registers. */
+ int numMiscRegs;
+
+ /** Number of logical integer + float registers. */
+ int numLogicalRegs;
+
+ /** Number of physical integer + float registers. */
+ int numPhysicalRegs;
+
+ /** The integer zero register. This implementation assumes it is always
+ * zero and never can be anything else.
+ */
+ RegIndex intZeroReg;
+
+ /** The floating point zero register. This implementation assumes it is
+ * always zero and never can be anything else.
+ */
+ RegIndex floatZeroReg;
+
+ class RenameEntry
+ {
+ public:
+ PhysRegIndex physical_reg;
+ bool valid;
+
+ RenameEntry()
+ : physical_reg(0), valid(false)
+ { }
+ };
+
+ /** Integer rename map. */
+ RenameEntry *intRenameMap;
+
+ /** Floating point rename map. */
+ RenameEntry *floatRenameMap;
+
+ /** Free list interface. */
+ SimpleFreeList *freeList;
+
+ // Might want to make all these scoreboards into one large scoreboard.
+
+ /** Scoreboard of physical integer registers, saying whether or not they
+ * are ready.
+ */
+ std::vector<bool> intScoreboard;
+
+ /** Scoreboard of physical floating registers, saying whether or not they
+ * are ready.
+ */
+ std::vector<bool> floatScoreboard;
+
+ /** Scoreboard of miscellaneous registers, saying whether or not they
+ * are ready.
+ */
+ std::vector<bool> miscScoreboard;
+};
+
+#endif //__CPU_O3_CPU_RENAME_MAP_HH__
diff --git a/src/cpu/o3/rob.cc b/src/cpu/o3/rob.cc
new file mode 100644
index 000000000..c10f782fd
--- /dev/null
+++ b/src/cpu/o3/rob.cc
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "cpu/o3/alpha_dyn_inst.hh"
+#include "cpu/o3/alpha_impl.hh"
+#include "cpu/o3/rob_impl.hh"
+
+// Force instantiation of InstructionQueue.
+template class ROB<AlphaSimpleImpl>;
diff --git a/src/cpu/o3/rob.hh b/src/cpu/o3/rob.hh
new file mode 100644
index 000000000..1185564ad
--- /dev/null
+++ b/src/cpu/o3/rob.hh
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Todo: Probably add in support for scheduling events (more than one as
+// well) on the case of the ROB being empty or full. Considering tracking
+// free entries instead of insts in ROB. Differentiate between squashing
+// all instructions after the instruction, and all instructions after *and*
+// including that instruction.
+
+#ifndef __CPU_O3_CPU_ROB_HH__
+#define __CPU_O3_CPU_ROB_HH__
+
+#include <utility>
+#include <vector>
+
+/**
+ * ROB class. Uses the instruction list that exists within the CPU to
+ * represent the ROB. This class doesn't contain that list, but instead
+ * a pointer to the CPU to get access to the list. The ROB, in this first
+ * implementation, is largely what drives squashing.
+ */
+template <class Impl>
+class ROB
+{
+ protected:
+ typedef TheISA::RegIndex RegIndex;
+ public:
+ //Typedefs from the Impl.
+ typedef typename Impl::FullCPU FullCPU;
+ typedef typename Impl::DynInstPtr DynInstPtr;
+
+ typedef std::pair<RegIndex, PhysRegIndex> UnmapInfo_t;
+ typedef typename list<DynInstPtr>::iterator InstIt_t;
+
+ public:
+ /** ROB constructor.
+ * @param _numEntries Number of entries in ROB.
+ * @param _squashWidth Number of instructions that can be squashed in a
+ * single cycle.
+ */
+ ROB(unsigned _numEntries, unsigned _squashWidth);
+
+ /** Function to set the CPU pointer, necessary due to which object the ROB
+ * is created within.
+ * @param cpu_ptr Pointer to the implementation specific full CPU object.
+ */
+ void setCPU(FullCPU *cpu_ptr);
+
+ /** Function to insert an instruction into the ROB. The parameter inst is
+ * not truly required, but is useful for checking correctness. Note
+ * that whatever calls this function must ensure that there is enough
+ * space within the ROB for the new instruction.
+ * @param inst The instruction being inserted into the ROB.
+ * @todo Remove the parameter once correctness is ensured.
+ */
+ void insertInst(DynInstPtr &inst);
+
+ /** Returns pointer to the head instruction within the ROB. There is
+ * no guarantee as to the return value if the ROB is empty.
+ * @retval Pointer to the DynInst that is at the head of the ROB.
+ */
+ DynInstPtr readHeadInst() { return cpu->instList.front(); }
+
+ DynInstPtr readTailInst() { return (*tail); }
+
+ void retireHead();
+
+ bool isHeadReady();
+
+ unsigned numFreeEntries();
+
+ bool isFull()
+ { return numInstsInROB == numEntries; }
+
+ bool isEmpty()
+ { return numInstsInROB == 0; }
+
+ void doSquash();
+
+ void squash(InstSeqNum squash_num);
+
+ uint64_t readHeadPC();
+
+ uint64_t readHeadNextPC();
+
+ InstSeqNum readHeadSeqNum();
+
+ uint64_t readTailPC();
+
+ InstSeqNum readTailSeqNum();
+
+ /** Checks if the ROB is still in the process of squashing instructions.
+ * @retval Whether or not the ROB is done squashing.
+ */
+ bool isDoneSquashing() const { return doneSquashing; }
+
+ /** This is more of a debugging function than anything. Use
+ * numInstsInROB to get the instructions in the ROB unless you are
+ * double checking that variable.
+ */
+ int countInsts();
+
+ private:
+
+ /** Pointer to the CPU. */
+ FullCPU *cpu;
+
+ /** Number of instructions in the ROB. */
+ unsigned numEntries;
+
+ /** Number of instructions that can be squashed in a single cycle. */
+ unsigned squashWidth;
+
+ /** Iterator pointing to the instruction which is the last instruction
+ * in the ROB. This may at times be invalid (ie when the ROB is empty),
+ * however it should never be incorrect.
+ */
+ InstIt_t tail;
+
+ /** Iterator used for walking through the list of instructions when
+ * squashing. Used so that there is persistent state between cycles;
+ * when squashing, the instructions are marked as squashed but not
+ * immediately removed, meaning the tail iterator remains the same before
+ * and after a squash.
+ * This will always be set to cpu->instList.end() if it is invalid.
+ */
+ InstIt_t squashIt;
+
+ /** Number of instructions in the ROB. */
+ int numInstsInROB;
+
+ /** The sequence number of the squashed instruction. */
+ InstSeqNum squashedSeqNum;
+
+ /** Is the ROB done squashing. */
+ bool doneSquashing;
+};
+
+#endif //__CPU_O3_CPU_ROB_HH__
diff --git a/src/cpu/o3/rob_impl.hh b/src/cpu/o3/rob_impl.hh
new file mode 100644
index 000000000..e7a5671d9
--- /dev/null
+++ b/src/cpu/o3/rob_impl.hh
@@ -0,0 +1,312 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPU_O3_CPU_ROB_IMPL_HH__
+#define __CPU_O3_CPU_ROB_IMPL_HH__
+
+#include "config/full_system.hh"
+#include "cpu/o3/rob.hh"
+
+template <class Impl>
+ROB<Impl>::ROB(unsigned _numEntries, unsigned _squashWidth)
+ : numEntries(_numEntries),
+ squashWidth(_squashWidth),
+ numInstsInROB(0),
+ squashedSeqNum(0)
+{
+ doneSquashing = true;
+}
+
+template <class Impl>
+void
+ROB<Impl>::setCPU(FullCPU *cpu_ptr)
+{
+ cpu = cpu_ptr;
+
+ // Set the tail to the beginning of the CPU instruction list so that
+ // upon the first instruction being inserted into the ROB, the tail
+ // iterator can simply be incremented.
+ tail = cpu->instList.begin();
+
+ // Set the squash iterator to the end of the instruction list.
+ squashIt = cpu->instList.end();
+}
+
+template <class Impl>
+int
+ROB<Impl>::countInsts()
+{
+ // Start at 1; if the tail matches cpu->instList.begin(), then there is
+ // one inst in the ROB.
+ int return_val = 1;
+
+ // There are quite a few special cases. Do not use this function other
+ // than for debugging purposes.
+ if (cpu->instList.begin() == cpu->instList.end()) {
+ // In this case there are no instructions in the list. The ROB
+ // must be empty.
+ return 0;
+ } else if (tail == cpu->instList.end()) {
+ // In this case, the tail is not yet pointing to anything valid.
+ // The ROB must be empty.
+ return 0;
+ }
+
+ // Iterate through the ROB from the head to the tail, counting the
+ // entries.
+ for (InstIt_t i = cpu->instList.begin(); i != tail; ++i)
+ {
+ assert(i != cpu->instList.end());
+ ++return_val;
+ }
+
+ return return_val;
+
+ // Because the head won't be tracked properly until the ROB gets the
+ // first instruction, and any time that the ROB is empty and has not
+ // yet gotten the instruction, this function doesn't work.
+// return numInstsInROB;
+}
+
+template <class Impl>
+void
+ROB<Impl>::insertInst(DynInstPtr &inst)
+{
+ // Make sure we have the right number of instructions.
+ assert(numInstsInROB == countInsts());
+ // Make sure the instruction is valid.
+ assert(inst);
+
+ DPRINTF(ROB, "ROB: Adding inst PC %#x to the ROB.\n", inst->readPC());
+
+ // If the ROB is full then exit.
+ assert(numInstsInROB != numEntries);
+
+ ++numInstsInROB;
+
+ // Increment the tail iterator, moving it one instruction back.
+ // There is a special case if the ROB was empty prior to this insertion,
+ // in which case the tail will be pointing at instList.end(). If that
+ // happens, then reset the tail to the beginning of the list.
+ if (tail != cpu->instList.end()) {
+ ++tail;
+ } else {
+ tail = cpu->instList.begin();
+ }
+
+ // Make sure the tail iterator is actually pointing at the instruction
+ // added.
+ assert((*tail) == inst);
+
+ DPRINTF(ROB, "ROB: Now has %d instructions.\n", numInstsInROB);
+
+}
+
+// Whatever calls this function needs to ensure that it properly frees up
+// registers prior to this function.
+template <class Impl>
+void
+ROB<Impl>::retireHead()
+{
+ assert(numInstsInROB == countInsts());
+ assert(numInstsInROB > 0);
+
+ // Get the head ROB instruction.
+ DynInstPtr head_inst = cpu->instList.front();
+
+ // Make certain this can retire.
+ assert(head_inst->readyToCommit());
+
+ DPRINTF(ROB, "ROB: Retiring head instruction of the ROB, "
+ "instruction PC %#x, seq num %i\n", head_inst->readPC(),
+ head_inst->seqNum);
+
+ // Keep track of how many instructions are in the ROB.
+ --numInstsInROB;
+
+ // Tell CPU to remove the instruction from the list of instructions.
+ // A special case is needed if the instruction being retired is the
+ // only instruction in the ROB; otherwise the tail iterator will become
+ // invalidated.
+ cpu->removeFrontInst(head_inst);
+
+ if (numInstsInROB == 0) {
+ tail = cpu->instList.end();
+ }
+}
+
+template <class Impl>
+bool
+ROB<Impl>::isHeadReady()
+{
+ if (numInstsInROB != 0) {
+ return cpu->instList.front()->readyToCommit();
+ }
+
+ return false;
+}
+
+template <class Impl>
+unsigned
+ROB<Impl>::numFreeEntries()
+{
+ assert(numInstsInROB == countInsts());
+
+ return numEntries - numInstsInROB;
+}
+
+template <class Impl>
+void
+ROB<Impl>::doSquash()
+{
+ DPRINTF(ROB, "ROB: Squashing instructions.\n");
+
+ assert(squashIt != cpu->instList.end());
+
+ for (int numSquashed = 0;
+ numSquashed < squashWidth && (*squashIt)->seqNum != squashedSeqNum;
+ ++numSquashed)
+ {
+ // Ensure that the instruction is younger.
+ assert((*squashIt)->seqNum > squashedSeqNum);
+
+ DPRINTF(ROB, "ROB: Squashing instruction PC %#x, seq num %i.\n",
+ (*squashIt)->readPC(), (*squashIt)->seqNum);
+
+ // Mark the instruction as squashed, and ready to commit so that
+ // it can drain out of the pipeline.
+ (*squashIt)->setSquashed();
+
+ (*squashIt)->setCanCommit();
+
+ // Special case for when squashing due to a syscall. It's possible
+ // that the squash happened after the head instruction was already
+ // committed, meaning that (*squashIt)->seqNum != squashedSeqNum
+ // will never be false. Normally the squash would never be able
+ // to go past the head of the ROB; in this case it might, so it
+ // must be handled otherwise it will segfault.
+#if !FULL_SYSTEM
+ if (squashIt == cpu->instList.begin()) {
+ DPRINTF(ROB, "ROB: Reached head of instruction list while "
+ "squashing.\n");
+
+ squashIt = cpu->instList.end();
+
+ doneSquashing = true;
+
+ return;
+ }
+#endif
+
+ // Move the tail iterator to the next instruction.
+ squashIt--;
+ }
+
+
+ // Check if ROB is done squashing.
+ if ((*squashIt)->seqNum == squashedSeqNum) {
+ DPRINTF(ROB, "ROB: Done squashing instructions.\n");
+
+ squashIt = cpu->instList.end();
+
+ doneSquashing = true;
+ }
+}
+
+template <class Impl>
+void
+ROB<Impl>::squash(InstSeqNum squash_num)
+{
+ DPRINTF(ROB, "ROB: Starting to squash within the ROB.\n");
+ doneSquashing = false;
+
+ squashedSeqNum = squash_num;
+
+ assert(tail != cpu->instList.end());
+
+ squashIt = tail;
+
+ doSquash();
+}
+
+template <class Impl>
+uint64_t
+ROB<Impl>::readHeadPC()
+{
+ assert(numInstsInROB == countInsts());
+
+ DynInstPtr head_inst = cpu->instList.front();
+
+ return head_inst->readPC();
+}
+
+template <class Impl>
+uint64_t
+ROB<Impl>::readHeadNextPC()
+{
+ assert(numInstsInROB == countInsts());
+
+ DynInstPtr head_inst = cpu->instList.front();
+
+ return head_inst->readNextPC();
+}
+
+template <class Impl>
+InstSeqNum
+ROB<Impl>::readHeadSeqNum()
+{
+ // Return the last sequence number that has not been squashed. Other
+ // stages can use it to squash any instructions younger than the current
+ // tail.
+ DynInstPtr head_inst = cpu->instList.front();
+
+ return head_inst->seqNum;
+}
+
+template <class Impl>
+uint64_t
+ROB<Impl>::readTailPC()
+{
+ assert(numInstsInROB == countInsts());
+
+ assert(tail != cpu->instList.end());
+
+ return (*tail)->readPC();
+}
+
+template <class Impl>
+InstSeqNum
+ROB<Impl>::readTailSeqNum()
+{
+ // Return the last sequence number that has not been squashed. Other
+ // stages can use it to squash any instructions younger than the current
+ // tail.
+ return (*tail)->seqNum;
+}
+
+#endif // __CPU_O3_CPU_ROB_IMPL_HH__
diff --git a/src/cpu/o3/sat_counter.cc b/src/cpu/o3/sat_counter.cc
new file mode 100644
index 000000000..d20fff650
--- /dev/null
+++ b/src/cpu/o3/sat_counter.cc
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "base/misc.hh"
+#include "cpu/o3/sat_counter.hh"
+
+SatCounter::SatCounter()
+ : maxVal(0), counter(0)
+{
+}
+
+SatCounter::SatCounter(unsigned bits)
+ : maxVal((1 << bits) - 1), counter(0)
+{
+}
+
+SatCounter::SatCounter(unsigned bits, unsigned initial_val)
+ : maxVal((1 << bits) - 1), counter(initial_val)
+{
+ // Check to make sure initial value doesn't exceed the max counter value.
+ if (initial_val > maxVal) {
+ panic("BP: Initial counter value exceeds max size.");
+ }
+}
+
+void
+SatCounter::setBits(unsigned bits)
+{
+ maxVal = (1 << bits) - 1;
+}
+
+void
+SatCounter::increment()
+{
+ if(counter < maxVal) {
+ ++counter;
+ }
+}
+
+void
+SatCounter::decrement()
+{
+ if(counter > 0) {
+ --counter;
+ }
+}
diff --git a/src/cpu/o3/sat_counter.hh b/src/cpu/o3/sat_counter.hh
new file mode 100644
index 000000000..b7cfe6423
--- /dev/null
+++ b/src/cpu/o3/sat_counter.hh
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPU_O3_CPU_SAT_COUNTER_HH__
+#define __CPU_O3_CPU_SAT_COUNTER_HH__
+
+#include "sim/host.hh"
+
+/**
+ * Private counter class for the internal saturating counters.
+ * Implements an n bit saturating counter and provides methods to
+ * increment, decrement, and read it.
+ * @todo Consider making this something that more closely mimics a
+ * built in class so you can use ++ or --.
+ */
+class SatCounter
+{
+ public:
+ /**
+ * Constructor for the counter.
+ */
+ SatCounter();
+
+ /**
+ * Constructor for the counter.
+ * @param bits How many bits the counter will have.
+ */
+ SatCounter(unsigned bits);
+
+ /**
+ * Constructor for the counter.
+ * @param bits How many bits the counter will have.
+ * @param initial_val Starting value for each counter.
+ */
+ SatCounter(unsigned bits, unsigned initial_val);
+
+ /**
+ * Sets the number of bits.
+ */
+ void setBits(unsigned bits);
+
+ /**
+ * Increments the counter's current value.
+ */
+ void increment();
+
+ /**
+ * Decrements the counter's current value.
+ */
+ void decrement();
+
+ /**
+ * Read the counter's value.
+ */
+ const uint8_t read() const
+ {
+ return counter;
+ }
+
+ private:
+ uint8_t maxVal;
+ uint8_t counter;
+};
+
+#endif // __CPU_O3_CPU_SAT_COUNTER_HH__
diff --git a/src/cpu/o3/store_set.cc b/src/cpu/o3/store_set.cc
new file mode 100644
index 000000000..11023f4a8
--- /dev/null
+++ b/src/cpu/o3/store_set.cc
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "base/trace.hh"
+#include "cpu/o3/store_set.hh"
+
+StoreSet::StoreSet(int _SSIT_size, int _LFST_size)
+ : SSIT_size(_SSIT_size), LFST_size(_LFST_size)
+{
+ DPRINTF(StoreSet, "StoreSet: Creating store set object.\n");
+ DPRINTF(StoreSet, "StoreSet: SSIT size: %i, LFST size: %i.\n",
+ SSIT_size, LFST_size);
+
+ SSIT = new SSID[SSIT_size];
+
+ validSSIT.resize(SSIT_size);
+
+ for (int i = 0; i < SSIT_size; ++i)
+ validSSIT[i] = false;
+
+ LFST = new InstSeqNum[LFST_size];
+
+ validLFST.resize(LFST_size);
+
+ SSCounters = new int[LFST_size];
+
+ for (int i = 0; i < LFST_size; ++i)
+ {
+ validLFST[i] = false;
+ SSCounters[i] = 0;
+ }
+
+ index_mask = SSIT_size - 1;
+
+ offset_bits = 2;
+}
+
+void
+StoreSet::violation(Addr store_PC, Addr load_PC)
+{
+ int load_index = calcIndex(load_PC);
+ int store_index = calcIndex(store_PC);
+
+ assert(load_index < SSIT_size && store_index < SSIT_size);
+
+ bool valid_load_SSID = validSSIT[load_index];
+ bool valid_store_SSID = validSSIT[store_index];
+
+ if (!valid_load_SSID && !valid_store_SSID) {
+ // Calculate a new SSID here.
+ SSID new_set = calcSSID(load_PC);
+
+ validSSIT[load_index] = true;
+
+ SSIT[load_index] = new_set;
+
+ validSSIT[store_index] = true;
+
+ SSIT[store_index] = new_set;
+
+ assert(new_set < LFST_size);
+
+ SSCounters[new_set]++;
+
+
+ DPRINTF(StoreSet, "StoreSet: Neither load nor store had a valid "
+ "storeset, creating a new one: %i for load %#x, store %#x\n",
+ new_set, load_PC, store_PC);
+ } else if (valid_load_SSID && !valid_store_SSID) {
+ SSID load_SSID = SSIT[load_index];
+
+ validSSIT[store_index] = true;
+
+ SSIT[store_index] = load_SSID;
+
+ assert(load_SSID < LFST_size);
+
+ SSCounters[load_SSID]++;
+
+ DPRINTF(StoreSet, "StoreSet: Load had a valid store set. Adding "
+ "store to that set: %i for load %#x, store %#x\n",
+ load_SSID, load_PC, store_PC);
+ } else if (!valid_load_SSID && valid_store_SSID) {
+ SSID store_SSID = SSIT[store_index];
+
+ validSSIT[load_index] = true;
+
+ SSIT[load_index] = store_SSID;
+
+ // Because we are having a load point to an already existing set,
+ // the size of the store set is not incremented.
+
+ DPRINTF(StoreSet, "StoreSet: Store had a valid store set: %i for "
+ "load %#x, store %#x\n",
+ store_SSID, load_PC, store_PC);
+ } else {
+ SSID load_SSID = SSIT[load_index];
+ SSID store_SSID = SSIT[store_index];
+
+ assert(load_SSID < LFST_size && store_SSID < LFST_size);
+
+ int load_SS_size = SSCounters[load_SSID];
+ int store_SS_size = SSCounters[store_SSID];
+
+ // If the load has the bigger store set, then assign the store
+ // to the same store set as the load. Otherwise vice-versa.
+ if (load_SS_size > store_SS_size) {
+ SSIT[store_index] = load_SSID;
+
+ SSCounters[load_SSID]++;
+ SSCounters[store_SSID]--;
+
+ DPRINTF(StoreSet, "StoreSet: Load had bigger store set: %i; "
+ "for load %#x, store %#x\n",
+ load_SSID, load_PC, store_PC);
+ } else {
+ SSIT[load_index] = store_SSID;
+
+ SSCounters[store_SSID]++;
+ SSCounters[load_SSID]--;
+
+ DPRINTF(StoreSet, "StoreSet: Store had bigger store set: %i; "
+ "for load %#x, store %#x\n",
+ store_SSID, load_PC, store_PC);
+ }
+ }
+}
+
+void
+StoreSet::insertLoad(Addr load_PC, InstSeqNum load_seq_num)
+{
+ // Does nothing.
+ return;
+}
+
+void
+StoreSet::insertStore(Addr store_PC, InstSeqNum store_seq_num)
+{
+ int index = calcIndex(store_PC);
+
+ int store_SSID;
+
+ assert(index < SSIT_size);
+
+ if (!validSSIT[index]) {
+ // Do nothing if there's no valid entry.
+ return;
+ } else {
+ store_SSID = SSIT[index];
+
+ assert(store_SSID < LFST_size);
+
+ // Update the last store that was fetched with the current one.
+ LFST[store_SSID] = store_seq_num;
+
+ validLFST[store_SSID] = 1;
+
+ DPRINTF(StoreSet, "Store %#x updated the LFST, SSID: %i\n",
+ store_PC, store_SSID);
+ }
+}
+
+InstSeqNum
+StoreSet::checkInst(Addr PC)
+{
+ int index = calcIndex(PC);
+
+ int inst_SSID;
+
+ assert(index < SSIT_size);
+
+ if (!validSSIT[index]) {
+ DPRINTF(StoreSet, "Inst %#x with index %i had no SSID\n",
+ PC, index);
+
+ // Return 0 if there's no valid entry.
+ return 0;
+ } else {
+ inst_SSID = SSIT[index];
+
+ assert(inst_SSID < LFST_size);
+
+ if (!validLFST[inst_SSID]) {
+
+ DPRINTF(StoreSet, "Inst %#x with index %i and SSID %i had no "
+ "dependency\n", PC, index, inst_SSID);
+
+ return 0;
+ } else {
+ DPRINTF(StoreSet, "Inst %#x with index %i and SSID %i had LFST "
+ "inum of %i\n", PC, index, inst_SSID, LFST[inst_SSID]);
+
+ return LFST[inst_SSID];
+ }
+ }
+}
+
+void
+StoreSet::issued(Addr issued_PC, InstSeqNum issued_seq_num, bool is_store)
+{
+ // This only is updated upon a store being issued.
+ if (!is_store) {
+ return;
+ }
+
+ int index = calcIndex(issued_PC);
+
+ int store_SSID;
+
+ assert(index < SSIT_size);
+
+ // Make sure the SSIT still has a valid entry for the issued store.
+ if (!validSSIT[index]) {
+ return;
+ }
+
+ store_SSID = SSIT[index];
+
+ assert(store_SSID < LFST_size);
+
+ // If the last fetched store in the store set refers to the store that
+ // was just issued, then invalidate the entry.
+ if (validLFST[store_SSID] && LFST[store_SSID] == issued_seq_num) {
+ DPRINTF(StoreSet, "StoreSet: store invalidated itself in LFST.\n");
+ validLFST[store_SSID] = false;
+ }
+}
+
+void
+StoreSet::squash(InstSeqNum squashed_num)
+{
+ // Not really sure how to do this well.
+ // Generally this is small enough that it should be okay; short circuit
+ // evaluation should take care of invalid entries.
+
+ DPRINTF(StoreSet, "StoreSet: Squashing until inum %i\n",
+ squashed_num);
+
+ for (int i = 0; i < LFST_size; ++i) {
+ if (validLFST[i] && LFST[i] < squashed_num) {
+ validLFST[i] = false;
+ }
+ }
+}
+
+void
+StoreSet::clear()
+{
+ for (int i = 0; i < SSIT_size; ++i) {
+ validSSIT[i] = false;
+ }
+
+ for (int i = 0; i < LFST_size; ++i) {
+ validLFST[i] = false;
+ }
+}
+
diff --git a/src/cpu/o3/store_set.hh b/src/cpu/o3/store_set.hh
new file mode 100644
index 000000000..5a885d838
--- /dev/null
+++ b/src/cpu/o3/store_set.hh
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPU_O3_CPU_STORE_SET_HH__
+#define __CPU_O3_CPU_STORE_SET_HH__
+
+#include <vector>
+
+#include "arch/isa_traits.hh"
+#include "cpu/inst_seq.hh"
+
+class StoreSet
+{
+ public:
+ typedef unsigned SSID;
+
+ public:
+ StoreSet(int SSIT_size, int LFST_size);
+
+ void violation(Addr store_PC, Addr load_PC);
+
+ void insertLoad(Addr load_PC, InstSeqNum load_seq_num);
+
+ void insertStore(Addr store_PC, InstSeqNum store_seq_num);
+
+ InstSeqNum checkInst(Addr PC);
+
+ void issued(Addr issued_PC, InstSeqNum issued_seq_num, bool is_store);
+
+ void squash(InstSeqNum squashed_num);
+
+ void clear();
+
+ private:
+ inline int calcIndex(Addr PC)
+ { return (PC >> offset_bits) & index_mask; }
+
+ inline SSID calcSSID(Addr PC)
+ { return ((PC ^ (PC >> 10)) % LFST_size); }
+
+ SSID *SSIT;
+
+ std::vector<bool> validSSIT;
+
+ InstSeqNum *LFST;
+
+ std::vector<bool> validLFST;
+
+ int *SSCounters;
+
+ int SSIT_size;
+
+ int LFST_size;
+
+ int index_mask;
+
+ // HACK: Hardcoded for now.
+ int offset_bits;
+};
+
+#endif // __CPU_O3_CPU_STORE_SET_HH__
diff --git a/src/cpu/o3/tournament_pred.cc b/src/cpu/o3/tournament_pred.cc
new file mode 100644
index 000000000..3fb580510
--- /dev/null
+++ b/src/cpu/o3/tournament_pred.cc
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "cpu/o3/tournament_pred.hh"
+
+TournamentBP::TournamentBP(unsigned _local_predictor_size,
+ unsigned _local_ctr_bits,
+ unsigned _local_history_table_size,
+ unsigned _local_history_bits,
+ unsigned _global_predictor_size,
+ unsigned _global_ctr_bits,
+ unsigned _global_history_bits,
+ unsigned _choice_predictor_size,
+ unsigned _choice_ctr_bits,
+ unsigned _instShiftAmt)
+ : localPredictorSize(_local_predictor_size),
+ localCtrBits(_local_ctr_bits),
+ localHistoryTableSize(_local_history_table_size),
+ localHistoryBits(_local_history_bits),
+ globalPredictorSize(_global_predictor_size),
+ globalCtrBits(_global_ctr_bits),
+ globalHistoryBits(_global_history_bits),
+ choicePredictorSize(_global_predictor_size),
+ choiceCtrBits(_choice_ctr_bits),
+ instShiftAmt(_instShiftAmt)
+{
+ //Should do checks here to make sure sizes are correct (powers of 2)
+
+ //Setup the array of counters for the local predictor
+ localCtrs = new SatCounter[localPredictorSize];
+
+ for (int i = 0; i < localPredictorSize; ++i)
+ localCtrs[i].setBits(localCtrBits);
+
+ //Setup the history table for the local table
+ localHistoryTable = new unsigned[localHistoryTableSize];
+
+ for (int i = 0; i < localHistoryTableSize; ++i)
+ localHistoryTable[i] = 0;
+
+ // Setup the local history mask
+ localHistoryMask = (1 << localHistoryBits) - 1;
+
+ //Setup the array of counters for the global predictor
+ globalCtrs = new SatCounter[globalPredictorSize];
+
+ for (int i = 0; i < globalPredictorSize; ++i)
+ globalCtrs[i].setBits(globalCtrBits);
+
+ //Clear the global history
+ globalHistory = 0;
+ // Setup the global history mask
+ globalHistoryMask = (1 << globalHistoryBits) - 1;
+
+ //Setup the array of counters for the choice predictor
+ choiceCtrs = new SatCounter[choicePredictorSize];
+
+ for (int i = 0; i < choicePredictorSize; ++i)
+ choiceCtrs[i].setBits(choiceCtrBits);
+
+ threshold = (1 << (localCtrBits - 1)) - 1;
+ threshold = threshold / 2;
+}
+
+inline
+unsigned
+TournamentBP::calcLocHistIdx(Addr &branch_addr)
+{
+ return (branch_addr >> instShiftAmt) & (localHistoryTableSize - 1);
+}
+
+inline
+void
+TournamentBP::updateHistoriesTaken(unsigned local_history_idx)
+{
+ globalHistory = (globalHistory << 1) | 1;
+ globalHistory = globalHistory & globalHistoryMask;
+
+ localHistoryTable[local_history_idx] =
+ (localHistoryTable[local_history_idx] << 1) | 1;
+}
+
+inline
+void
+TournamentBP::updateHistoriesNotTaken(unsigned local_history_idx)
+{
+ globalHistory = (globalHistory << 1);
+ globalHistory = globalHistory & globalHistoryMask;
+
+ localHistoryTable[local_history_idx] =
+ (localHistoryTable[local_history_idx] << 1);
+}
+
+bool
+TournamentBP::lookup(Addr &branch_addr)
+{
+ uint8_t local_prediction;
+ unsigned local_history_idx;
+ unsigned local_predictor_idx;
+
+ uint8_t global_prediction;
+ uint8_t choice_prediction;
+
+ //Lookup in the local predictor to get its branch prediction
+ local_history_idx = calcLocHistIdx(branch_addr);
+ local_predictor_idx = localHistoryTable[local_history_idx]
+ & localHistoryMask;
+ local_prediction = localCtrs[local_predictor_idx].read();
+
+ //Lookup in the global predictor to get its branch prediction
+ global_prediction = globalCtrs[globalHistory].read();
+
+ //Lookup in the choice predictor to see which one to use
+ choice_prediction = choiceCtrs[globalHistory].read();
+
+ //@todo Put a threshold value in for the three predictors that can
+ // be set through the constructor (so this isn't hard coded).
+ //Also should put some of this code into functions.
+ if (choice_prediction > threshold) {
+ if (global_prediction > threshold) {
+ updateHistoriesTaken(local_history_idx);
+
+ assert(globalHistory < globalPredictorSize &&
+ local_history_idx < localPredictorSize);
+
+ globalCtrs[globalHistory].increment();
+ localCtrs[local_history_idx].increment();
+
+ return true;
+ } else {
+ updateHistoriesNotTaken(local_history_idx);
+
+ assert(globalHistory < globalPredictorSize &&
+ local_history_idx < localPredictorSize);
+
+ globalCtrs[globalHistory].decrement();
+ localCtrs[local_history_idx].decrement();
+
+ return false;
+ }
+ } else {
+ if (local_prediction > threshold) {
+ updateHistoriesTaken(local_history_idx);
+
+ assert(globalHistory < globalPredictorSize &&
+ local_history_idx < localPredictorSize);
+
+ globalCtrs[globalHistory].increment();
+ localCtrs[local_history_idx].increment();
+
+ return true;
+ } else {
+ updateHistoriesNotTaken(local_history_idx);
+
+ assert(globalHistory < globalPredictorSize &&
+ local_history_idx < localPredictorSize);
+
+ globalCtrs[globalHistory].decrement();
+ localCtrs[local_history_idx].decrement();
+
+ return false;
+ }
+ }
+}
+
+// Update the branch predictor if it predicted a branch wrong.
+void
+TournamentBP::update(Addr &branch_addr, unsigned correct_gh, bool taken)
+{
+
+ uint8_t local_prediction;
+ unsigned local_history_idx;
+ unsigned local_predictor_idx;
+ bool local_pred_taken;
+
+ uint8_t global_prediction;
+ bool global_pred_taken;
+
+ // Load the correct global history into the register.
+ globalHistory = correct_gh;
+
+ // Get the local predictor's current prediction, remove the incorrect
+ // update, and update the local predictor
+ local_history_idx = calcLocHistIdx(branch_addr);
+ local_predictor_idx = localHistoryTable[local_history_idx];
+ local_predictor_idx = (local_predictor_idx >> 1) & localHistoryMask;
+
+ local_prediction = localCtrs[local_predictor_idx].read();
+ local_pred_taken = local_prediction > threshold;
+
+ //Get the global predictor's current prediction, and update the
+ //global predictor
+ global_prediction = globalCtrs[globalHistory].read();
+ global_pred_taken = global_prediction > threshold;
+
+ //Update the choice predictor to tell it which one was correct
+ if (local_pred_taken != global_pred_taken) {
+ //If the local prediction matches the actual outcome, decerement
+ //the counter. Otherwise increment the counter.
+ if (local_pred_taken == taken) {
+ choiceCtrs[globalHistory].decrement();
+ } else {
+ choiceCtrs[globalHistory].increment();
+ }
+ }
+
+ if (taken) {
+ assert(globalHistory < globalPredictorSize &&
+ local_predictor_idx < localPredictorSize);
+
+ localCtrs[local_predictor_idx].increment();
+ globalCtrs[globalHistory].increment();
+
+ globalHistory = (globalHistory << 1) | 1;
+ globalHistory = globalHistory & globalHistoryMask;
+
+ localHistoryTable[local_history_idx] |= 1;
+ }
+ else {
+ assert(globalHistory < globalPredictorSize &&
+ local_predictor_idx < localPredictorSize);
+
+ localCtrs[local_predictor_idx].decrement();
+ globalCtrs[globalHistory].decrement();
+
+ globalHistory = (globalHistory << 1);
+ globalHistory = globalHistory & globalHistoryMask;
+
+ localHistoryTable[local_history_idx] &= ~1;
+ }
+}
diff --git a/src/cpu/o3/tournament_pred.hh b/src/cpu/o3/tournament_pred.hh
new file mode 100644
index 000000000..cb93c2f67
--- /dev/null
+++ b/src/cpu/o3/tournament_pred.hh
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPU_O3_CPU_TOURNAMENT_PRED_HH__
+#define __CPU_O3_CPU_TOURNAMENT_PRED_HH__
+
+// For Addr type.
+#include "arch/isa_traits.hh"
+#include "cpu/o3/sat_counter.hh"
+
+class TournamentBP
+{
+ public:
+ /**
+ * Default branch predictor constructor.
+ */
+ TournamentBP(unsigned local_predictor_size,
+ unsigned local_ctr_bits,
+ unsigned local_history_table_size,
+ unsigned local_history_bits,
+ unsigned global_predictor_size,
+ unsigned global_history_bits,
+ unsigned global_ctr_bits,
+ unsigned choice_predictor_size,
+ unsigned choice_ctr_bits,
+ unsigned instShiftAmt);
+
+ /**
+ * Looks up the given address in the branch predictor and returns
+ * a true/false value as to whether it is taken.
+ * @param branch_addr The address of the branch to look up.
+ * @return Whether or not the branch is taken.
+ */
+ bool lookup(Addr &branch_addr);
+
+ /**
+ * Updates the branch predictor with the actual result of a branch.
+ * @param branch_addr The address of the branch to update.
+ * @param taken Whether or not the branch was taken.
+ */
+ void update(Addr &branch_addr, unsigned global_history, bool taken);
+
+ inline unsigned readGlobalHist() { return globalHistory; }
+
+ private:
+
+ inline bool getPrediction(uint8_t &count);
+
+ inline unsigned calcLocHistIdx(Addr &branch_addr);
+
+ inline void updateHistoriesTaken(unsigned local_history_idx);
+
+ inline void updateHistoriesNotTaken(unsigned local_history_idx);
+
+ /** Local counters. */
+ SatCounter *localCtrs;
+
+ /** Size of the local predictor. */
+ unsigned localPredictorSize;
+
+ /** Number of bits of the local predictor's counters. */
+ unsigned localCtrBits;
+
+ /** Array of local history table entries. */
+ unsigned *localHistoryTable;
+
+ /** Size of the local history table. */
+ unsigned localHistoryTableSize;
+
+ /** Number of bits for each entry of the local history table.
+ * @todo Doesn't this come from the size of the local predictor?
+ */
+ unsigned localHistoryBits;
+
+ /** Mask to get the proper local history. */
+ unsigned localHistoryMask;
+
+
+ /** Array of counters that make up the global predictor. */
+ SatCounter *globalCtrs;
+
+ /** Size of the global predictor. */
+ unsigned globalPredictorSize;
+
+ /** Number of bits of the global predictor's counters. */
+ unsigned globalCtrBits;
+
+ /** Global history register. */
+ unsigned globalHistory;
+
+ /** Number of bits for the global history. */
+ unsigned globalHistoryBits;
+
+ /** Mask to get the proper global history. */
+ unsigned globalHistoryMask;
+
+
+ /** Array of counters that make up the choice predictor. */
+ SatCounter *choiceCtrs;
+
+ /** Size of the choice predictor (identical to the global predictor). */
+ unsigned choicePredictorSize;
+
+ /** Number of bits of the choice predictor's counters. */
+ unsigned choiceCtrBits;
+
+ /** Number of bits to shift the instruction over to get rid of the word
+ * offset.
+ */
+ unsigned instShiftAmt;
+
+ /** Threshold for the counter value; above the threshold is taken,
+ * equal to or below the threshold is not taken.
+ */
+ unsigned threshold;
+};
+
+#endif // __CPU_O3_CPU_TOURNAMENT_PRED_HH__
diff --git a/src/cpu/op_class.cc b/src/cpu/op_class.cc
new file mode 100644
index 000000000..00136ded5
--- /dev/null
+++ b/src/cpu/op_class.cc
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "cpu/op_class.hh"
+
+/** OpClass enum -> description string */
+const char *
+opClassStrings[Num_OpClasses] =
+{
+ "(null)",
+ "IntAlu",
+ "IntMult",
+ "IntDiv",
+ "FloatAdd",
+ "FloatCmp",
+ "FloatCvt",
+ "FloatMult",
+ "FloatDiv",
+ "FloatSqrt",
+ "MemRead",
+ "MemWrite",
+ "IprAccess",
+ "InstPrefetch"
+};
+
diff --git a/src/cpu/op_class.hh b/src/cpu/op_class.hh
new file mode 100644
index 000000000..cdb40a0fb
--- /dev/null
+++ b/src/cpu/op_class.hh
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPU__OP_CLASS_HH__
+#define __CPU__OP_CLASS_HH__
+
+/**
+ * @file
+ * Definition of operation classes.
+ */
+
+/**
+ * Instruction operation classes. These classes are used for
+ * assigning instructions to functional units.
+ */
+enum OpClass {
+ No_OpClass = 0, ///< Instruction does not use a functional unit
+ IntAluOp, ///< Integer ALU operaton (add/sub/logical)
+ IntMultOp, ///< Integer multiply
+ IntDivOp, ///< Integer divide
+ FloatAddOp, ///< Floating point add/subtract
+ FloatCmpOp, ///< Floating point comparison
+ FloatCvtOp, ///< Floating point<->integer conversion
+ FloatMultOp, ///< Floating point multiply
+ FloatDivOp, ///< Floating point divide
+ FloatSqrtOp, ///< Floating point square root
+ MemReadOp, ///< Memory read port
+ MemWriteOp, ///< Memory write port
+ IprAccessOp, ///< Internal Processor Register read/write port
+ InstPrefetchOp, ///< Instruction prefetch port (on I-cache)
+ Num_OpClasses ///< Total number of operation classes
+};
+
+/**
+ * Array mapping OpClass enum values to strings. Defined in op_class.cc.
+ */
+extern const char *opClassStrings[];
+
+#endif // __CPU__OP_CLASS_HH__
diff --git a/src/cpu/ozone/cpu.cc b/src/cpu/ozone/cpu.cc
new file mode 100644
index 000000000..cbeca9d3b
--- /dev/null
+++ b/src/cpu/ozone/cpu.cc
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "cpu/ooo_cpu/ooo_cpu_impl.hh"
+#include "cpu/ooo_cpu/ooo_dyn_inst.hh"
+#include "cpu/ooo_cpu/ooo_impl.hh"
+
+template class OoOCPU<OoOImpl>;
diff --git a/src/cpu/ozone/cpu.hh b/src/cpu/ozone/cpu.hh
new file mode 100644
index 000000000..fa849bb09
--- /dev/null
+++ b/src/cpu/ozone/cpu.hh
@@ -0,0 +1,638 @@
+/*
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPU_OOO_CPU_OOO_CPU_HH__
+#define __CPU_OOO_CPU_OOO_CPU_HH__
+
+#include "base/statistics.hh"
+#include "config/full_system.hh"
+#include "cpu/base.hh"
+#include "cpu/exec_context.hh"
+#include "encumbered/cpu/full/fu_pool.hh"
+#include "cpu/ooo_cpu/ea_list.hh"
+#include "cpu/pc_event.hh"
+#include "cpu/static_inst.hh"
+#include "mem/mem_interface.hh"
+#include "sim/eventq.hh"
+
+// forward declarations
+#if FULL_SYSTEM
+class Processor;
+class AlphaITB;
+class AlphaDTB;
+class PhysicalMemory;
+
+class RemoteGDB;
+class GDBListener;
+
+#else
+
+class Process;
+
+#endif // FULL_SYSTEM
+
+class Checkpoint;
+class MemInterface;
+
+namespace Trace {
+ class InstRecord;
+}
+
+/**
+ * Declaration of Out-of-Order CPU class. Basically it is a SimpleCPU with
+ * simple out-of-order capabilities added to it. It is still a 1 CPI machine
+ * (?), but is capable of handling cache misses. Basically it models having
+ * a ROB/IQ by only allowing a certain amount of instructions to execute while
+ * the cache miss is outstanding.
+ */
+
+template <class Impl>
+class OoOCPU : public BaseCPU
+{
+ private:
+ typedef typename Impl::DynInst DynInst;
+ typedef typename Impl::DynInstPtr DynInstPtr;
+
+ public:
+ // main simulation loop (one cycle)
+ void tick();
+
+ private:
+ struct TickEvent : public Event
+ {
+ OoOCPU *cpu;
+ int width;
+
+ TickEvent(OoOCPU *c, int w);
+ void process();
+ const char *description();
+ };
+
+ TickEvent tickEvent;
+
+ /// Schedule tick event, regardless of its current state.
+ void scheduleTickEvent(int delay)
+ {
+ if (tickEvent.squashed())
+ tickEvent.reschedule(curTick + delay);
+ else if (!tickEvent.scheduled())
+ tickEvent.schedule(curTick + delay);
+ }
+
+ /// Unschedule tick event, regardless of its current state.
+ void unscheduleTickEvent()
+ {
+ if (tickEvent.scheduled())
+ tickEvent.squash();
+ }
+
+ private:
+ Trace::InstRecord *traceData;
+
+ template<typename T>
+ void trace_data(T data);
+
+ public:
+ //
+ enum Status {
+ Running,
+ Idle,
+ IcacheMiss,
+ IcacheMissComplete,
+ DcacheMissStall,
+ SwitchedOut
+ };
+
+ private:
+ Status _status;
+
+ public:
+ void post_interrupt(int int_num, int index);
+
+ void zero_fill_64(Addr addr) {
+ static int warned = 0;
+ if (!warned) {
+ warn ("WH64 is not implemented");
+ warned = 1;
+ }
+ };
+
+ struct Params : public BaseCPU::Params
+ {
+ MemInterface *icache_interface;
+ MemInterface *dcache_interface;
+ int width;
+#if FULL_SYSTEM
+ AlphaITB *itb;
+ AlphaDTB *dtb;
+ FunctionalMemory *mem;
+#else
+ Process *process;
+#endif
+ int issueWidth;
+ };
+
+ OoOCPU(Params *params);
+
+ virtual ~OoOCPU();
+
+ void init();
+
+ private:
+ void copyFromXC();
+
+ public:
+ // execution context
+ ExecContext *xc;
+
+ void switchOut();
+ void takeOverFrom(BaseCPU *oldCPU);
+
+#if FULL_SYSTEM
+ Addr dbg_vtophys(Addr addr);
+
+ bool interval_stats;
+#endif
+
+ // L1 instruction cache
+ MemInterface *icacheInterface;
+
+ // L1 data cache
+ MemInterface *dcacheInterface;
+
+ FuncUnitPool *fuPool;
+
+ // Refcounted pointer to the one memory request.
+ MemReqPtr cacheMemReq;
+
+ class ICacheCompletionEvent : public Event
+ {
+ private:
+ OoOCPU *cpu;
+
+ public:
+ ICacheCompletionEvent(OoOCPU *_cpu);
+
+ virtual void process();
+ virtual const char *description();
+ };
+
+ // Will need to create a cache completion event upon any memory miss.
+ ICacheCompletionEvent iCacheCompletionEvent;
+
+ class DCacheCompletionEvent;
+
+ typedef typename
+ std::list<DCacheCompletionEvent>::iterator DCacheCompEventIt;
+
+ class DCacheCompletionEvent : public Event
+ {
+ private:
+ OoOCPU *cpu;
+ DynInstPtr inst;
+ DCacheCompEventIt dcceIt;
+
+ public:
+ DCacheCompletionEvent(OoOCPU *_cpu, DynInstPtr &_inst,
+ DCacheCompEventIt &_dcceIt);
+
+ virtual void process();
+ virtual const char *description();
+ };
+
+ friend class DCacheCompletionEvent;
+
+ protected:
+ std::list<DCacheCompletionEvent> dCacheCompList;
+ DCacheCompEventIt dcceIt;
+
+ private:
+ Status status() const { return _status; }
+
+ virtual void activateContext(int thread_num, int delay);
+ virtual void suspendContext(int thread_num);
+ virtual void deallocateContext(int thread_num);
+ virtual void haltContext(int thread_num);
+
+ // statistics
+ virtual void regStats();
+ virtual void resetStats();
+
+ // number of simulated instructions
+ Counter numInst;
+ Counter startNumInst;
+ Stats::Scalar<> numInsts;
+
+ virtual Counter totalInstructions() const
+ {
+ return numInst - startNumInst;
+ }
+
+ // number of simulated memory references
+ Stats::Scalar<> numMemRefs;
+
+ // number of simulated loads
+ Counter numLoad;
+ Counter startNumLoad;
+
+ // number of idle cycles
+ Stats::Average<> notIdleFraction;
+ Stats::Formula idleFraction;
+
+ // number of cycles stalled for I-cache misses
+ Stats::Scalar<> icacheStallCycles;
+ Counter lastIcacheStall;
+
+ // number of cycles stalled for D-cache misses
+ Stats::Scalar<> dcacheStallCycles;
+ Counter lastDcacheStall;
+
+ void processICacheCompletion();
+
+ public:
+
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+
+#if FULL_SYSTEM
+ bool validInstAddr(Addr addr) { return true; }
+ bool validDataAddr(Addr addr) { return true; }
+ int getInstAsid() { return xc->regs.instAsid(); }
+ int getDataAsid() { return xc->regs.dataAsid(); }
+
+ Fault translateInstReq(MemReqPtr &req)
+ {
+ return itb->translate(req);
+ }
+
+ Fault translateDataReadReq(MemReqPtr &req)
+ {
+ return dtb->translate(req, false);
+ }
+
+ Fault translateDataWriteReq(MemReqPtr &req)
+ {
+ return dtb->translate(req, true);
+ }
+
+#else
+ bool validInstAddr(Addr addr)
+ { return xc->validInstAddr(addr); }
+
+ bool validDataAddr(Addr addr)
+ { return xc->validDataAddr(addr); }
+
+ int getInstAsid() { return xc->asid; }
+ int getDataAsid() { return xc->asid; }
+
+ Fault dummyTranslation(MemReqPtr &req)
+ {
+#if 0
+ assert((req->vaddr >> 48 & 0xffff) == 0);
+#endif
+
+ // put the asid in the upper 16 bits of the paddr
+ req->paddr = req->vaddr & ~((Addr)0xffff << sizeof(Addr) * 8 - 16);
+ req->paddr = req->paddr | (Addr)req->asid << sizeof(Addr) * 8 - 16;
+ return NoFault;
+ }
+ Fault translateInstReq(MemReqPtr &req)
+ {
+ return dummyTranslation(req);
+ }
+ Fault translateDataReadReq(MemReqPtr &req)
+ {
+ return dummyTranslation(req);
+ }
+ Fault translateDataWriteReq(MemReqPtr &req)
+ {
+ return dummyTranslation(req);
+ }
+
+#endif
+
+ template <class T>
+ Fault read(Addr addr, T &data, unsigned flags, DynInstPtr inst);
+
+ template <class T>
+ Fault write(T data, Addr addr, unsigned flags,
+ uint64_t *res, DynInstPtr inst);
+
+ void prefetch(Addr addr, unsigned flags)
+ {
+ // need to do this...
+ }
+
+ void writeHint(Addr addr, int size, unsigned flags)
+ {
+ // need to do this...
+ }
+
+ Fault copySrcTranslate(Addr src);
+
+ Fault copy(Addr dest);
+
+ private:
+ bool executeInst(DynInstPtr &inst);
+
+ void renameInst(DynInstPtr &inst);
+
+ void addInst(DynInstPtr &inst);
+
+ void commitHeadInst();
+
+ bool getOneInst();
+
+ Fault fetchCacheLine();
+
+ InstSeqNum getAndIncrementInstSeq();
+
+ bool ambigMemAddr;
+
+ private:
+ InstSeqNum globalSeqNum;
+
+ DynInstPtr renameTable[TheISA::TotalNumRegs];
+ DynInstPtr commitTable[TheISA::TotalNumRegs];
+
+ // Might need a table of the shadow registers as well.
+#if FULL_SYSTEM
+ DynInstPtr palShadowTable[TheISA::NumIntRegs];
+#endif
+
+ public:
+ // The register accessor methods provide the index of the
+ // instruction's operand (e.g., 0 or 1), not the architectural
+ // register index, to simplify the implementation of register
+ // renaming. We find the architectural register index by indexing
+ // into the instruction's own operand index table. Note that a
+ // raw pointer to the StaticInst is provided instead of a
+ // ref-counted StaticInstPtr to redice overhead. This is fine as
+ // long as these methods don't copy the pointer into any long-term
+ // storage (which is pretty hard to imagine they would have reason
+ // to do).
+
+ // In the OoO case these shouldn't read from the XC but rather from the
+ // rename table of DynInsts. Also these likely shouldn't be called very
+ // often, other than when adding things into the xc during say a syscall.
+
+ uint64_t readIntReg(StaticInst *si, int idx)
+ {
+ return xc->readIntReg(si->srcRegIdx(idx));
+ }
+
+ FloatReg readFloatReg(StaticInst *si, int idx, width)
+ {
+ int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag;
+ return xc->readFloatReg(reg_idx, width);
+ }
+
+ FloatReg readFloatReg(StaticInst *si, int idx)
+ {
+ int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag;
+ return xc->readFloatReg(reg_idx);
+ }
+
+ FloatRegBits readFloatRegBits(StaticInst *si, int idx, int width)
+ {
+ int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag;
+ return xc->readFloatRegBits(reg_idx, width);
+ }
+
+ FloatRegBits readFloatRegBits(StaticInst *si, int idx)
+ {
+ int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag;
+ return xc->readFloatRegBits(reg_idx);
+ }
+
+ void setIntReg(StaticInst *si, int idx, uint64_t val)
+ {
+ xc->setIntReg(si->destRegIdx(idx), val);
+ }
+
+ void setFloatReg(StaticInst *si, int idx, FloatReg val, int width)
+ {
+ int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
+ xc->setFloatReg(reg_idx, val, width);
+ }
+
+ void setFloatReg(StaticInst *si, int idx, FloatReg val)
+ {
+ int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
+ xc->setFloatReg(reg_idx, val);
+ }
+
+ void setFloatRegBits(StaticInst *si, int idx, FloatRegBits val, int width)
+ {
+ int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
+ xc->setFloatRegBits(reg_idx, val, width);
+ }
+
+ void setFloatRegBits(StaticInst *si, int idx, FloatRegBits val)
+ {
+ int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
+ xc->setFloatRegBits(reg_idx, val);
+ }
+
+ uint64_t readPC() { return PC; }
+ void setNextPC(Addr val) { nextPC = val; }
+
+ private:
+ Addr PC;
+ Addr nextPC;
+
+ unsigned issueWidth;
+
+ bool fetchRedirExcp;
+ bool fetchRedirBranch;
+
+ /** Mask to get a cache block's address. */
+ Addr cacheBlkMask;
+
+ unsigned cacheBlkSize;
+
+ Addr cacheBlkPC;
+
+ /** The cache line being fetched. */
+ uint8_t *cacheData;
+
+ protected:
+ bool cacheBlkValid;
+
+ private:
+
+ // Align an address (typically a PC) to the start of an I-cache block.
+ // We fold in the PISA 64- to 32-bit conversion here as well.
+ Addr icacheBlockAlignPC(Addr addr)
+ {
+ addr = TheISA::realPCToFetchPC(addr);
+ return (addr & ~(cacheBlkMask));
+ }
+
+ unsigned instSize;
+
+ // ROB tracking stuff.
+ DynInstPtr robHeadPtr;
+ DynInstPtr robTailPtr;
+ unsigned robSize;
+ unsigned robInsts;
+
+ // List of outstanding EA instructions.
+ protected:
+ EAList eaList;
+
+ public:
+ void branchToTarget(Addr val)
+ {
+ if (!fetchRedirExcp) {
+ fetchRedirBranch = true;
+ PC = val;
+ }
+ }
+
+ // ISA stuff:
+ uint64_t readUniq() { return xc->readUniq(); }
+ void setUniq(uint64_t val) { xc->setUniq(val); }
+
+ uint64_t readFpcr() { return xc->readFpcr(); }
+ void setFpcr(uint64_t val) { xc->setFpcr(val); }
+
+#if FULL_SYSTEM
+ uint64_t readIpr(int idx, Fault &fault) { return xc->readIpr(idx, fault); }
+ Fault setIpr(int idx, uint64_t val) { return xc->setIpr(idx, val); }
+ Fault hwrei() { return xc->hwrei(); }
+ int readIntrFlag() { return xc->readIntrFlag(); }
+ void setIntrFlag(int val) { xc->setIntrFlag(val); }
+ bool inPalMode() { return xc->inPalMode(); }
+ void trap(Fault fault) { fault->invoke(xc); }
+ bool simPalCheck(int palFunc) { return xc->simPalCheck(palFunc); }
+#else
+ void syscall() { xc->syscall(); }
+#endif
+
+ ExecContext *xcBase() { return xc; }
+};
+
+
+// precise architected memory state accessor macros
+template <class Impl>
+template <class T>
+Fault
+OoOCPU<Impl>::read(Addr addr, T &data, unsigned flags, DynInstPtr inst)
+{
+ MemReqPtr readReq = new MemReq();
+ readReq->xc = xc;
+ readReq->asid = 0;
+ readReq->data = new uint8_t[64];
+
+ readReq->reset(addr, sizeof(T), flags);
+
+ // translate to physical address - This might be an ISA impl call
+ Fault fault = translateDataReadReq(readReq);
+
+ // do functional access
+ if (fault == NoFault)
+ fault = xc->mem->read(readReq, data);
+#if 0
+ if (traceData) {
+ traceData->setAddr(addr);
+ if (fault == NoFault)
+ traceData->setData(data);
+ }
+#endif
+
+ // if we have a cache, do cache access too
+ if (fault == NoFault && dcacheInterface) {
+ readReq->cmd = Read;
+ readReq->completionEvent = NULL;
+ readReq->time = curTick;
+ /*MemAccessResult result = */dcacheInterface->access(readReq);
+
+ if (dcacheInterface->doEvents()) {
+ readReq->completionEvent = new DCacheCompletionEvent(this, inst,
+ dcceIt);
+ }
+ }
+
+ if (!dcacheInterface && (readReq->flags & UNCACHEABLE))
+ recordEvent("Uncached Read");
+
+ return fault;
+}
+
+template <class Impl>
+template <class T>
+Fault
+OoOCPU<Impl>::write(T data, Addr addr, unsigned flags,
+ uint64_t *res, DynInstPtr inst)
+{
+ MemReqPtr writeReq = new MemReq();
+ writeReq->xc = xc;
+ writeReq->asid = 0;
+ writeReq->data = new uint8_t[64];
+
+#if 0
+ if (traceData) {
+ traceData->setAddr(addr);
+ traceData->setData(data);
+ }
+#endif
+
+ writeReq->reset(addr, sizeof(T), flags);
+
+ // translate to physical address
+ Fault fault = translateDataWriteReq(writeReq);
+
+ // do functional access
+ if (fault == NoFault)
+ fault = xc->write(writeReq, data);
+
+ if (fault == NoFault && dcacheInterface) {
+ writeReq->cmd = Write;
+ memcpy(writeReq->data,(uint8_t *)&data,writeReq->size);
+ writeReq->completionEvent = NULL;
+ writeReq->time = curTick;
+ /*MemAccessResult result = */dcacheInterface->access(writeReq);
+
+ if (dcacheInterface->doEvents()) {
+ writeReq->completionEvent = new DCacheCompletionEvent(this, inst,
+ dcceIt);
+ }
+ }
+
+ if (res && (fault == NoFault))
+ *res = writeReq->result;
+
+ if (!dcacheInterface && (writeReq->flags & UNCACHEABLE))
+ recordEvent("Uncached Write");
+
+ return fault;
+}
+
+
+#endif // __CPU_OOO_CPU_OOO_CPU_HH__
diff --git a/src/cpu/ozone/cpu_impl.hh b/src/cpu/ozone/cpu_impl.hh
new file mode 100644
index 000000000..e7ed3cfe0
--- /dev/null
+++ b/src/cpu/ozone/cpu_impl.hh
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPU_OOO_CPU_OOO_IMPL_HH__
+#define __CPU_OOO_CPU_OOO_IMPL_HH__
+
+#include "arch/isa_traits.hh"
+
+template <class Impl>
+class OoOCPU;
+
+template <class Impl>
+class OoODynInst;
+
+struct OoOImpl {
+ typedef AlphaISA ISA;
+ typedef OoOCPU<OoOImpl> OoOCPU;
+ typedef OoOCPU FullCPU;
+ typedef OoODynInst<OoOImpl> DynInst;
+ typedef RefCountingPtr<DynInst> DynInstPtr;
+};
+
+#endif // __CPU_OOO_CPU_OOO_IMPL_HH__
diff --git a/src/cpu/ozone/ea_list.cc b/src/cpu/ozone/ea_list.cc
new file mode 100644
index 000000000..6114a0ca1
--- /dev/null
+++ b/src/cpu/ozone/ea_list.cc
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "arch/isa_traits.hh"
+#include "cpu/inst_seq.hh"
+#include "cpu/ooo_cpu/ea_list.hh"
+
+void
+EAList::addAddr(const InstSeqNum &new_sn, const Addr &new_ea)
+{
+ instEA newEA(new_sn, new_ea);
+
+ eaList.push_back(newEA);
+}
+
+void
+EAList::clearAddr(const InstSeqNum &sn_to_clear, const Addr &ea_to_clear)
+{
+ eaListIt list_it = eaList.begin();
+
+ while (list_it != eaList.end() && (*list_it).first != sn_to_clear) {
+ assert((*list_it).second == ea_to_clear);
+ }
+}
+
+bool
+EAList::checkConflict(const InstSeqNum &check_sn, const Addr &check_ea) const
+{
+ const constEAListIt list_it = eaList.begin();
+
+ while (list_it != eaList.end() && (*list_it).first < check_sn) {
+ if ((*list_it).second == check_ea) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void
+EAList::clear()
+{
+ eaList.clear();
+}
+
+void
+EAList::commit(const InstSeqNum &commit_sn)
+{
+ while (!eaList.empty() && eaList.front().first <= commit_sn) {
+ eaList.pop_front();
+ }
+}
diff --git a/src/cpu/ozone/ea_list.hh b/src/cpu/ozone/ea_list.hh
new file mode 100644
index 000000000..c0eee4bb8
--- /dev/null
+++ b/src/cpu/ozone/ea_list.hh
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPU_EA_LIST_HH__
+#define __CPU_EA_LIST_HH__
+
+#include <list>
+#include <utility>
+
+#include "arch/isa_traits.hh"
+#include "cpu/inst_seq.hh"
+
+/**
+ * Simple class to hold onto a list of pairs, each pair having a memory
+ * instruction's sequence number and effective addr. This list can be used
+ * for memory disambiguation. However, if I ever want to forward results, I
+ * may have to use a list that holds DynInstPtrs. Hence this may change in
+ * the future.
+ */
+class EAList {
+ private:
+ typedef std::pair<InstSeqNum, Addr> instEA;
+ typedef std::list<instEA>::iterator eaListIt;
+ typedef std::list<instEA>::const_iterator constEAListIt;
+
+ std::list<instEA> eaList;
+
+ public:
+ EAList() { }
+ ~EAList() { }
+
+ void addAddr(const InstSeqNum &new_sn, const Addr &new_ea);
+
+ void clearAddr(const InstSeqNum &sn_to_clear, const Addr &ea_to_clear);
+
+ /** Checks if any instructions older than check_sn have a conflicting
+ * address with check_ea. Note that this function does not handle the
+ * sequence number rolling over.
+ */
+ bool checkConflict(const InstSeqNum &check_sn, const Addr &check_ea) const;
+
+ void clear();
+
+ void commit(const InstSeqNum &commit_sn);
+};
+
+#endif // __CPU_EA_LIST_HH__
diff --git a/src/cpu/pc_event.cc b/src/cpu/pc_event.cc
new file mode 100644
index 000000000..050bf1a88
--- /dev/null
+++ b/src/cpu/pc_event.cc
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <algorithm>
+#include <map>
+#include <string>
+#include <utility>
+
+#include "base/trace.hh"
+#include "config/full_system.hh"
+#include "cpu/base.hh"
+#include "cpu/exec_context.hh"
+#include "cpu/pc_event.hh"
+#include "sim/debug.hh"
+#include "sim/root.hh"
+#include "sim/system.hh"
+
+using namespace std;
+
+PCEventQueue::PCEventQueue()
+{}
+
+PCEventQueue::~PCEventQueue()
+{}
+
+bool
+PCEventQueue::remove(PCEvent *event)
+{
+ int removed = 0;
+ range_t range = equal_range(event);
+ for (iterator i = range.first; i != range.second; ++i) {
+ if (*i == event) {
+ DPRINTF(PCEvent, "PC based event removed at %#x: %s\n",
+ event->pc(), event->descr());
+ pc_map.erase(i);
+ ++removed;
+ }
+ }
+
+ return removed > 0;
+}
+
+bool
+PCEventQueue::schedule(PCEvent *event)
+{
+ pc_map.push_back(event);
+ sort(pc_map.begin(), pc_map.end(), MapCompare());
+
+ DPRINTF(PCEvent, "PC based event scheduled for %#x: %s\n",
+ event->pc(), event->descr());
+
+ return true;
+}
+
+bool
+PCEventQueue::doService(ExecContext *xc)
+{
+ Addr pc = xc->readPC() & ~0x3;
+ int serviced = 0;
+ range_t range = equal_range(pc);
+ for (iterator i = range.first; i != range.second; ++i) {
+ // Make sure that the pc wasn't changed as the side effect of
+ // another event. This for example, prevents two invocations
+ // of the SkipFuncEvent. Maybe we should have separate PC
+ // event queues for each processor?
+ if (pc != (xc->readPC() & ~0x3))
+ continue;
+
+ DPRINTF(PCEvent, "PC based event serviced at %#x: %s\n",
+ (*i)->pc(), (*i)->descr());
+
+ (*i)->process(xc);
+ ++serviced;
+ }
+
+ return serviced > 0;
+}
+
+void
+PCEventQueue::dump() const
+{
+ const_iterator i = pc_map.begin();
+ const_iterator e = pc_map.end();
+
+ for (; i != e; ++i)
+ cprintf("%d: event at %#x: %s\n", curTick, (*i)->pc(),
+ (*i)->descr());
+}
+
+PCEventQueue::range_t
+PCEventQueue::equal_range(Addr pc)
+{
+ return std::equal_range(pc_map.begin(), pc_map.end(), pc, MapCompare());
+}
+
+BreakPCEvent::BreakPCEvent(PCEventQueue *q, const std::string &desc, Addr addr,
+ bool del)
+ : PCEvent(q, desc, addr), remove(del)
+{
+}
+
+void
+BreakPCEvent::process(ExecContext *xc)
+{
+ StringWrap name(xc->getCpuPtr()->name() + ".break_event");
+ DPRINTFN("break event %s triggered\n", descr());
+ debug_break();
+ if (remove)
+ delete this;
+}
+
+#if FULL_SYSTEM
+extern "C"
+void
+sched_break_pc_sys(System *sys, Addr addr)
+{
+ new BreakPCEvent(&sys->pcEventQueue, "debug break", addr, true);
+}
+
+extern "C"
+void
+sched_break_pc(Addr addr)
+{
+ for (vector<System *>::iterator sysi = System::systemList.begin();
+ sysi != System::systemList.end(); ++sysi) {
+ sched_break_pc_sys(*sysi, addr);
+ }
+
+}
+#endif
diff --git a/src/cpu/pc_event.hh b/src/cpu/pc_event.hh
new file mode 100644
index 000000000..32b7f3ef5
--- /dev/null
+++ b/src/cpu/pc_event.hh
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __PC_EVENT_HH__
+#define __PC_EVENT_HH__
+
+#include <vector>
+
+#include "base/misc.hh"
+
+class ExecContext;
+class PCEventQueue;
+
+class PCEvent
+{
+ protected:
+ std::string description;
+ PCEventQueue *queue;
+ Addr evpc;
+
+ public:
+ PCEvent(PCEventQueue *q, const std::string &desc, Addr pc);
+
+ virtual ~PCEvent() { if (queue) remove(); }
+
+ // for DPRINTF
+ virtual const std::string name() const { return description; }
+
+ std::string descr() const { return description; }
+ Addr pc() const { return evpc; }
+
+ bool remove();
+ virtual void process(ExecContext *xc) = 0;
+};
+
+class PCEventQueue
+{
+ protected:
+ typedef PCEvent * record_t;
+ class MapCompare {
+ public:
+ bool operator()(const record_t &l, const record_t &r) const {
+ return l->pc() < r->pc();
+ }
+ bool operator()(const record_t &l, Addr pc) const {
+ return l->pc() < pc;
+ }
+ bool operator()(Addr pc, const record_t &r) const {
+ return pc < r->pc();
+ }
+ };
+ typedef std::vector<record_t> map_t;
+
+ public:
+ typedef map_t::iterator iterator;
+ typedef map_t::const_iterator const_iterator;
+
+ protected:
+ typedef std::pair<iterator, iterator> range_t;
+ typedef std::pair<const_iterator, const_iterator> const_range_t;
+
+ protected:
+ map_t pc_map;
+
+ bool doService(ExecContext *xc);
+
+ public:
+ PCEventQueue();
+ ~PCEventQueue();
+
+ bool remove(PCEvent *event);
+ bool schedule(PCEvent *event);
+ bool service(ExecContext *xc)
+ {
+ if (pc_map.empty())
+ return false;
+
+ return doService(xc);
+ }
+
+ range_t equal_range(Addr pc);
+ range_t equal_range(PCEvent *event) { return equal_range(event->pc()); }
+
+ void dump() const;
+};
+
+
+inline
+PCEvent::PCEvent(PCEventQueue *q, const std::string &desc, Addr pc)
+ : description(desc), queue(q), evpc(pc)
+{
+ queue->schedule(this);
+}
+
+inline bool
+PCEvent::remove()
+{
+ if (!queue)
+ panic("cannot remove an uninitialized event;");
+
+ return queue->remove(this);
+}
+
+class BreakPCEvent : public PCEvent
+{
+ protected:
+ bool remove;
+
+ public:
+ BreakPCEvent(PCEventQueue *q, const std::string &desc, Addr addr,
+ bool del = false);
+ virtual void process(ExecContext *xc);
+};
+
+#endif // __PC_EVENT_HH__
diff --git a/src/cpu/profile.cc b/src/cpu/profile.cc
new file mode 100644
index 000000000..fe3458b61
--- /dev/null
+++ b/src/cpu/profile.cc
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string>
+
+#include "base/bitfield.hh"
+#include "base/callback.hh"
+#include "base/statistics.hh"
+#include "base/trace.hh"
+#include "base/loader/symtab.hh"
+#include "cpu/base.hh"
+#include "cpu/exec_context.hh"
+#include "cpu/profile.hh"
+
+using namespace std;
+
+ProfileNode::ProfileNode()
+ : count(0)
+{ }
+
+void
+ProfileNode::dump(const string &symbol, uint64_t id, const SymbolTable *symtab,
+ ostream &os) const
+{
+ ccprintf(os, "%#x %s %d ", id, symbol, count);
+ ChildList::const_iterator i, end = children.end();
+ for (i = children.begin(); i != end; ++i) {
+ const ProfileNode *node = i->second;
+ ccprintf(os, "%#x ", (intptr_t)node);
+ }
+
+ ccprintf(os, "\n");
+
+ for (i = children.begin(); i != end; ++i) {
+ Addr addr = i->first;
+ string symbol;
+ if (addr == 1)
+ symbol = "user";
+ else if (addr == 2)
+ symbol = "console";
+ else if (addr == 3)
+ symbol = "unknown";
+ else if (!symtab->findSymbol(addr, symbol))
+ panic("could not find symbol for address %#x\n", addr);
+
+ const ProfileNode *node = i->second;
+ node->dump(symbol, (intptr_t)node, symtab, os);
+ }
+}
+
+void
+ProfileNode::clear()
+{
+ count = 0;
+ ChildList::iterator i, end = children.end();
+ for (i = children.begin(); i != end; ++i)
+ i->second->clear();
+}
+
+FunctionProfile::FunctionProfile(const SymbolTable *_symtab)
+ : reset(0), symtab(_symtab)
+{
+ reset = new MakeCallback<FunctionProfile, &FunctionProfile::clear>(this);
+ Stats::registerResetCallback(reset);
+}
+
+FunctionProfile::~FunctionProfile()
+{
+ if (reset)
+ delete reset;
+}
+
+ProfileNode *
+FunctionProfile::consume(const vector<Addr> &stack)
+{
+ ProfileNode *current = &top;
+ for (int i = 0, size = stack.size(); i < size; ++i) {
+ ProfileNode *&ptr = current->children[stack[size - i - 1]];
+ if (ptr == NULL)
+ ptr = new ProfileNode;
+
+ current = ptr;
+ }
+
+ return current;
+}
+
+void
+FunctionProfile::clear()
+{
+ top.clear();
+ pc_count.clear();
+}
+
+void
+FunctionProfile::dump(ExecContext *xc, ostream &os) const
+{
+ ccprintf(os, ">>>PC data\n");
+ map<Addr, Counter>::const_iterator i, end = pc_count.end();
+ for (i = pc_count.begin(); i != end; ++i) {
+ Addr pc = i->first;
+ Counter count = i->second;
+
+ std::string symbol;
+ if (pc == 1)
+ ccprintf(os, "user %d\n", count);
+ else if (symtab->findSymbol(pc, symbol) && !symbol.empty())
+ ccprintf(os, "%s %d\n", symbol, count);
+ else
+ ccprintf(os, "%#x %d\n", pc, count);
+ }
+
+ ccprintf(os, ">>>function data\n");
+ top.dump("top", 0, symtab, os);
+}
+
+void
+FunctionProfile::sample(ProfileNode *node, Addr pc)
+{
+ node->count++;
+
+ Addr symaddr;
+ if (symtab->findNearestAddr(pc, symaddr)) {
+ pc_count[symaddr]++;
+ } else {
+ // record PC even if we don't have a symbol to avoid
+ // silently biasing the histogram
+ pc_count[pc]++;
+ }
+}
diff --git a/src/cpu/profile.hh b/src/cpu/profile.hh
new file mode 100644
index 000000000..d55c9eec9
--- /dev/null
+++ b/src/cpu/profile.hh
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPU_PROFILE_HH__
+#define __CPU_PROFILE_HH__
+
+#include <map>
+
+#include "cpu/static_inst.hh"
+#include "sim/host.hh"
+#include "arch/stacktrace.hh"
+
+class ExecContext;
+
+class ProfileNode
+{
+ private:
+ friend class FunctionProfile;
+
+ typedef std::map<Addr, ProfileNode *> ChildList;
+ ChildList children;
+
+ public:
+ Counter count;
+
+ public:
+ ProfileNode();
+
+ void dump(const std::string &symbol, uint64_t id,
+ const SymbolTable *symtab, std::ostream &os) const;
+ void clear();
+};
+
+class Callback;
+class FunctionProfile
+{
+ private:
+ Callback *reset;
+ const SymbolTable *symtab;
+ ProfileNode top;
+ std::map<Addr, Counter> pc_count;
+ StackTrace trace;
+
+ public:
+ FunctionProfile(const SymbolTable *symtab);
+ ~FunctionProfile();
+
+ ProfileNode *consume(ExecContext *xc, StaticInstPtr inst);
+ ProfileNode *consume(const std::vector<Addr> &stack);
+ void clear();
+ void dump(ExecContext *xc, std::ostream &out) const;
+ void sample(ProfileNode *node, Addr pc);
+};
+
+inline ProfileNode *
+FunctionProfile::consume(ExecContext *xc, StaticInstPtr inst)
+{
+ if (!trace.trace(xc, inst))
+ return NULL;
+ trace.dprintf();
+ return consume(trace.getstack());
+}
+
+#endif // __CPU_PROFILE_HH__
diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc
new file mode 100644
index 000000000..e9422b9c0
--- /dev/null
+++ b/src/cpu/simple/atomic.cc
@@ -0,0 +1,560 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "arch/utility.hh"
+#include "cpu/exetrace.hh"
+#include "cpu/simple/atomic.hh"
+#include "mem/packet_impl.hh"
+#include "sim/builder.hh"
+
+using namespace std;
+using namespace TheISA;
+
+AtomicSimpleCPU::TickEvent::TickEvent(AtomicSimpleCPU *c)
+ : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c)
+{
+}
+
+
+void
+AtomicSimpleCPU::TickEvent::process()
+{
+ cpu->tick();
+}
+
+const char *
+AtomicSimpleCPU::TickEvent::description()
+{
+ return "AtomicSimpleCPU tick event";
+}
+
+
+void
+AtomicSimpleCPU::init()
+{
+ //Create Memory Ports (conect them up)
+ Port *mem_dport = mem->getPort("");
+ dcachePort.setPeer(mem_dport);
+ mem_dport->setPeer(&dcachePort);
+
+ Port *mem_iport = mem->getPort("");
+ icachePort.setPeer(mem_iport);
+ mem_iport->setPeer(&icachePort);
+
+ BaseCPU::init();
+#if FULL_SYSTEM
+ for (int i = 0; i < execContexts.size(); ++i) {
+ ExecContext *xc = execContexts[i];
+
+ // initialize CPU, including PC
+ TheISA::initCPU(xc, xc->readCpuId());
+ }
+#endif
+}
+
+bool
+AtomicSimpleCPU::CpuPort::recvTiming(Packet *pkt)
+{
+ panic("AtomicSimpleCPU doesn't expect recvAtomic callback!");
+ return true;
+}
+
+Tick
+AtomicSimpleCPU::CpuPort::recvAtomic(Packet *pkt)
+{
+ panic("AtomicSimpleCPU doesn't expect recvAtomic callback!");
+ return curTick;
+}
+
+void
+AtomicSimpleCPU::CpuPort::recvFunctional(Packet *pkt)
+{
+ panic("AtomicSimpleCPU doesn't expect recvFunctional callback!");
+}
+
+void
+AtomicSimpleCPU::CpuPort::recvStatusChange(Status status)
+{
+ if (status == RangeChange)
+ return;
+
+ panic("AtomicSimpleCPU doesn't expect recvStatusChange callback!");
+}
+
+Packet *
+AtomicSimpleCPU::CpuPort::recvRetry()
+{
+ panic("AtomicSimpleCPU doesn't expect recvRetry callback!");
+ return NULL;
+}
+
+
+AtomicSimpleCPU::AtomicSimpleCPU(Params *p)
+ : BaseSimpleCPU(p), tickEvent(this),
+ width(p->width), simulate_stalls(p->simulate_stalls),
+ icachePort(this), dcachePort(this)
+{
+ _status = Idle;
+
+ ifetch_req = new Request(true);
+ ifetch_req->setAsid(0);
+ // @todo fix me and get the real cpu iD!!!
+ ifetch_req->setCpuNum(0);
+ ifetch_req->setSize(sizeof(MachInst));
+ ifetch_pkt = new Packet;
+ ifetch_pkt->cmd = Read;
+ ifetch_pkt->dataStatic(&inst);
+ ifetch_pkt->req = ifetch_req;
+ ifetch_pkt->size = sizeof(MachInst);
+ ifetch_pkt->dest = Packet::Broadcast;
+
+ data_read_req = new Request(true);
+ // @todo fix me and get the real cpu iD!!!
+ data_read_req->setCpuNum(0);
+ data_read_req->setAsid(0);
+ data_read_pkt = new Packet;
+ data_read_pkt->cmd = Read;
+ data_read_pkt->dataStatic(&dataReg);
+ data_read_pkt->req = data_read_req;
+ data_read_pkt->dest = Packet::Broadcast;
+
+ data_write_req = new Request(true);
+ // @todo fix me and get the real cpu iD!!!
+ data_write_req->setCpuNum(0);
+ data_write_req->setAsid(0);
+ data_write_pkt = new Packet;
+ data_write_pkt->cmd = Write;
+ data_write_pkt->req = data_write_req;
+ data_write_pkt->dest = Packet::Broadcast;
+}
+
+
+AtomicSimpleCPU::~AtomicSimpleCPU()
+{
+}
+
+void
+AtomicSimpleCPU::serialize(ostream &os)
+{
+ BaseSimpleCPU::serialize(os);
+ SERIALIZE_ENUM(_status);
+ nameOut(os, csprintf("%s.tickEvent", name()));
+ tickEvent.serialize(os);
+}
+
+void
+AtomicSimpleCPU::unserialize(Checkpoint *cp, const string &section)
+{
+ BaseSimpleCPU::unserialize(cp, section);
+ UNSERIALIZE_ENUM(_status);
+ tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
+}
+
+void
+AtomicSimpleCPU::switchOut(Sampler *s)
+{
+ sampler = s;
+ if (status() == Running) {
+ _status = SwitchedOut;
+
+ tickEvent.squash();
+ }
+ sampler->signalSwitched();
+}
+
+
+void
+AtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
+{
+ BaseCPU::takeOverFrom(oldCPU);
+
+ assert(!tickEvent.scheduled());
+
+ // if any of this CPU's ExecContexts are active, mark the CPU as
+ // running and schedule its tick event.
+ for (int i = 0; i < execContexts.size(); ++i) {
+ ExecContext *xc = execContexts[i];
+ if (xc->status() == ExecContext::Active && _status != Running) {
+ _status = Running;
+ tickEvent.schedule(curTick);
+ break;
+ }
+ }
+}
+
+
+void
+AtomicSimpleCPU::activateContext(int thread_num, int delay)
+{
+ assert(thread_num == 0);
+ assert(cpuXC);
+
+ assert(_status == Idle);
+ assert(!tickEvent.scheduled());
+
+ notIdleFraction++;
+ tickEvent.schedule(curTick + cycles(delay));
+ _status = Running;
+}
+
+
+void
+AtomicSimpleCPU::suspendContext(int thread_num)
+{
+ assert(thread_num == 0);
+ assert(cpuXC);
+
+ assert(_status == Running);
+
+ // tick event may not be scheduled if this gets called from inside
+ // an instruction's execution, e.g. "quiesce"
+ if (tickEvent.scheduled())
+ tickEvent.deschedule();
+
+ notIdleFraction--;
+ _status = Idle;
+}
+
+
+template <class T>
+Fault
+AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags)
+{
+ data_read_req->setVaddr(addr);
+ data_read_req->setSize(sizeof(T));
+ data_read_req->setFlags(flags);
+ data_read_req->setTime(curTick);
+
+ if (traceData) {
+ traceData->setAddr(addr);
+ }
+
+ // translate to physical address
+ Fault fault = cpuXC->translateDataReadReq(data_read_req);
+
+ // Now do the access.
+ if (fault == NoFault) {
+ data_read_pkt->reset();
+ data_read_pkt->addr = data_read_req->getPaddr();
+ data_read_pkt->size = sizeof(T);
+
+ dcache_complete = dcachePort.sendAtomic(data_read_pkt);
+ dcache_access = true;
+
+ assert(data_read_pkt->result == Success);
+ data = data_read_pkt->get<T>();
+
+ }
+
+ // This will need a new way to tell if it has a dcache attached.
+ if (data_read_req->getFlags() & UNCACHEABLE)
+ recordEvent("Uncached Read");
+
+ return fault;
+}
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+template
+Fault
+AtomicSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
+
+template
+Fault
+AtomicSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
+
+template
+Fault
+AtomicSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
+
+template
+Fault
+AtomicSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
+
+#endif //DOXYGEN_SHOULD_SKIP_THIS
+
+template<>
+Fault
+AtomicSimpleCPU::read(Addr addr, double &data, unsigned flags)
+{
+ return read(addr, *(uint64_t*)&data, flags);
+}
+
+template<>
+Fault
+AtomicSimpleCPU::read(Addr addr, float &data, unsigned flags)
+{
+ return read(addr, *(uint32_t*)&data, flags);
+}
+
+
+template<>
+Fault
+AtomicSimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
+{
+ return read(addr, (uint32_t&)data, flags);
+}
+
+
+template <class T>
+Fault
+AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
+{
+ data_write_req->setVaddr(addr);
+ data_write_req->setTime(curTick);
+ data_write_req->setSize(sizeof(T));
+ data_write_req->setFlags(flags);
+
+ if (traceData) {
+ traceData->setAddr(addr);
+ }
+
+ // translate to physical address
+ Fault fault = cpuXC->translateDataWriteReq(data_write_req);
+
+ // Now do the access.
+ if (fault == NoFault) {
+ data_write_pkt->reset();
+ data = htog(data);
+ data_write_pkt->dataStatic(&data);
+ data_write_pkt->addr = data_write_req->getPaddr();
+ data_write_pkt->size = sizeof(T);
+
+ dcache_complete = dcachePort.sendAtomic(data_write_pkt);
+ dcache_access = true;
+
+ assert(data_write_pkt->result == Success);
+
+ if (res && data_write_req->getFlags() & LOCKED) {
+ *res = data_write_req->getScResult();
+ }
+ }
+
+ // This will need a new way to tell if it's hooked up to a cache or not.
+ if (data_write_req->getFlags() & UNCACHEABLE)
+ recordEvent("Uncached Write");
+
+ // If the write needs to have a fault on the access, consider calling
+ // changeStatus() and changing it to "bad addr write" or something.
+ return fault;
+}
+
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+template
+Fault
+AtomicSimpleCPU::write(uint64_t data, Addr addr,
+ unsigned flags, uint64_t *res);
+
+template
+Fault
+AtomicSimpleCPU::write(uint32_t data, Addr addr,
+ unsigned flags, uint64_t *res);
+
+template
+Fault
+AtomicSimpleCPU::write(uint16_t data, Addr addr,
+ unsigned flags, uint64_t *res);
+
+template
+Fault
+AtomicSimpleCPU::write(uint8_t data, Addr addr,
+ unsigned flags, uint64_t *res);
+
+#endif //DOXYGEN_SHOULD_SKIP_THIS
+
+template<>
+Fault
+AtomicSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
+{
+ return write(*(uint64_t*)&data, addr, flags, res);
+}
+
+template<>
+Fault
+AtomicSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
+{
+ return write(*(uint32_t*)&data, addr, flags, res);
+}
+
+
+template<>
+Fault
+AtomicSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
+{
+ return write((uint32_t)data, addr, flags, res);
+}
+
+
+void
+AtomicSimpleCPU::tick()
+{
+ Tick latency = cycles(1); // instruction takes one cycle by default
+
+ for (int i = 0; i < width; ++i) {
+ numCycles++;
+
+ checkForInterrupts();
+
+ ifetch_req->resetMin();
+ ifetch_pkt->reset();
+ Fault fault = setupFetchPacket(ifetch_pkt);
+
+ if (fault == NoFault) {
+ Tick icache_complete = icachePort.sendAtomic(ifetch_pkt);
+ // ifetch_req is initialized to read the instruction directly
+ // into the CPU object's inst field.
+
+ dcache_access = false; // assume no dcache access
+ preExecute();
+ fault = curStaticInst->execute(this, traceData);
+ postExecute();
+
+ if (traceData) {
+ traceData->finalize();
+ }
+
+ if (simulate_stalls) {
+ // This calculation assumes that the icache and dcache
+ // access latencies are always a multiple of the CPU's
+ // cycle time. If not, the next tick event may get
+ // scheduled at a non-integer multiple of the CPU
+ // cycle time.
+ Tick icache_stall = icache_complete - curTick - cycles(1);
+ Tick dcache_stall =
+ dcache_access ? dcache_complete - curTick - cycles(1) : 0;
+ latency += icache_stall + dcache_stall;
+ }
+
+ }
+
+ advancePC(fault);
+ }
+
+ if (_status != Idle)
+ tickEvent.schedule(curTick + latency);
+}
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// AtomicSimpleCPU Simulation Object
+//
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(AtomicSimpleCPU)
+
+ Param<Counter> max_insts_any_thread;
+ Param<Counter> max_insts_all_threads;
+ Param<Counter> max_loads_any_thread;
+ Param<Counter> max_loads_all_threads;
+ SimObjectParam<MemObject *> mem;
+
+#if FULL_SYSTEM
+ SimObjectParam<AlphaITB *> itb;
+ SimObjectParam<AlphaDTB *> dtb;
+ SimObjectParam<System *> system;
+ Param<int> cpu_id;
+ Param<Tick> profile;
+#else
+ SimObjectParam<Process *> workload;
+#endif // FULL_SYSTEM
+
+ Param<int> clock;
+
+ Param<bool> defer_registration;
+ Param<int> width;
+ Param<bool> function_trace;
+ Param<Tick> function_trace_start;
+ Param<bool> simulate_stalls;
+
+END_DECLARE_SIM_OBJECT_PARAMS(AtomicSimpleCPU)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(AtomicSimpleCPU)
+
+ INIT_PARAM(max_insts_any_thread,
+ "terminate when any thread reaches this inst count"),
+ INIT_PARAM(max_insts_all_threads,
+ "terminate when all threads have reached this inst count"),
+ INIT_PARAM(max_loads_any_thread,
+ "terminate when any thread reaches this load count"),
+ INIT_PARAM(max_loads_all_threads,
+ "terminate when all threads have reached this load count"),
+ INIT_PARAM(mem, "memory"),
+
+#if FULL_SYSTEM
+ INIT_PARAM(itb, "Instruction TLB"),
+ INIT_PARAM(dtb, "Data TLB"),
+ INIT_PARAM(system, "system object"),
+ INIT_PARAM(cpu_id, "processor ID"),
+ INIT_PARAM(profile, ""),
+#else
+ INIT_PARAM(workload, "processes to run"),
+#endif // FULL_SYSTEM
+
+ INIT_PARAM(clock, "clock speed"),
+ INIT_PARAM(defer_registration, "defer system registration (for sampling)"),
+ INIT_PARAM(width, "cpu width"),
+ INIT_PARAM(function_trace, "Enable function trace"),
+ INIT_PARAM(function_trace_start, "Cycle to start function trace"),
+ INIT_PARAM(simulate_stalls, "Simulate cache stall cycles")
+
+END_INIT_SIM_OBJECT_PARAMS(AtomicSimpleCPU)
+
+
+CREATE_SIM_OBJECT(AtomicSimpleCPU)
+{
+ AtomicSimpleCPU::Params *params = new AtomicSimpleCPU::Params();
+ params->name = getInstanceName();
+ params->numberOfThreads = 1;
+ params->max_insts_any_thread = max_insts_any_thread;
+ params->max_insts_all_threads = max_insts_all_threads;
+ params->max_loads_any_thread = max_loads_any_thread;
+ params->max_loads_all_threads = max_loads_all_threads;
+ params->deferRegistration = defer_registration;
+ params->clock = clock;
+ params->functionTrace = function_trace;
+ params->functionTraceStart = function_trace_start;
+ params->width = width;
+ params->simulate_stalls = simulate_stalls;
+ params->mem = mem;
+
+#if FULL_SYSTEM
+ params->itb = itb;
+ params->dtb = dtb;
+ params->system = system;
+ params->cpu_id = cpu_id;
+ params->profile = profile;
+#else
+ params->process = workload;
+#endif
+
+ AtomicSimpleCPU *cpu = new AtomicSimpleCPU(params);
+ return cpu;
+}
+
+REGISTER_SIM_OBJECT("AtomicSimpleCPU", AtomicSimpleCPU)
+
diff --git a/src/cpu/simple/atomic.hh b/src/cpu/simple/atomic.hh
new file mode 100644
index 000000000..d0ba085f0
--- /dev/null
+++ b/src/cpu/simple/atomic.hh
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPU_SIMPLE_ATOMIC_HH__
+#define __CPU_SIMPLE_ATOMIC_HH__
+
+#include "cpu/simple/base.hh"
+
+class AtomicSimpleCPU : public BaseSimpleCPU
+{
+ public:
+
+ struct Params : public BaseSimpleCPU::Params {
+ int width;
+ bool simulate_stalls;
+ };
+
+ AtomicSimpleCPU(Params *params);
+ virtual ~AtomicSimpleCPU();
+
+ virtual void init();
+
+ public:
+ //
+ enum Status {
+ Running,
+ Idle,
+ SwitchedOut
+ };
+
+ protected:
+ Status _status;
+
+ Status status() const { return _status; }
+
+ private:
+
+ struct TickEvent : public Event
+ {
+ AtomicSimpleCPU *cpu;
+
+ TickEvent(AtomicSimpleCPU *c);
+ void process();
+ const char *description();
+ };
+
+ TickEvent tickEvent;
+
+ const int width;
+ const bool simulate_stalls;
+
+ // main simulation loop (one cycle)
+ void tick();
+
+ class CpuPort : public Port
+ {
+
+ AtomicSimpleCPU *cpu;
+
+ public:
+
+ CpuPort(AtomicSimpleCPU *_cpu)
+ : cpu(_cpu)
+ { }
+
+ protected:
+
+ virtual bool recvTiming(Packet *pkt);
+
+ virtual Tick recvAtomic(Packet *pkt);
+
+ virtual void recvFunctional(Packet *pkt);
+
+ virtual void recvStatusChange(Status status);
+
+ virtual Packet *recvRetry();
+
+ virtual void getDeviceAddressRanges(AddrRangeList &resp,
+ AddrRangeList &snoop)
+ { resp.clear(); snoop.clear(); }
+ };
+
+ CpuPort icachePort;
+ CpuPort dcachePort;
+
+ Request *ifetch_req;
+ Packet *ifetch_pkt;
+ Request *data_read_req;
+ Packet *data_read_pkt;
+ Request *data_write_req;
+ Packet *data_write_pkt;
+
+ bool dcache_access;
+ Tick dcache_complete;
+
+ public:
+
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+
+ void switchOut(Sampler *s);
+ void takeOverFrom(BaseCPU *oldCPU);
+
+ virtual void activateContext(int thread_num, int delay);
+ virtual void suspendContext(int thread_num);
+
+ template <class T>
+ Fault read(Addr addr, T &data, unsigned flags);
+
+ template <class T>
+ Fault write(T data, Addr addr, unsigned flags, uint64_t *res);
+};
+
+#endif // __CPU_SIMPLE_ATOMIC_HH__
diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc
new file mode 100644
index 000000000..30c002ed5
--- /dev/null
+++ b/src/cpu/simple/base.cc
@@ -0,0 +1,478 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "arch/utility.hh"
+#include "base/cprintf.hh"
+#include "base/inifile.hh"
+#include "base/loader/symtab.hh"
+#include "base/misc.hh"
+#include "base/pollevent.hh"
+#include "base/range.hh"
+#include "base/stats/events.hh"
+#include "base/trace.hh"
+#include "cpu/base.hh"
+#include "cpu/cpu_exec_context.hh"
+#include "cpu/exec_context.hh"
+#include "cpu/exetrace.hh"
+#include "cpu/profile.hh"
+#include "cpu/sampler/sampler.hh"
+#include "cpu/simple/base.hh"
+#include "cpu/smt.hh"
+#include "cpu/static_inst.hh"
+#include "kern/kernel_stats.hh"
+#include "mem/packet_impl.hh"
+#include "sim/byteswap.hh"
+#include "sim/builder.hh"
+#include "sim/debug.hh"
+#include "sim/host.hh"
+#include "sim/sim_events.hh"
+#include "sim/sim_object.hh"
+#include "sim/stats.hh"
+
+#if FULL_SYSTEM
+#include "base/remote_gdb.hh"
+#include "sim/system.hh"
+#include "arch/tlb.hh"
+#include "arch/stacktrace.hh"
+#include "arch/vtophys.hh"
+#else // !FULL_SYSTEM
+#include "mem/mem_object.hh"
+#endif // FULL_SYSTEM
+
+using namespace std;
+using namespace TheISA;
+
+BaseSimpleCPU::BaseSimpleCPU(Params *p)
+ : BaseCPU(p), mem(p->mem), cpuXC(NULL)
+{
+#if FULL_SYSTEM
+ cpuXC = new CPUExecContext(this, 0, p->system, p->itb, p->dtb);
+#else
+ cpuXC = new CPUExecContext(this, /* thread_num */ 0, p->process,
+ /* asid */ 0, mem);
+#endif // !FULL_SYSTEM
+
+ xcProxy = cpuXC->getProxy();
+
+ numInst = 0;
+ startNumInst = 0;
+ numLoad = 0;
+ startNumLoad = 0;
+ lastIcacheStall = 0;
+ lastDcacheStall = 0;
+
+ execContexts.push_back(xcProxy);
+}
+
+BaseSimpleCPU::~BaseSimpleCPU()
+{
+}
+
+void
+BaseSimpleCPU::deallocateContext(int thread_num)
+{
+ // for now, these are equivalent
+ suspendContext(thread_num);
+}
+
+
+void
+BaseSimpleCPU::haltContext(int thread_num)
+{
+ // for now, these are equivalent
+ suspendContext(thread_num);
+}
+
+
+void
+BaseSimpleCPU::regStats()
+{
+ using namespace Stats;
+
+ BaseCPU::regStats();
+
+ numInsts
+ .name(name() + ".num_insts")
+ .desc("Number of instructions executed")
+ ;
+
+ numMemRefs
+ .name(name() + ".num_refs")
+ .desc("Number of memory references")
+ ;
+
+ notIdleFraction
+ .name(name() + ".not_idle_fraction")
+ .desc("Percentage of non-idle cycles")
+ ;
+
+ idleFraction
+ .name(name() + ".idle_fraction")
+ .desc("Percentage of idle cycles")
+ ;
+
+ icacheStallCycles
+ .name(name() + ".icache_stall_cycles")
+ .desc("ICache total stall cycles")
+ .prereq(icacheStallCycles)
+ ;
+
+ dcacheStallCycles
+ .name(name() + ".dcache_stall_cycles")
+ .desc("DCache total stall cycles")
+ .prereq(dcacheStallCycles)
+ ;
+
+ icacheRetryCycles
+ .name(name() + ".icache_retry_cycles")
+ .desc("ICache total retry cycles")
+ .prereq(icacheRetryCycles)
+ ;
+
+ dcacheRetryCycles
+ .name(name() + ".dcache_retry_cycles")
+ .desc("DCache total retry cycles")
+ .prereq(dcacheRetryCycles)
+ ;
+
+ idleFraction = constant(1.0) - notIdleFraction;
+}
+
+void
+BaseSimpleCPU::resetStats()
+{
+ startNumInst = numInst;
+ // notIdleFraction = (_status != Idle);
+}
+
+void
+BaseSimpleCPU::serialize(ostream &os)
+{
+ BaseCPU::serialize(os);
+ SERIALIZE_SCALAR(inst);
+ nameOut(os, csprintf("%s.xc", name()));
+ cpuXC->serialize(os);
+}
+
+void
+BaseSimpleCPU::unserialize(Checkpoint *cp, const string &section)
+{
+ BaseCPU::unserialize(cp, section);
+ UNSERIALIZE_SCALAR(inst);
+ cpuXC->unserialize(cp, csprintf("%s.xc", section));
+}
+
+void
+change_thread_state(int thread_number, int activate, int priority)
+{
+}
+
+Fault
+BaseSimpleCPU::copySrcTranslate(Addr src)
+{
+#if 0
+ static bool no_warn = true;
+ int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
+ // Only support block sizes of 64 atm.
+ assert(blk_size == 64);
+ int offset = src & (blk_size - 1);
+
+ // Make sure block doesn't span page
+ if (no_warn &&
+ (src & PageMask) != ((src + blk_size) & PageMask) &&
+ (src >> 40) != 0xfffffc) {
+ warn("Copied block source spans pages %x.", src);
+ no_warn = false;
+ }
+
+ memReq->reset(src & ~(blk_size - 1), blk_size);
+
+ // translate to physical address
+ Fault fault = cpuXC->translateDataReadReq(req);
+
+ if (fault == NoFault) {
+ cpuXC->copySrcAddr = src;
+ cpuXC->copySrcPhysAddr = memReq->paddr + offset;
+ } else {
+ assert(!fault->isAlignmentFault());
+
+ cpuXC->copySrcAddr = 0;
+ cpuXC->copySrcPhysAddr = 0;
+ }
+ return fault;
+#else
+ return NoFault;
+#endif
+}
+
+Fault
+BaseSimpleCPU::copy(Addr dest)
+{
+#if 0
+ static bool no_warn = true;
+ int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
+ // Only support block sizes of 64 atm.
+ assert(blk_size == 64);
+ uint8_t data[blk_size];
+ //assert(cpuXC->copySrcAddr);
+ int offset = dest & (blk_size - 1);
+
+ // Make sure block doesn't span page
+ if (no_warn &&
+ (dest & PageMask) != ((dest + blk_size) & PageMask) &&
+ (dest >> 40) != 0xfffffc) {
+ no_warn = false;
+ warn("Copied block destination spans pages %x. ", dest);
+ }
+
+ memReq->reset(dest & ~(blk_size -1), blk_size);
+ // translate to physical address
+ Fault fault = cpuXC->translateDataWriteReq(req);
+
+ if (fault == NoFault) {
+ Addr dest_addr = memReq->paddr + offset;
+ // Need to read straight from memory since we have more than 8 bytes.
+ memReq->paddr = cpuXC->copySrcPhysAddr;
+ cpuXC->mem->read(memReq, data);
+ memReq->paddr = dest_addr;
+ cpuXC->mem->write(memReq, data);
+ if (dcacheInterface) {
+ memReq->cmd = Copy;
+ memReq->completionEvent = NULL;
+ memReq->paddr = cpuXC->copySrcPhysAddr;
+ memReq->dest = dest_addr;
+ memReq->size = 64;
+ memReq->time = curTick;
+ memReq->flags &= ~INST_READ;
+ dcacheInterface->access(memReq);
+ }
+ }
+ else
+ assert(!fault->isAlignmentFault());
+
+ return fault;
+#else
+ panic("copy not implemented");
+ return NoFault;
+#endif
+}
+
+#if FULL_SYSTEM
+Addr
+BaseSimpleCPU::dbg_vtophys(Addr addr)
+{
+ return vtophys(xcProxy, addr);
+}
+#endif // FULL_SYSTEM
+
+#if FULL_SYSTEM
+void
+BaseSimpleCPU::post_interrupt(int int_num, int index)
+{
+ BaseCPU::post_interrupt(int_num, index);
+
+ if (cpuXC->status() == ExecContext::Suspended) {
+ DPRINTF(IPI,"Suspended Processor awoke\n");
+ cpuXC->activate();
+ }
+}
+#endif // FULL_SYSTEM
+
+void
+BaseSimpleCPU::checkForInterrupts()
+{
+#if FULL_SYSTEM
+ if (checkInterrupts && check_interrupts() && !cpuXC->inPalMode()) {
+ int ipl = 0;
+ int summary = 0;
+ checkInterrupts = false;
+
+ if (cpuXC->readMiscReg(IPR_SIRR)) {
+ for (int i = INTLEVEL_SOFTWARE_MIN;
+ i < INTLEVEL_SOFTWARE_MAX; i++) {
+ if (cpuXC->readMiscReg(IPR_SIRR) & (ULL(1) << i)) {
+ // See table 4-19 of 21164 hardware reference
+ ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1;
+ summary |= (ULL(1) << i);
+ }
+ }
+ }
+
+ uint64_t interrupts = cpuXC->cpu->intr_status();
+ for (int i = INTLEVEL_EXTERNAL_MIN;
+ i < INTLEVEL_EXTERNAL_MAX; i++) {
+ if (interrupts & (ULL(1) << i)) {
+ // See table 4-19 of 21164 hardware reference
+ ipl = i;
+ summary |= (ULL(1) << i);
+ }
+ }
+
+ if (cpuXC->readMiscReg(IPR_ASTRR))
+ panic("asynchronous traps not implemented\n");
+
+ if (ipl && ipl > cpuXC->readMiscReg(IPR_IPLR)) {
+ cpuXC->setMiscReg(IPR_ISR, summary);
+ cpuXC->setMiscReg(IPR_INTID, ipl);
+
+ Fault(new InterruptFault)->invoke(xcProxy);
+
+ DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n",
+ cpuXC->readMiscReg(IPR_IPLR), ipl, summary);
+ }
+ }
+#endif
+}
+
+
+Fault
+BaseSimpleCPU::setupFetchPacket(Packet *ifetch_pkt)
+{
+ // Try to fetch an instruction
+
+ // set up memory request for instruction fetch
+
+ DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p NNPC:%08p\n",cpuXC->readPC(),
+ cpuXC->readNextPC(),cpuXC->readNextNPC());
+
+ Request *ifetch_req = ifetch_pkt->req;
+ ifetch_req->setVaddr(cpuXC->readPC() & ~3);
+ ifetch_req->setTime(curTick);
+#if FULL_SYSTEM
+ ifetch_req->setFlags((cpuXC->readPC() & 1) ? PHYSICAL : 0);
+#else
+ ifetch_req->setFlags(0);
+#endif
+
+ Fault fault = cpuXC->translateInstReq(ifetch_req);
+
+ if (fault == NoFault) {
+ ifetch_pkt->addr = ifetch_req->getPaddr();
+ }
+
+ return fault;
+}
+
+
+void
+BaseSimpleCPU::preExecute()
+{
+ // maintain $r0 semantics
+ cpuXC->setIntReg(ZeroReg, 0);
+#if THE_ISA == ALPHA_ISA
+ cpuXC->setFloatReg(ZeroReg, 0.0);
+#endif // ALPHA_ISA
+
+ // keep an instruction count
+ numInst++;
+ numInsts++;
+
+ cpuXC->func_exe_inst++;
+
+ // check for instruction-count-based events
+ comInstEventQueue[0]->serviceEvents(numInst);
+
+ // decode the instruction
+ inst = gtoh(inst);
+ curStaticInst = StaticInst::decode(makeExtMI(inst, cpuXC->readPC()));
+
+ traceData = Trace::getInstRecord(curTick, xcProxy, this, curStaticInst,
+ cpuXC->readPC());
+
+ DPRINTF(Decode,"Decode: Decoded %s instruction (opcode: 0x%x): 0x%x\n",
+ curStaticInst->getName(), curStaticInst->getOpcode(),
+ curStaticInst->machInst);
+
+#if FULL_SYSTEM
+ cpuXC->setInst(inst);
+#endif // FULL_SYSTEM
+}
+
+void
+BaseSimpleCPU::postExecute()
+{
+#if FULL_SYSTEM
+ if (system->kernelBinning->fnbin) {
+ assert(kernelStats);
+ system->kernelBinning->execute(xcProxy, inst);
+ }
+
+ if (cpuXC->profile) {
+ bool usermode =
+ (cpuXC->readMiscReg(AlphaISA::IPR_DTB_CM) & 0x18) != 0;
+ cpuXC->profilePC = usermode ? 1 : cpuXC->readPC();
+ ProfileNode *node = cpuXC->profile->consume(xcProxy, inst);
+ if (node)
+ cpuXC->profileNode = node;
+ }
+#endif
+
+ if (curStaticInst->isMemRef()) {
+ numMemRefs++;
+ }
+
+ if (curStaticInst->isLoad()) {
+ ++numLoad;
+ comLoadEventQueue[0]->serviceEvents(numLoad);
+ }
+
+ traceFunctions(cpuXC->readPC());
+}
+
+
+void
+BaseSimpleCPU::advancePC(Fault fault)
+{
+ if (fault != NoFault) {
+#if FULL_SYSTEM
+ fault->invoke(xcProxy);
+#else // !FULL_SYSTEM
+ fatal("fault (%s) detected @ PC %08p", fault->name(), cpuXC->readPC());
+#endif // FULL_SYSTEM
+ }
+ else {
+ // go to the next instruction
+ cpuXC->setPC(cpuXC->readNextPC());
+#if THE_ISA == ALPHA_ISA
+ cpuXC->setNextPC(cpuXC->readNextPC() + sizeof(MachInst));
+#else
+ cpuXC->setNextPC(cpuXC->readNextNPC());
+ cpuXC->setNextNPC(cpuXC->readNextNPC() + sizeof(MachInst));
+#endif
+
+ }
+
+#if FULL_SYSTEM
+ Addr oldpc;
+ do {
+ oldpc = cpuXC->readPC();
+ system->pcEventQueue.service(xcProxy);
+ } while (oldpc != cpuXC->readPC());
+#endif
+}
+
diff --git a/src/cpu/simple/base.hh b/src/cpu/simple/base.hh
new file mode 100644
index 000000000..4c0e6f3c7
--- /dev/null
+++ b/src/cpu/simple/base.hh
@@ -0,0 +1,316 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPU_SIMPLE_BASE_HH__
+#define __CPU_SIMPLE_BASE_HH__
+
+#include "base/statistics.hh"
+#include "config/full_system.hh"
+#include "cpu/base.hh"
+#include "cpu/cpu_exec_context.hh"
+#include "cpu/pc_event.hh"
+#include "cpu/sampler/sampler.hh"
+#include "cpu/static_inst.hh"
+#include "mem/packet.hh"
+#include "mem/port.hh"
+#include "mem/request.hh"
+#include "sim/eventq.hh"
+
+// forward declarations
+#if FULL_SYSTEM
+class Processor;
+class AlphaITB;
+class AlphaDTB;
+class MemObject;
+
+class RemoteGDB;
+class GDBListener;
+
+#else
+
+class Process;
+
+#endif // FULL_SYSTEM
+
+class ExecContext;
+class Checkpoint;
+
+namespace Trace {
+ class InstRecord;
+}
+
+
+class BaseSimpleCPU : public BaseCPU
+{
+ protected:
+ typedef TheISA::MachInst MachInst;
+ typedef TheISA::MiscReg MiscReg;
+ typedef TheISA::FloatReg FloatReg;
+ typedef TheISA::FloatRegBits FloatRegBits;
+
+ MemObject *mem;
+
+ protected:
+ Trace::InstRecord *traceData;
+
+ public:
+ void post_interrupt(int int_num, int index);
+
+ void zero_fill_64(Addr addr) {
+ static int warned = 0;
+ if (!warned) {
+ warn ("WH64 is not implemented");
+ warned = 1;
+ }
+ };
+
+ public:
+ struct Params : public BaseCPU::Params
+ {
+ MemObject *mem;
+#if FULL_SYSTEM
+ AlphaITB *itb;
+ AlphaDTB *dtb;
+#else
+ Process *process;
+#endif
+ };
+ BaseSimpleCPU(Params *params);
+ virtual ~BaseSimpleCPU();
+
+ public:
+ // execution context
+ CPUExecContext *cpuXC;
+
+ ExecContext *xcProxy;
+
+#if FULL_SYSTEM
+ Addr dbg_vtophys(Addr addr);
+
+ bool interval_stats;
+#endif
+
+ // current instruction
+ MachInst inst;
+
+ // Static data storage
+ TheISA::IntReg dataReg;
+
+ // Pointer to the sampler that is telling us to switchover.
+ // Used to signal the completion of the pipe drain and schedule
+ // the next switchover
+ Sampler *sampler;
+
+ StaticInstPtr curStaticInst;
+
+ void checkForInterrupts();
+ Fault setupFetchPacket(Packet *ifetch_pkt);
+ void preExecute();
+ void postExecute();
+ void advancePC(Fault fault);
+
+ virtual void deallocateContext(int thread_num);
+ virtual void haltContext(int thread_num);
+
+ // statistics
+ virtual void regStats();
+ virtual void resetStats();
+
+ // number of simulated instructions
+ Counter numInst;
+ Counter startNumInst;
+ Stats::Scalar<> numInsts;
+
+ virtual Counter totalInstructions() const
+ {
+ return numInst - startNumInst;
+ }
+
+ // number of simulated memory references
+ Stats::Scalar<> numMemRefs;
+
+ // number of simulated loads
+ Counter numLoad;
+ Counter startNumLoad;
+
+ // number of idle cycles
+ Stats::Average<> notIdleFraction;
+ Stats::Formula idleFraction;
+
+ // number of cycles stalled for I-cache responses
+ Stats::Scalar<> icacheStallCycles;
+ Counter lastIcacheStall;
+
+ // number of cycles stalled for I-cache retries
+ Stats::Scalar<> icacheRetryCycles;
+ Counter lastIcacheRetry;
+
+ // number of cycles stalled for D-cache responses
+ Stats::Scalar<> dcacheStallCycles;
+ Counter lastDcacheStall;
+
+ // number of cycles stalled for D-cache retries
+ Stats::Scalar<> dcacheRetryCycles;
+ Counter lastDcacheRetry;
+
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+
+ // These functions are only used in CPU models that split
+ // effective address computation from the actual memory access.
+ void setEA(Addr EA) { panic("BaseSimpleCPU::setEA() not implemented\n"); }
+ Addr getEA() { panic("BaseSimpleCPU::getEA() not implemented\n"); }
+
+ void prefetch(Addr addr, unsigned flags)
+ {
+ // need to do this...
+ }
+
+ void writeHint(Addr addr, int size, unsigned flags)
+ {
+ // need to do this...
+ }
+
+ Fault copySrcTranslate(Addr src);
+
+ Fault copy(Addr dest);
+
+ // The register accessor methods provide the index of the
+ // instruction's operand (e.g., 0 or 1), not the architectural
+ // register index, to simplify the implementation of register
+ // renaming. We find the architectural register index by indexing
+ // into the instruction's own operand index table. Note that a
+ // raw pointer to the StaticInst is provided instead of a
+ // ref-counted StaticInstPtr to redice overhead. This is fine as
+ // long as these methods don't copy the pointer into any long-term
+ // storage (which is pretty hard to imagine they would have reason
+ // to do).
+
+ uint64_t readIntReg(const StaticInst *si, int idx)
+ {
+ return cpuXC->readIntReg(si->srcRegIdx(idx));
+ }
+
+ FloatReg readFloatReg(const StaticInst *si, int idx, int width)
+ {
+ int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag;
+ return cpuXC->readFloatReg(reg_idx, width);
+ }
+
+ FloatReg readFloatReg(const StaticInst *si, int idx)
+ {
+ int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag;
+ return cpuXC->readFloatReg(reg_idx);
+ }
+
+ FloatRegBits readFloatRegBits(const StaticInst *si, int idx, int width)
+ {
+ int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag;
+ return cpuXC->readFloatRegBits(reg_idx, width);
+ }
+
+ FloatRegBits readFloatRegBits(const StaticInst *si, int idx)
+ {
+ int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag;
+ return cpuXC->readFloatRegBits(reg_idx);
+ }
+
+ void setIntReg(const StaticInst *si, int idx, uint64_t val)
+ {
+ cpuXC->setIntReg(si->destRegIdx(idx), val);
+ }
+
+ void setFloatReg(const StaticInst *si, int idx, FloatReg val, int width)
+ {
+ int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
+ cpuXC->setFloatReg(reg_idx, val, width);
+ }
+
+ void setFloatReg(const StaticInst *si, int idx, FloatReg val)
+ {
+ int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
+ cpuXC->setFloatReg(reg_idx, val);
+ }
+
+ void setFloatRegBits(const StaticInst *si, int idx,
+ FloatRegBits val, int width)
+ {
+ int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
+ cpuXC->setFloatRegBits(reg_idx, val, width);
+ }
+
+ void setFloatRegBits(const StaticInst *si, int idx, FloatRegBits val)
+ {
+ int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
+ cpuXC->setFloatRegBits(reg_idx, val);
+ }
+
+ uint64_t readPC() { return cpuXC->readPC(); }
+ uint64_t readNextPC() { return cpuXC->readNextPC(); }
+ uint64_t readNextNPC() { return cpuXC->readNextNPC(); }
+
+ void setPC(uint64_t val) { cpuXC->setPC(val); }
+ void setNextPC(uint64_t val) { cpuXC->setNextPC(val); }
+ void setNextNPC(uint64_t val) { cpuXC->setNextNPC(val); }
+
+ MiscReg readMiscReg(int misc_reg)
+ {
+ return cpuXC->readMiscReg(misc_reg);
+ }
+
+ MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault)
+ {
+ return cpuXC->readMiscRegWithEffect(misc_reg, fault);
+ }
+
+ Fault setMiscReg(int misc_reg, const MiscReg &val)
+ {
+ return cpuXC->setMiscReg(misc_reg, val);
+ }
+
+ Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val)
+ {
+ return cpuXC->setMiscRegWithEffect(misc_reg, val);
+ }
+
+#if FULL_SYSTEM
+ Fault hwrei() { return cpuXC->hwrei(); }
+ int readIntrFlag() { return cpuXC->readIntrFlag(); }
+ void setIntrFlag(int val) { cpuXC->setIntrFlag(val); }
+ bool inPalMode() { return cpuXC->inPalMode(); }
+ void ev5_trap(Fault fault) { fault->invoke(xcProxy); }
+ bool simPalCheck(int palFunc) { return cpuXC->simPalCheck(palFunc); }
+#else
+ void syscall(int64_t callnum) { cpuXC->syscall(callnum); }
+#endif
+
+ bool misspeculating() { return cpuXC->misspeculating(); }
+ ExecContext *xcBase() { return xcProxy; }
+};
+
+#endif // __CPU_SIMPLE_BASE_HH__
diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc
new file mode 100644
index 000000000..70b88c4b1
--- /dev/null
+++ b/src/cpu/simple/timing.cc
@@ -0,0 +1,570 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "arch/utility.hh"
+#include "cpu/exetrace.hh"
+#include "cpu/simple/timing.hh"
+#include "mem/packet_impl.hh"
+#include "sim/builder.hh"
+
+using namespace std;
+using namespace TheISA;
+
+
+void
+TimingSimpleCPU::init()
+{
+ //Create Memory Ports (conect them up)
+ Port *mem_dport = mem->getPort("");
+ dcachePort.setPeer(mem_dport);
+ mem_dport->setPeer(&dcachePort);
+
+ Port *mem_iport = mem->getPort("");
+ icachePort.setPeer(mem_iport);
+ mem_iport->setPeer(&icachePort);
+
+ BaseCPU::init();
+#if FULL_SYSTEM
+ for (int i = 0; i < execContexts.size(); ++i) {
+ ExecContext *xc = execContexts[i];
+
+ // initialize CPU, including PC
+ TheISA::initCPU(xc, xc->readCpuId());
+ }
+#endif
+}
+
+Tick
+TimingSimpleCPU::CpuPort::recvAtomic(Packet *pkt)
+{
+ panic("TimingSimpleCPU doesn't expect recvAtomic callback!");
+ return curTick;
+}
+
+void
+TimingSimpleCPU::CpuPort::recvFunctional(Packet *pkt)
+{
+ panic("TimingSimpleCPU doesn't expect recvFunctional callback!");
+}
+
+void
+TimingSimpleCPU::CpuPort::recvStatusChange(Status status)
+{
+ if (status == RangeChange)
+ return;
+
+ panic("TimingSimpleCPU doesn't expect recvStatusChange callback!");
+}
+
+TimingSimpleCPU::TimingSimpleCPU(Params *p)
+ : BaseSimpleCPU(p), icachePort(this), dcachePort(this)
+{
+ _status = Idle;
+ ifetch_pkt = dcache_pkt = NULL;
+}
+
+
+TimingSimpleCPU::~TimingSimpleCPU()
+{
+}
+
+void
+TimingSimpleCPU::serialize(ostream &os)
+{
+ BaseSimpleCPU::serialize(os);
+ SERIALIZE_ENUM(_status);
+}
+
+void
+TimingSimpleCPU::unserialize(Checkpoint *cp, const string &section)
+{
+ BaseSimpleCPU::unserialize(cp, section);
+ UNSERIALIZE_ENUM(_status);
+}
+
+void
+TimingSimpleCPU::switchOut(Sampler *s)
+{
+ sampler = s;
+ if (status() == Running) {
+ _status = SwitchedOut;
+ }
+ sampler->signalSwitched();
+}
+
+
+void
+TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
+{
+ BaseCPU::takeOverFrom(oldCPU);
+
+ // if any of this CPU's ExecContexts are active, mark the CPU as
+ // running and schedule its tick event.
+ for (int i = 0; i < execContexts.size(); ++i) {
+ ExecContext *xc = execContexts[i];
+ if (xc->status() == ExecContext::Active && _status != Running) {
+ _status = Running;
+ break;
+ }
+ }
+}
+
+
+void
+TimingSimpleCPU::activateContext(int thread_num, int delay)
+{
+ assert(thread_num == 0);
+ assert(cpuXC);
+
+ assert(_status == Idle);
+
+ notIdleFraction++;
+ _status = Running;
+ // kick things off by initiating the fetch of the next instruction
+ Event *e =
+ new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, true);
+ e->schedule(curTick + cycles(delay));
+}
+
+
+void
+TimingSimpleCPU::suspendContext(int thread_num)
+{
+ assert(thread_num == 0);
+ assert(cpuXC);
+
+ panic("TimingSimpleCPU::suspendContext not implemented");
+
+ assert(_status == Running);
+
+ notIdleFraction--;
+ _status = Idle;
+}
+
+
+template <class T>
+Fault
+TimingSimpleCPU::read(Addr addr, T &data, unsigned flags)
+{
+ Request *data_read_req = new Request(true);
+
+ data_read_req->setVaddr(addr);
+ data_read_req->setSize(sizeof(T));
+ data_read_req->setFlags(flags);
+ data_read_req->setTime(curTick);
+
+ if (traceData) {
+ traceData->setAddr(data_read_req->getVaddr());
+ }
+
+ // translate to physical address
+ Fault fault = cpuXC->translateDataReadReq(data_read_req);
+
+ // Now do the access.
+ if (fault == NoFault) {
+ Packet *data_read_pkt = new Packet;
+ data_read_pkt->cmd = Read;
+ data_read_pkt->req = data_read_req;
+ data_read_pkt->dataDynamic<T>(new T);
+ data_read_pkt->addr = data_read_req->getPaddr();
+ data_read_pkt->size = sizeof(T);
+ data_read_pkt->dest = Packet::Broadcast;
+
+ if (!dcachePort.sendTiming(data_read_pkt)) {
+ _status = DcacheRetry;
+ dcache_pkt = data_read_pkt;
+ } else {
+ _status = DcacheWaitResponse;
+ dcache_pkt = NULL;
+ }
+ }
+
+ // This will need a new way to tell if it has a dcache attached.
+ if (data_read_req->getFlags() & UNCACHEABLE)
+ recordEvent("Uncached Read");
+
+ return fault;
+}
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+template
+Fault
+TimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
+
+template
+Fault
+TimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
+
+template
+Fault
+TimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
+
+template
+Fault
+TimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
+
+#endif //DOXYGEN_SHOULD_SKIP_THIS
+
+template<>
+Fault
+TimingSimpleCPU::read(Addr addr, double &data, unsigned flags)
+{
+ return read(addr, *(uint64_t*)&data, flags);
+}
+
+template<>
+Fault
+TimingSimpleCPU::read(Addr addr, float &data, unsigned flags)
+{
+ return read(addr, *(uint32_t*)&data, flags);
+}
+
+
+template<>
+Fault
+TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
+{
+ return read(addr, (uint32_t&)data, flags);
+}
+
+
+template <class T>
+Fault
+TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
+{
+ Request *data_write_req = new Request(true);
+ data_write_req->setVaddr(addr);
+ data_write_req->setTime(curTick);
+ data_write_req->setSize(sizeof(T));
+ data_write_req->setFlags(flags);
+
+ // translate to physical address
+ Fault fault = cpuXC->translateDataWriteReq(data_write_req);
+ // Now do the access.
+ if (fault == NoFault) {
+ Packet *data_write_pkt = new Packet;
+ data_write_pkt->cmd = Write;
+ data_write_pkt->req = data_write_req;
+ data_write_pkt->allocate();
+ data_write_pkt->size = sizeof(T);
+ data_write_pkt->set(data);
+ data_write_pkt->addr = data_write_req->getPaddr();
+ data_write_pkt->dest = Packet::Broadcast;
+
+ if (!dcachePort.sendTiming(data_write_pkt)) {
+ _status = DcacheRetry;
+ dcache_pkt = data_write_pkt;
+ } else {
+ _status = DcacheWaitResponse;
+ dcache_pkt = NULL;
+ }
+ }
+
+ // This will need a new way to tell if it's hooked up to a cache or not.
+ if (data_write_req->getFlags() & UNCACHEABLE)
+ recordEvent("Uncached Write");
+
+ // If the write needs to have a fault on the access, consider calling
+ // changeStatus() and changing it to "bad addr write" or something.
+ return fault;
+}
+
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+template
+Fault
+TimingSimpleCPU::write(uint64_t data, Addr addr,
+ unsigned flags, uint64_t *res);
+
+template
+Fault
+TimingSimpleCPU::write(uint32_t data, Addr addr,
+ unsigned flags, uint64_t *res);
+
+template
+Fault
+TimingSimpleCPU::write(uint16_t data, Addr addr,
+ unsigned flags, uint64_t *res);
+
+template
+Fault
+TimingSimpleCPU::write(uint8_t data, Addr addr,
+ unsigned flags, uint64_t *res);
+
+#endif //DOXYGEN_SHOULD_SKIP_THIS
+
+template<>
+Fault
+TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
+{
+ return write(*(uint64_t*)&data, addr, flags, res);
+}
+
+template<>
+Fault
+TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
+{
+ return write(*(uint32_t*)&data, addr, flags, res);
+}
+
+
+template<>
+Fault
+TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
+{
+ return write((uint32_t)data, addr, flags, res);
+}
+
+
+void
+TimingSimpleCPU::fetch()
+{
+ checkForInterrupts();
+
+ Request *ifetch_req = new Request(true);
+ ifetch_req->setSize(sizeof(MachInst));
+
+ ifetch_pkt = new Packet;
+ ifetch_pkt->cmd = Read;
+ ifetch_pkt->dataStatic(&inst);
+ ifetch_pkt->req = ifetch_req;
+ ifetch_pkt->size = sizeof(MachInst);
+ ifetch_pkt->dest = Packet::Broadcast;
+
+ Fault fault = setupFetchPacket(ifetch_pkt);
+ if (fault == NoFault) {
+ if (!icachePort.sendTiming(ifetch_pkt)) {
+ // Need to wait for retry
+ _status = IcacheRetry;
+ } else {
+ // Need to wait for cache to respond
+ _status = IcacheWaitResponse;
+ // ownership of packet transferred to memory system
+ ifetch_pkt = NULL;
+ }
+ } else {
+ panic("TimingSimpleCPU fetch fault handling not implemented");
+ }
+}
+
+
+void
+TimingSimpleCPU::completeInst(Fault fault)
+{
+ postExecute();
+
+ if (traceData) {
+ traceData->finalize();
+ }
+
+ advancePC(fault);
+
+ if (_status == Running) {
+ // kick off fetch of next instruction... callback from icache
+ // response will cause that instruction to be executed,
+ // keeping the CPU running.
+ fetch();
+ }
+}
+
+
+void
+TimingSimpleCPU::completeIfetch()
+{
+ // received a response from the icache: execute the received
+ // instruction
+ assert(_status == IcacheWaitResponse);
+ _status = Running;
+ preExecute();
+ if (curStaticInst->isMemRef()) {
+ // load or store: just send to dcache
+ Fault fault = curStaticInst->initiateAcc(this, traceData);
+ assert(fault == NoFault);
+ assert(_status == DcacheWaitResponse);
+ // instruction will complete in dcache response callback
+ } else {
+ // non-memory instruction: execute completely now
+ Fault fault = curStaticInst->execute(this, traceData);
+ completeInst(fault);
+ }
+}
+
+
+bool
+TimingSimpleCPU::IcachePort::recvTiming(Packet *pkt)
+{
+ cpu->completeIfetch();
+ return true;
+}
+
+Packet *
+TimingSimpleCPU::IcachePort::recvRetry()
+{
+ // we shouldn't get a retry unless we have a packet that we're
+ // waiting to transmit
+ assert(cpu->ifetch_pkt != NULL);
+ assert(cpu->_status == IcacheRetry);
+ cpu->_status = IcacheWaitResponse;
+ Packet *tmp = cpu->ifetch_pkt;
+ cpu->ifetch_pkt = NULL;
+ return tmp;
+}
+
+void
+TimingSimpleCPU::completeDataAccess(Packet *pkt)
+{
+ // received a response from the dcache: complete the load or store
+ // instruction
+ assert(pkt->result == Success);
+ assert(_status == DcacheWaitResponse);
+ _status = Running;
+
+ Fault fault = curStaticInst->completeAcc(pkt, this, traceData);
+
+ completeInst(fault);
+}
+
+
+
+bool
+TimingSimpleCPU::DcachePort::recvTiming(Packet *pkt)
+{
+ cpu->completeDataAccess(pkt);
+ return true;
+}
+
+Packet *
+TimingSimpleCPU::DcachePort::recvRetry()
+{
+ // we shouldn't get a retry unless we have a packet that we're
+ // waiting to transmit
+ assert(cpu->dcache_pkt != NULL);
+ assert(cpu->_status == DcacheRetry);
+ cpu->_status = DcacheWaitResponse;
+ Packet *tmp = cpu->dcache_pkt;
+ cpu->dcache_pkt = NULL;
+ return tmp;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// TimingSimpleCPU Simulation Object
+//
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU)
+
+ Param<Counter> max_insts_any_thread;
+ Param<Counter> max_insts_all_threads;
+ Param<Counter> max_loads_any_thread;
+ Param<Counter> max_loads_all_threads;
+ SimObjectParam<MemObject *> mem;
+
+#if FULL_SYSTEM
+ SimObjectParam<AlphaITB *> itb;
+ SimObjectParam<AlphaDTB *> dtb;
+ SimObjectParam<System *> system;
+ Param<int> cpu_id;
+ Param<Tick> profile;
+#else
+ SimObjectParam<Process *> workload;
+#endif // FULL_SYSTEM
+
+ Param<int> clock;
+
+ Param<bool> defer_registration;
+ Param<int> width;
+ Param<bool> function_trace;
+ Param<Tick> function_trace_start;
+ Param<bool> simulate_stalls;
+
+END_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU)
+
+ INIT_PARAM(max_insts_any_thread,
+ "terminate when any thread reaches this inst count"),
+ INIT_PARAM(max_insts_all_threads,
+ "terminate when all threads have reached this inst count"),
+ INIT_PARAM(max_loads_any_thread,
+ "terminate when any thread reaches this load count"),
+ INIT_PARAM(max_loads_all_threads,
+ "terminate when all threads have reached this load count"),
+ INIT_PARAM(mem, "memory"),
+
+#if FULL_SYSTEM
+ INIT_PARAM(itb, "Instruction TLB"),
+ INIT_PARAM(dtb, "Data TLB"),
+ INIT_PARAM(system, "system object"),
+ INIT_PARAM(cpu_id, "processor ID"),
+ INIT_PARAM(profile, ""),
+#else
+ INIT_PARAM(workload, "processes to run"),
+#endif // FULL_SYSTEM
+
+ INIT_PARAM(clock, "clock speed"),
+ INIT_PARAM(defer_registration, "defer system registration (for sampling)"),
+ INIT_PARAM(width, "cpu width"),
+ INIT_PARAM(function_trace, "Enable function trace"),
+ INIT_PARAM(function_trace_start, "Cycle to start function trace"),
+ INIT_PARAM(simulate_stalls, "Simulate cache stall cycles")
+
+END_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU)
+
+
+CREATE_SIM_OBJECT(TimingSimpleCPU)
+{
+ TimingSimpleCPU::Params *params = new TimingSimpleCPU::Params();
+ params->name = getInstanceName();
+ params->numberOfThreads = 1;
+ params->max_insts_any_thread = max_insts_any_thread;
+ params->max_insts_all_threads = max_insts_all_threads;
+ params->max_loads_any_thread = max_loads_any_thread;
+ params->max_loads_all_threads = max_loads_all_threads;
+ params->deferRegistration = defer_registration;
+ params->clock = clock;
+ params->functionTrace = function_trace;
+ params->functionTraceStart = function_trace_start;
+ params->mem = mem;
+
+#if FULL_SYSTEM
+ params->itb = itb;
+ params->dtb = dtb;
+ params->system = system;
+ params->cpu_id = cpu_id;
+ params->profile = profile;
+#else
+ params->process = workload;
+#endif
+
+ TimingSimpleCPU *cpu = new TimingSimpleCPU(params);
+ return cpu;
+}
+
+REGISTER_SIM_OBJECT("TimingSimpleCPU", TimingSimpleCPU)
+
diff --git a/src/cpu/simple/timing.hh b/src/cpu/simple/timing.hh
new file mode 100644
index 000000000..83be025d9
--- /dev/null
+++ b/src/cpu/simple/timing.hh
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPU_SIMPLE_TIMING_HH__
+#define __CPU_SIMPLE_TIMING_HH__
+
+#include "cpu/simple/base.hh"
+
+class TimingSimpleCPU : public BaseSimpleCPU
+{
+ public:
+
+ struct Params : public BaseSimpleCPU::Params {
+ };
+
+ TimingSimpleCPU(Params *params);
+ virtual ~TimingSimpleCPU();
+
+ virtual void init();
+
+ public:
+ //
+ enum Status {
+ Idle,
+ Running,
+ IcacheRetry,
+ IcacheWaitResponse,
+ IcacheWaitSwitch,
+ DcacheRetry,
+ DcacheWaitResponse,
+ DcacheWaitSwitch,
+ SwitchedOut
+ };
+
+ protected:
+ Status _status;
+
+ Status status() const { return _status; }
+
+ private:
+
+ class CpuPort : public Port
+ {
+ protected:
+ TimingSimpleCPU *cpu;
+
+ public:
+
+ CpuPort(TimingSimpleCPU *_cpu)
+ : cpu(_cpu)
+ { }
+
+ protected:
+
+ virtual Tick recvAtomic(Packet *pkt);
+
+ virtual void recvFunctional(Packet *pkt);
+
+ virtual void recvStatusChange(Status status);
+
+ virtual void getDeviceAddressRanges(AddrRangeList &resp,
+ AddrRangeList &snoop)
+ { resp.clear(); snoop.clear(); }
+ };
+
+ class IcachePort : public CpuPort
+ {
+ public:
+
+ IcachePort(TimingSimpleCPU *_cpu)
+ : CpuPort(_cpu)
+ { }
+
+ protected:
+
+ virtual bool recvTiming(Packet *pkt);
+
+ virtual Packet *recvRetry();
+ };
+
+ class DcachePort : public CpuPort
+ {
+ public:
+
+ DcachePort(TimingSimpleCPU *_cpu)
+ : CpuPort(_cpu)
+ { }
+
+ protected:
+
+ virtual bool recvTiming(Packet *pkt);
+
+ virtual Packet *recvRetry();
+ };
+
+ IcachePort icachePort;
+ DcachePort dcachePort;
+
+ Packet *ifetch_pkt;
+ Packet *dcache_pkt;
+
+ public:
+
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+
+ void switchOut(Sampler *s);
+ void takeOverFrom(BaseCPU *oldCPU);
+
+ virtual void activateContext(int thread_num, int delay);
+ virtual void suspendContext(int thread_num);
+
+ template <class T>
+ Fault read(Addr addr, T &data, unsigned flags);
+
+ template <class T>
+ Fault write(T data, Addr addr, unsigned flags, uint64_t *res);
+
+ void fetch();
+ void completeInst(Fault fault);
+ void completeIfetch();
+ void completeDataAccess(Packet *);
+};
+
+#endif // __CPU_SIMPLE_TIMING_HH__
diff --git a/src/cpu/smt.hh b/src/cpu/smt.hh
new file mode 100644
index 000000000..9c52abf95
--- /dev/null
+++ b/src/cpu/smt.hh
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * Defines SMT_MAX_THREADS.
+ */
+
+#ifndef __SMT_HH__
+#define __SMT_HH__
+
+#ifndef SMT_MAX_THREADS
+/** The number of TPUs in any processor. */
+#define SMT_MAX_THREADS 4
+#endif
+
+/**
+ * The maximum number of active threads across all cpus. Used to
+ * initialize per-thread statistics in the cache.
+ *
+ * NB: Be careful to only use it once all the CPUs that you care about
+ * have been initialized
+ */
+extern int maxThreadsPerCPU;
+
+/**
+ * Changes the status and priority of the thread with the given number.
+ * @param thread_number The thread to change.
+ * @param activate The new active status.
+ * @param priority The new priority.
+ */
+void change_thread_state(int thread_number, int activate, int priority);
+
+#endif // __SMT_HH__
diff --git a/src/cpu/static_inst.cc b/src/cpu/static_inst.cc
new file mode 100644
index 000000000..c307dc6fc
--- /dev/null
+++ b/src/cpu/static_inst.cc
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <iostream>
+#include "cpu/static_inst.hh"
+#include "sim/root.hh"
+
+StaticInstPtr StaticInst::nullStaticInstPtr;
+
+// Define the decode cache hash map.
+StaticInst::DecodeCache StaticInst::decodeCache;
+
+void
+StaticInst::dumpDecodeCacheStats()
+{
+ using namespace std;
+
+ cerr << "Decode hash table stats @ " << curTick << ":" << endl;
+ cerr << "\tnum entries = " << decodeCache.size() << endl;
+ cerr << "\tnum buckets = " << decodeCache.bucket_count() << endl;
+ vector<int> hist(100, 0);
+ int max_hist = 0;
+ for (int i = 0; i < decodeCache.bucket_count(); ++i) {
+ int count = decodeCache.elems_in_bucket(i);
+ if (count > max_hist)
+ max_hist = count;
+ hist[count]++;
+ }
+ for (int i = 0; i <= max_hist; ++i) {
+ cerr << "\tbuckets of size " << i << " = " << hist[i] << endl;
+ }
+}
+
+bool
+StaticInst::hasBranchTarget(Addr pc, ExecContext *xc, Addr &tgt) const
+{
+ if (isDirectCtrl()) {
+ tgt = branchTarget(pc);
+ return true;
+ }
+
+ if (isIndirectCtrl()) {
+ tgt = branchTarget(xc);
+ return true;
+ }
+
+ return false;
+}
+
diff --git a/src/cpu/static_inst.hh b/src/cpu/static_inst.hh
new file mode 100644
index 000000000..33c9144fb
--- /dev/null
+++ b/src/cpu/static_inst.hh
@@ -0,0 +1,475 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CPU_STATIC_INST_HH__
+#define __CPU_STATIC_INST_HH__
+
+#include <bitset>
+#include <string>
+
+#include "base/hashmap.hh"
+#include "base/misc.hh"
+#include "base/refcnt.hh"
+#include "cpu/op_class.hh"
+#include "sim/host.hh"
+#include "arch/isa_traits.hh"
+
+// forward declarations
+struct AlphaSimpleImpl;
+class ExecContext;
+class DynInst;
+class Packet;
+
+template <class Impl>
+class AlphaDynInst;
+
+class FastCPU;
+class AtomicSimpleCPU;
+class TimingSimpleCPU;
+class InorderCPU;
+class SymbolTable;
+
+namespace Trace {
+ class InstRecord;
+}
+
+/**
+ * Base, ISA-independent static instruction class.
+ *
+ * The main component of this class is the vector of flags and the
+ * associated methods for reading them. Any object that can rely
+ * solely on these flags can process instructions without being
+ * recompiled for multiple ISAs.
+ */
+class StaticInstBase : public RefCounted
+{
+ protected:
+
+ /// Set of boolean static instruction properties.
+ ///
+ /// Notes:
+ /// - The IsInteger and IsFloating flags are based on the class of
+ /// registers accessed by the instruction. Although most
+ /// instructions will have exactly one of these two flags set, it
+ /// is possible for an instruction to have neither (e.g., direct
+ /// unconditional branches, memory barriers) or both (e.g., an
+ /// FP/int conversion).
+ /// - If IsMemRef is set, then exactly one of IsLoad or IsStore
+ /// will be set.
+ /// - If IsControl is set, then exactly one of IsDirectControl or
+ /// IsIndirect Control will be set, and exactly one of
+ /// IsCondControl or IsUncondControl will be set.
+ /// - IsSerializing, IsMemBarrier, and IsWriteBarrier are
+ /// implemented as flags since in the current model there's no
+ /// other way for instructions to inject behavior into the
+ /// pipeline outside of fetch. Once we go to an exec-in-exec CPU
+ /// model we should be able to get rid of these flags and
+ /// implement this behavior via the execute() methods.
+ ///
+ enum Flags {
+ IsNop, ///< Is a no-op (no effect at all).
+
+ IsInteger, ///< References integer regs.
+ IsFloating, ///< References FP regs.
+
+ IsMemRef, ///< References memory (load, store, or prefetch).
+ IsLoad, ///< Reads from memory (load or prefetch).
+ IsStore, ///< Writes to memory.
+ IsInstPrefetch, ///< Instruction-cache prefetch.
+ IsDataPrefetch, ///< Data-cache prefetch.
+ IsCopy, ///< Fast Cache block copy
+
+ IsControl, ///< Control transfer instruction.
+ IsDirectControl, ///< PC relative control transfer.
+ IsIndirectControl, ///< Register indirect control transfer.
+ IsCondControl, ///< Conditional control transfer.
+ IsUncondControl, ///< Unconditional control transfer.
+ IsCall, ///< Subroutine call.
+ IsReturn, ///< Subroutine return.
+
+ IsCondDelaySlot,///< Conditional Delay-Slot Instruction
+
+ IsThreadSync, ///< Thread synchronization operation.
+
+ IsSerializing, ///< Serializes pipeline: won't execute until all
+ /// older instructions have committed.
+ IsSerializeBefore,
+ IsSerializeAfter,
+ IsMemBarrier, ///< Is a memory barrier
+ IsWriteBarrier, ///< Is a write barrier
+
+ IsNonSpeculative, ///< Should not be executed speculatively
+
+ NumFlags
+ };
+
+ /// Flag values for this instruction.
+ std::bitset<NumFlags> flags;
+
+ /// See opClass().
+ OpClass _opClass;
+
+ /// See numSrcRegs().
+ int8_t _numSrcRegs;
+
+ /// See numDestRegs().
+ int8_t _numDestRegs;
+
+ /// The following are used to track physical register usage
+ /// for machines with separate int & FP reg files.
+ //@{
+ int8_t _numFPDestRegs;
+ int8_t _numIntDestRegs;
+ //@}
+
+ /// Constructor.
+ /// It's important to initialize everything here to a sane
+ /// default, since the decoder generally only overrides
+ /// the fields that are meaningful for the particular
+ /// instruction.
+ StaticInstBase(OpClass __opClass)
+ : _opClass(__opClass), _numSrcRegs(0), _numDestRegs(0),
+ _numFPDestRegs(0), _numIntDestRegs(0)
+ {
+ }
+
+ public:
+
+ /// @name Register information.
+ /// The sum of numFPDestRegs() and numIntDestRegs() equals
+ /// numDestRegs(). The former two functions are used to track
+ /// physical register usage for machines with separate int & FP
+ /// reg files.
+ //@{
+ /// Number of source registers.
+ int8_t numSrcRegs() const { return _numSrcRegs; }
+ /// Number of destination registers.
+ int8_t numDestRegs() const { return _numDestRegs; }
+ /// Number of floating-point destination regs.
+ int8_t numFPDestRegs() const { return _numFPDestRegs; }
+ /// Number of integer destination regs.
+ int8_t numIntDestRegs() const { return _numIntDestRegs; }
+ //@}
+
+ /// @name Flag accessors.
+ /// These functions are used to access the values of the various
+ /// instruction property flags. See StaticInstBase::Flags for descriptions
+ /// of the individual flags.
+ //@{
+
+ bool isNop() const { return flags[IsNop]; }
+
+ bool isMemRef() const { return flags[IsMemRef]; }
+ bool isLoad() const { return flags[IsLoad]; }
+ bool isStore() const { return flags[IsStore]; }
+ bool isInstPrefetch() const { return flags[IsInstPrefetch]; }
+ bool isDataPrefetch() const { return flags[IsDataPrefetch]; }
+ bool isCopy() const { return flags[IsCopy];}
+
+ bool isInteger() const { return flags[IsInteger]; }
+ bool isFloating() const { return flags[IsFloating]; }
+
+ bool isControl() const { return flags[IsControl]; }
+ bool isCall() const { return flags[IsCall]; }
+ bool isReturn() const { return flags[IsReturn]; }
+ bool isDirectCtrl() const { return flags[IsDirectControl]; }
+ bool isIndirectCtrl() const { return flags[IsIndirectControl]; }
+ bool isCondCtrl() const { return flags[IsCondControl]; }
+ bool isUncondCtrl() const { return flags[IsUncondControl]; }
+
+ bool isThreadSync() const { return flags[IsThreadSync]; }
+ bool isSerializing() const { return flags[IsSerializing] ||
+ flags[IsSerializeBefore] ||
+ flags[IsSerializeAfter]; }
+ bool isSerializeBefore() const { return flags[IsSerializeBefore]; }
+ bool isSerializeAfter() const { return flags[IsSerializeAfter]; }
+ bool isMemBarrier() const { return flags[IsMemBarrier]; }
+ bool isWriteBarrier() const { return flags[IsWriteBarrier]; }
+ bool isNonSpeculative() const { return flags[IsNonSpeculative]; }
+ //@}
+
+ /// Operation class. Used to select appropriate function unit in issue.
+ OpClass opClass() const { return _opClass; }
+};
+
+
+// forward declaration
+class StaticInstPtr;
+
+/**
+ * Generic yet ISA-dependent static instruction class.
+ *
+ * This class builds on StaticInstBase, defining fields and interfaces
+ * that are generic across all ISAs but that differ in details
+ * according to the specific ISA being used.
+ */
+class StaticInst : public StaticInstBase
+{
+ public:
+
+ /// Binary machine instruction type.
+ typedef TheISA::MachInst MachInst;
+ /// Binary extended machine instruction type.
+ typedef TheISA::ExtMachInst ExtMachInst;
+ /// Logical register index type.
+ typedef TheISA::RegIndex RegIndex;
+
+ enum {
+ MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs
+ MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs
+ };
+
+
+ /// Return logical index (architectural reg num) of i'th destination reg.
+ /// Only the entries from 0 through numDestRegs()-1 are valid.
+ RegIndex destRegIdx(int i) const { return _destRegIdx[i]; }
+
+ /// Return logical index (architectural reg num) of i'th source reg.
+ /// Only the entries from 0 through numSrcRegs()-1 are valid.
+ RegIndex srcRegIdx(int i) const { return _srcRegIdx[i]; }
+
+ /// Pointer to a statically allocated "null" instruction object.
+ /// Used to give eaCompInst() and memAccInst() something to return
+ /// when called on non-memory instructions.
+ static StaticInstPtr nullStaticInstPtr;
+
+ /**
+ * Memory references only: returns "fake" instruction representing
+ * the effective address part of the memory operation. Used to
+ * obtain the dependence info (numSrcRegs and srcRegIdx[]) for
+ * just the EA computation.
+ */
+ virtual const
+ StaticInstPtr &eaCompInst() const { return nullStaticInstPtr; }
+
+ /**
+ * Memory references only: returns "fake" instruction representing
+ * the memory access part of the memory operation. Used to
+ * obtain the dependence info (numSrcRegs and srcRegIdx[]) for
+ * just the memory access (not the EA computation).
+ */
+ virtual const
+ StaticInstPtr &memAccInst() const { return nullStaticInstPtr; }
+
+ /// The binary machine instruction.
+ const ExtMachInst machInst;
+
+ protected:
+
+ /// See destRegIdx().
+ RegIndex _destRegIdx[MaxInstDestRegs];
+ /// See srcRegIdx().
+ RegIndex _srcRegIdx[MaxInstSrcRegs];
+
+ /**
+ * Base mnemonic (e.g., "add"). Used by generateDisassembly()
+ * methods. Also useful to readily identify instructions from
+ * within the debugger when #cachedDisassembly has not been
+ * initialized.
+ */
+ const char *mnemonic;
+
+ /**
+ * String representation of disassembly (lazily evaluated via
+ * disassemble()).
+ */
+ mutable std::string *cachedDisassembly;
+
+ /**
+ * Internal function to generate disassembly string.
+ */
+ virtual std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const = 0;
+
+ /// Constructor.
+ StaticInst(const char *_mnemonic, ExtMachInst _machInst, OpClass __opClass)
+ : StaticInstBase(__opClass),
+ machInst(_machInst), mnemonic(_mnemonic), cachedDisassembly(0)
+ {
+ }
+
+ public:
+
+ virtual ~StaticInst()
+ {
+ if (cachedDisassembly)
+ delete cachedDisassembly;
+ }
+
+/**
+ * The execute() signatures are auto-generated by scons based on the
+ * set of CPU models we are compiling in today.
+ */
+#include "cpu/static_inst_exec_sigs.hh"
+
+ /**
+ * Return the target address for a PC-relative branch.
+ * Invalid if not a PC-relative branch (i.e. isDirectCtrl()
+ * should be true).
+ */
+ virtual Addr branchTarget(Addr branchPC) const
+ {
+ panic("StaticInst::branchTarget() called on instruction "
+ "that is not a PC-relative branch.");
+ }
+
+ /**
+ * Return the target address for an indirect branch (jump). The
+ * register value is read from the supplied execution context, so
+ * the result is valid only if the execution context is about to
+ * execute the branch in question. Invalid if not an indirect
+ * branch (i.e. isIndirectCtrl() should be true).
+ */
+ virtual Addr branchTarget(ExecContext *xc) const
+ {
+ panic("StaticInst::branchTarget() called on instruction "
+ "that is not an indirect branch.");
+ }
+
+ /**
+ * Return true if the instruction is a control transfer, and if so,
+ * return the target address as well.
+ */
+ bool hasBranchTarget(Addr pc, ExecContext *xc, Addr &tgt) const;
+
+ /**
+ * Return string representation of disassembled instruction.
+ * The default version of this function will call the internal
+ * virtual generateDisassembly() function to get the string,
+ * then cache it in #cachedDisassembly. If the disassembly
+ * should not be cached, this function should be overridden directly.
+ */
+ virtual const std::string &disassemble(Addr pc,
+ const SymbolTable *symtab = 0) const
+ {
+ if (!cachedDisassembly)
+ cachedDisassembly =
+ new std::string(generateDisassembly(pc, symtab));
+
+ return *cachedDisassembly;
+ }
+
+ /// Decoded instruction cache type.
+ /// For now we're using a generic hash_map; this seems to work
+ /// pretty well.
+ typedef m5::hash_map<ExtMachInst, StaticInstPtr> DecodeCache;
+
+ /// A cache of decoded instruction objects.
+ static DecodeCache decodeCache;
+
+ /**
+ * Dump some basic stats on the decode cache hash map.
+ * Only gets called if DECODE_CACHE_HASH_STATS is defined.
+ */
+ static void dumpDecodeCacheStats();
+
+ /// Decode a machine instruction.
+ /// @param mach_inst The binary instruction to decode.
+ /// @retval A pointer to the corresponding StaticInst object.
+ //This is defined as inline below.
+ static StaticInstPtr decode(ExtMachInst mach_inst);
+
+ //MIPS Decoder Debug Functions
+ int getOpcode() { return (machInst & 0xFC000000) >> 26 ; }//31..26
+ int getRs() { return (machInst & 0x03E00000) >> 21; } //25...21
+ int getRt() { return (machInst & 0x001F0000) >> 16; } //20...16
+ int getRd() { return (machInst & 0x0000F800) >> 11; } //15...11
+ int getImm() { return (machInst & 0x0000FFFF); } //15...0
+ int getFunction(){ return (machInst & 0x0000003F); }//5...0
+ int getBranch(){ return (machInst & 0x0000FFFF); }//15...0
+ int getJump(){ return (machInst & 0x03FFFFFF); }//5...0
+ int getHint(){ return (machInst & 0x000007C0) >> 6; } //10...6
+ std::string getName() { return mnemonic; }
+};
+
+typedef RefCountingPtr<StaticInstBase> StaticInstBasePtr;
+
+/// Reference-counted pointer to a StaticInst object.
+/// This type should be used instead of "StaticInst *" so that
+/// StaticInst objects can be properly reference-counted.
+class StaticInstPtr : public RefCountingPtr<StaticInst>
+{
+ public:
+ /// Constructor.
+ StaticInstPtr()
+ : RefCountingPtr<StaticInst>()
+ {
+ }
+
+ /// Conversion from "StaticInst *".
+ StaticInstPtr(StaticInst *p)
+ : RefCountingPtr<StaticInst>(p)
+ {
+ }
+
+ /// Copy constructor.
+ StaticInstPtr(const StaticInstPtr &r)
+ : RefCountingPtr<StaticInst>(r)
+ {
+ }
+
+ /// Construct directly from machine instruction.
+ /// Calls StaticInst::decode().
+ StaticInstPtr(TheISA::ExtMachInst mach_inst)
+ : RefCountingPtr<StaticInst>(StaticInst::decode(mach_inst))
+ {
+ }
+
+ /// Convert to pointer to StaticInstBase class.
+ operator const StaticInstBasePtr()
+ {
+ return this->get();
+ }
+};
+
+inline StaticInstPtr
+StaticInst::decode(StaticInst::ExtMachInst mach_inst)
+{
+#ifdef DECODE_CACHE_HASH_STATS
+ // Simple stats on decode hash_map. Turns out the default
+ // hash function is as good as anything I could come up with.
+ const int dump_every_n = 10000000;
+ static int decodes_til_dump = dump_every_n;
+
+ if (--decodes_til_dump == 0) {
+ dumpDecodeCacheStats();
+ decodes_til_dump = dump_every_n;
+ }
+#endif
+
+ DecodeCache::iterator iter = decodeCache.find(mach_inst);
+ if (iter != decodeCache.end()) {
+ return iter->second;
+ }
+
+ StaticInstPtr si = TheISA::decodeInst(mach_inst);
+ decodeCache[mach_inst] = si;
+ return si;
+}
+
+#endif // __CPU_STATIC_INST_HH__
diff --git a/src/cpu/trace/opt_cpu.cc b/src/cpu/trace/opt_cpu.cc
new file mode 100644
index 000000000..6cd23b0dd
--- /dev/null
+++ b/src/cpu/trace/opt_cpu.cc
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * Definition of a memory trace CPU object for optimal caches. Uses a memory
+ * trace to access a fully associative cache with optimal replacement.
+ */
+
+#include <algorithm> // For heap functions.
+
+#include "cpu/trace/opt_cpu.hh"
+#include "cpu/trace/reader/mem_trace_reader.hh"
+
+#include "sim/builder.hh"
+#include "sim/sim_events.hh"
+
+using namespace std;
+
+OptCPU::OptCPU(const string &name,
+ MemTraceReader *_trace,
+ int block_size,
+ int cache_size,
+ int _assoc)
+ : SimObject(name), tickEvent(this), trace(_trace),
+ numBlks(cache_size/block_size), assoc(_assoc), numSets(numBlks/assoc),
+ setMask(numSets - 1)
+{
+ int log_block_size = 0;
+ int tmp_block_size = block_size;
+ while (tmp_block_size > 1) {
+ ++log_block_size;
+ tmp_block_size = tmp_block_size >> 1;
+ }
+ assert(1<<log_block_size == block_size);
+ MemReqPtr req;
+ trace->getNextReq(req);
+ refInfo.resize(numSets);
+ while (req) {
+ RefInfo temp;
+ temp.addr = req->paddr >> log_block_size;
+ int set = temp.addr & setMask;
+ refInfo[set].push_back(temp);
+ trace->getNextReq(req);
+ }
+
+ // Initialize top level of lookup table.
+ lookupTable.resize(16);
+
+ // Annotate references with next ref time.
+ for (int k = 0; k < numSets; ++k) {
+ for (RefIndex i = refInfo[k].size() - 1; i >= 0; --i) {
+ Addr addr = refInfo[k][i].addr;
+ initTable(addr, InfiniteRef);
+ refInfo[k][i].nextRefTime = lookupValue(addr);
+ setValue(addr, i);
+ }
+ }
+
+ // Reset the lookup table
+ for (int j = 0; j < 16; ++j) {
+ if (lookupTable[j].size() == (1<<16)) {
+ for (int k = 0; k < (1<<16); ++k) {
+ if (lookupTable[j][k].size() == (1<<16)) {
+ for (int l = 0; l < (1<<16); ++l) {
+ lookupTable[j][k][l] = -1;
+ }
+ }
+ }
+ }
+ }
+
+ tickEvent.schedule(0);
+
+ hits = 0;
+ misses = 0;
+}
+
+void
+OptCPU::processSet(int set)
+{
+ // Initialize cache
+ int blks_in_cache = 0;
+ RefIndex i = 0;
+ cacheHeap.clear();
+ cacheHeap.resize(assoc);
+
+ while (blks_in_cache < assoc) {
+ RefIndex cache_index = lookupValue(refInfo[set][i].addr);
+ if (cache_index == -1) {
+ // First reference to this block
+ misses++;
+ cache_index = blks_in_cache++;
+ setValue(refInfo[set][i].addr, cache_index);
+ } else {
+ hits++;
+ }
+ // update cache heap to most recent reference
+ cacheHeap[cache_index] = i;
+ if (++i >= refInfo[set].size()) {
+ return;
+ }
+ }
+ for (int start = assoc/2; start >= 0; --start) {
+ heapify(set,start);
+ }
+ //verifyHeap(set,0);
+
+ for (; i < refInfo[set].size(); ++i) {
+ RefIndex cache_index = lookupValue(refInfo[set][i].addr);
+ if (cache_index == -1) {
+ // miss
+ misses++;
+ // replace from cacheHeap[0]
+ // mark replaced block as absent
+ setValue(refInfo[set][cacheHeap[0]].addr, -1);
+ setValue(refInfo[set][i].addr, 0);
+ cacheHeap[0] = i;
+ heapify(set, 0);
+ // Make sure its in the cache
+ assert(lookupValue(refInfo[set][i].addr) != -1);
+ } else {
+ // hit
+ hits++;
+ assert(refInfo[set][cacheHeap[cache_index]].addr ==
+ refInfo[set][i].addr);
+ assert(refInfo[set][cacheHeap[cache_index]].nextRefTime == i);
+ assert(heapLeft(cache_index) >= assoc);
+
+ cacheHeap[cache_index] = i;
+ processRankIncrease(set, cache_index);
+ assert(lookupValue(refInfo[set][i].addr) != -1);
+ }
+ }
+}
+void
+OptCPU::tick()
+{
+ // Do opt simulation
+
+ int references = 0;
+ for (int set = 0; set < numSets; ++set) {
+ if (!refInfo[set].empty()) {
+ processSet(set);
+ }
+ references += refInfo[set].size();
+ }
+ // exit;
+ fprintf(stderr,"sys.cpu.misses %d #opt cache misses\n",misses);
+ fprintf(stderr,"sys.cpu.hits %d #opt cache hits\n", hits);
+ fprintf(stderr,"sys.cpu.accesses %d #opt cache acceses\n", references);
+ new SimExitEvent("Finshed Memory Trace");
+}
+
+void
+OptCPU::initTable(Addr addr, RefIndex index)
+{
+ int l1_index = (addr >> 32) & 0x0f;
+ int l2_index = (addr >> 16) & 0xffff;
+ assert(l1_index == addr >> 32);
+ if (lookupTable[l1_index].size() != (1<<16)) {
+ lookupTable[l1_index].resize(1<<16);
+ }
+ if (lookupTable[l1_index][l2_index].size() != (1<<16)) {
+ lookupTable[l1_index][l2_index].resize(1<<16, index);
+ }
+}
+
+OptCPU::TickEvent::TickEvent(OptCPU *c)
+ : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c)
+{
+}
+
+void
+OptCPU::TickEvent::process()
+{
+ cpu->tick();
+}
+
+const char *
+OptCPU::TickEvent::description()
+{
+ return "OptCPU tick event";
+}
+
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(OptCPU)
+
+ SimObjectParam<MemTraceReader *> data_trace;
+ Param<int> size;
+ Param<int> block_size;
+Param<int> assoc;
+
+END_DECLARE_SIM_OBJECT_PARAMS(OptCPU)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(OptCPU)
+
+ INIT_PARAM_DFLT(data_trace, "memory trace", NULL),
+ INIT_PARAM(size, "cache size"),
+ INIT_PARAM(block_size, "block size"),
+ INIT_PARAM(assoc,"associativity")
+
+END_INIT_SIM_OBJECT_PARAMS(OptCPU)
+
+CREATE_SIM_OBJECT(OptCPU)
+{
+ return new OptCPU(getInstanceName(),
+ data_trace,
+ block_size,
+ size,
+ assoc);
+}
+
+REGISTER_SIM_OBJECT("OptCPU", OptCPU)
diff --git a/src/cpu/trace/opt_cpu.hh b/src/cpu/trace/opt_cpu.hh
new file mode 100644
index 000000000..f81691733
--- /dev/null
+++ b/src/cpu/trace/opt_cpu.hh
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * Declaration of a memory trace CPU object for optimal caches. Uses a memory
+ * trace to access a fully associative cache with optimal replacement.
+ */
+
+#ifndef __CPU_TRACE_OPT_CPU_HH__
+#define __CPU_TRACE_OPT_CPU_HH__
+
+#include <vector>
+
+#include "mem/mem_req.hh" // for MemReqPtr
+#include "sim/eventq.hh" // for Event
+#include "sim/sim_object.hh"
+
+// Forward Declaration
+class MemTraceReader;
+
+/**
+ * A CPU object to simulate a fully-associative cache with optimal replacement.
+ */
+class OptCPU : public SimObject
+{
+ private:
+ typedef int RefIndex;
+
+ typedef std::vector<RefIndex> L3Table;
+ typedef std::vector<L3Table> L2Table;
+ typedef std::vector<L2Table> L1Table;
+
+ /**
+ * Event to call OptCPU::tick
+ */
+ class TickEvent : public Event
+ {
+ private:
+ /** The associated CPU */
+ OptCPU *cpu;
+
+ public:
+ /**
+ * Construct this event;
+ */
+ TickEvent(OptCPU *c);
+
+ /**
+ * Call the tick function.
+ */
+ void process();
+
+ /**
+ * Return a string description of this event.
+ */
+ const char *description();
+ };
+
+ TickEvent tickEvent;
+
+ class RefInfo
+ {
+ public:
+ RefIndex nextRefTime;
+ Addr addr;
+ };
+
+ /** Reference Information, per set. */
+ std::vector<std::vector<RefInfo> > refInfo;
+
+ /** Lookup table to track blocks in the cache heap */
+ L1Table lookupTable;
+
+ /**
+ * Return the correct value in the lookup table.
+ */
+ RefIndex lookupValue(Addr addr)
+ {
+ int l1_index = (addr >> 32) & 0x0f;
+ int l2_index = (addr >> 16) & 0xffff;
+ int l3_index = addr & 0xffff;
+ assert(l1_index == addr >> 32);
+ return lookupTable[l1_index][l2_index][l3_index];
+ }
+
+ /**
+ * Set the value in the lookup table.
+ */
+ void setValue(Addr addr, RefIndex index)
+ {
+ int l1_index = (addr >> 32) & 0x0f;
+ int l2_index = (addr >> 16) & 0xffff;
+ int l3_index = addr & 0xffff;
+ assert(l1_index == addr >> 32);
+ lookupTable[l1_index][l2_index][l3_index]=index;
+ }
+
+ /**
+ * Initialize the lookup table to the given value.
+ */
+ void initTable(Addr addr, RefIndex index);
+
+ void heapSwap(int set, int a, int b) {
+ RefIndex tmp = cacheHeap[a];
+ cacheHeap[a] = cacheHeap[b];
+ cacheHeap[b] = tmp;
+
+ setValue(refInfo[set][cacheHeap[a]].addr, a);
+ setValue(refInfo[set][cacheHeap[b]].addr, b);
+ }
+
+ int heapLeft(int index) { return index + index + 1; }
+ int heapRight(int index) { return index + index + 2; }
+ int heapParent(int index) { return (index - 1) >> 1; }
+
+ RefIndex heapRank(int set, int index) {
+ return refInfo[set][cacheHeap[index]].nextRefTime;
+ }
+
+ void heapify(int set, int start){
+ int left = heapLeft(start);
+ int right = heapRight(start);
+ int max = start;
+ if (left < assoc && heapRank(set, left) > heapRank(set, start)) {
+ max = left;
+ }
+ if (right < assoc && heapRank(set, right) > heapRank(set, max)) {
+ max = right;
+ }
+
+ if (max != start) {
+ heapSwap(set, start, max);
+ heapify(set, max);
+ }
+ }
+
+ void verifyHeap(int set, int start) {
+ int left = heapLeft(start);
+ int right = heapRight(start);
+
+ if (left < assoc) {
+ assert(heapRank(set, start) >= heapRank(set, left));
+ verifyHeap(set, left);
+ }
+ if (right < assoc) {
+ assert(heapRank(set, start) >= heapRank(set, right));
+ verifyHeap(set, right);
+ }
+ }
+
+ void processRankIncrease(int set, int start) {
+ int parent = heapParent(start);
+ while (start > 0 && heapRank(set,parent) < heapRank(set,start)) {
+ heapSwap(set, parent, start);
+ start = parent;
+ parent = heapParent(start);
+ }
+ }
+
+ void processSet(int set);
+
+ static const RefIndex InfiniteRef = 0x7fffffff;
+
+ /** Memory reference trace. */
+ MemTraceReader *trace;
+
+ /** Cache heap for replacement. */
+ std::vector<RefIndex> cacheHeap;
+
+ /** The number of blocks in the cache. */
+ const int numBlks;
+
+ const int assoc;
+ const int numSets;
+ const int setMask;
+
+
+ int misses;
+ int hits;
+
+ public:
+ /**
+ * Construct a OptCPU object.
+ */
+ OptCPU(const std::string &name,
+ MemTraceReader *_trace,
+ int block_size,
+ int cache_size,
+ int assoc);
+
+ /**
+ * Perform the optimal replacement simulation.
+ */
+ void tick();
+};
+
+#endif // __CPU_TRACE_OPT_CPU_HH__
diff --git a/src/cpu/trace/reader/ibm_reader.cc b/src/cpu/trace/reader/ibm_reader.cc
new file mode 100644
index 000000000..420101b63
--- /dev/null
+++ b/src/cpu/trace/reader/ibm_reader.cc
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * Declaration of a IBM memory trace format reader.
+ */
+#include <sstream>
+
+#include "cpu/trace/reader/ibm_reader.hh"
+#include "sim/builder.hh"
+#include "base/misc.hh" // for fatal
+
+using namespace std;
+
+IBMReader::IBMReader(const string &name, const string &filename)
+ : MemTraceReader(name)
+{
+ if (strcmp((filename.c_str() + filename.length() -3), ".gz") == 0) {
+ // Compressed file, need to use a pipe to gzip.
+ stringstream buf;
+ buf << "gzip -d -c " << filename << endl;
+ trace = popen(buf.str().c_str(), "r");
+ } else {
+ trace = fopen(filename.c_str(), "rb");
+ }
+ if (!trace) {
+ fatal("Can't open file %s", filename);
+ }
+}
+
+Tick
+IBMReader::getNextReq(MemReqPtr &req)
+{
+ MemReqPtr tmp_req;
+
+ int c = getc(trace);
+ if (c != EOF) {
+ tmp_req = new MemReq();
+ //int cpu_id = (c & 0xf0) >> 4;
+ int type = c & 0x0f;
+ // We have L1 miss traces, so all accesses are 128 bytes
+ tmp_req->size = 128;
+
+ tmp_req->paddr = 0;
+ for (int i = 2; i >= 0; --i) {
+ c = getc(trace);
+ if (c == EOF) {
+ fatal("Unexpected end of file");
+ }
+ tmp_req->paddr |= ((c & 0xff) << (8 * i));
+ }
+ tmp_req->paddr = tmp_req->paddr << 7;
+
+ switch(type) {
+ case IBM_COND_EXCLUSIVE_FETCH:
+ case IBM_READ_ONLY_FETCH:
+ tmp_req->cmd = Read;
+ break;
+ case IBM_EXCLUSIVE_FETCH:
+ case IBM_FETCH_NO_DATA:
+ tmp_req->cmd = Write;
+ break;
+ case IBM_INST_FETCH:
+ tmp_req->cmd = Read;
+ break;
+ default:
+ fatal("Unknown trace entry type.");
+ }
+
+ }
+ req = tmp_req;
+ return 0;
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(IBMReader)
+
+ Param<string> filename;
+
+END_DECLARE_SIM_OBJECT_PARAMS(IBMReader)
+
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(IBMReader)
+
+ INIT_PARAM(filename, "trace file")
+
+END_INIT_SIM_OBJECT_PARAMS(IBMReader)
+
+
+CREATE_SIM_OBJECT(IBMReader)
+{
+ return new IBMReader(getInstanceName(), filename);
+}
+
+REGISTER_SIM_OBJECT("IBMReader", IBMReader)
diff --git a/src/cpu/trace/reader/ibm_reader.hh b/src/cpu/trace/reader/ibm_reader.hh
new file mode 100644
index 000000000..ce29206a2
--- /dev/null
+++ b/src/cpu/trace/reader/ibm_reader.hh
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * Definition of a IBM memory trace format reader.
+ */
+
+#ifndef __IBM_READER_HH__
+#define __IBM_READER_HH__
+
+#include <stdio.h>
+#include "cpu/trace/reader/mem_trace_reader.hh"
+#include "mem/mem_req.hh"
+
+/**
+ * A memory trace reader for the IBM memory trace format.
+ */
+class IBMReader : public MemTraceReader
+{
+ /** IBM trace file. */
+ FILE* trace;
+
+ enum IBMType {
+ IBM_INST_FETCH,
+ IBM_READ_ONLY_FETCH,
+ IBM_COND_EXCLUSIVE_FETCH,
+ IBM_EXCLUSIVE_FETCH,
+ IBM_FETCH_NO_DATA
+ };
+
+ public:
+ /**
+ * Construct an IBMReader.
+ */
+ IBMReader(const std::string &name, const std::string &filename);
+
+ /**
+ * Read the next request from the trace. Returns the request in the
+ * provided MemReqPtr and the cycle of the request in the return value.
+ * @param req Return the next request from the trace.
+ * @return IBM traces don't store timing information, return 0
+ */
+ virtual Tick getNextReq(MemReqPtr &req);
+};
+
+#endif //__IBM_READER_HH__
+
diff --git a/src/cpu/trace/reader/itx_reader.cc b/src/cpu/trace/reader/itx_reader.cc
new file mode 100644
index 000000000..39ba27393
--- /dev/null
+++ b/src/cpu/trace/reader/itx_reader.cc
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * Declaration of a Intel ITX memory trace format reader.
+ */
+#include <sstream>
+
+#include "cpu/trace/reader/itx_reader.hh"
+#include "sim/builder.hh"
+#include "base/misc.hh" // for fatal
+
+using namespace std;
+
+ITXReader::ITXReader(const string &name, const string &filename)
+ : MemTraceReader(name)
+{
+ if (strcmp((filename.c_str() + filename.length() -3), ".gz") == 0) {
+ // Compressed file, need to use a pipe to gzip.
+ stringstream buf;
+ buf << "gzip -d -c " << filename << endl;
+ trace = popen(buf.str().c_str(), "r");
+ } else {
+ trace = fopen(filename.c_str(), "rb");
+ }
+ if (!trace) {
+ fatal("Can't open file %s", filename);
+ }
+ traceFormat = 0;
+ int c;
+ for (int i = 0; i < 4; ++i) {
+ c = getc(trace);
+ if (c == EOF) {
+ fatal("Unexpected end of trace file.");
+ }
+ traceFormat |= (c & 0xff) << (8 * i);
+ }
+ if (traceFormat > 2)
+ fatal("Invalid trace format.");
+}
+
+Tick
+ITXReader::getNextReq(MemReqPtr &req)
+{
+ MemReqPtr tmp_req = new MemReq();
+ bool phys_val;
+ do {
+ int c = getc(trace);
+ if (c != EOF) {
+ // Decode first byte
+ // phys_val<1> | type <2:0> | size <3:0>
+ phys_val = c & 0x80;
+ tmp_req->size = (c & 0x0f) + 1;
+ int type = (c & 0x70) >> 4;
+
+ // Could be a compressed instruction entry, expand if necessary
+ if (type == ITXCodeComp) {
+ if (traceFormat != 2) {
+ fatal("Compressed code entry in non CompCode trace.");
+ }
+ if (!codeVirtValid) {
+ fatal("Corrupt CodeComp entry.");
+ }
+
+ tmp_req->vaddr = codeVirtAddr;
+ codeVirtAddr += tmp_req->size;
+ if (phys_val) {
+ if (!codePhysValid) {
+ fatal("Corrupt CodeComp entry.");
+ }
+ tmp_req->paddr = codePhysAddr;
+ if (((tmp_req->paddr & 0xfff) + tmp_req->size) & ~0xfff) {
+ // Crossed page boundary, next physical address is
+ // invalid
+ codePhysValid = false;
+ } else {
+ codePhysAddr += tmp_req->size;
+ }
+ assert(tmp_req->paddr >> 36 == 0);
+ } else {
+ codePhysValid = false;
+ }
+ type = ITXCode;
+ tmp_req->cmd = Read;
+ } else {
+ // Normal entry
+ tmp_req->vaddr = 0;
+ for (int i = 0; i < 4; ++i) {
+ c = getc(trace);
+ if (c == EOF) {
+ fatal("Unexpected end of trace file.");
+ }
+ tmp_req->vaddr |= (c & 0xff) << (8 * i);
+ }
+ if (type == ITXCode) {
+ codeVirtAddr = tmp_req->vaddr + tmp_req->size;
+ codeVirtValid = true;
+ }
+ tmp_req->paddr = 0;
+ if (phys_val) {
+ c = getc(trace);
+ if (c == EOF) {
+ fatal("Unexpected end of trace file.");
+ }
+ // Get the page offset from the virtual address.
+ tmp_req->paddr = tmp_req->vaddr & 0xfff;
+ tmp_req->paddr |= (c & 0xf0) << 8;
+ tmp_req->paddr |= (Addr)(c & 0x0f) << 32;
+ for (int i = 2; i < 4; ++i) {
+ c = getc(trace);
+ if (c == EOF) {
+ fatal("Unexpected end of trace file.");
+ }
+ tmp_req->paddr |= (Addr)(c & 0xff) << (8 * i);
+ }
+ if (type == ITXCode) {
+ if (((tmp_req->paddr & 0xfff) + tmp_req->size)
+ & ~0xfff) {
+ // Crossing the page boundary, next physical
+ // address isn't valid
+ codePhysValid = false;
+ } else {
+ codePhysAddr = tmp_req->paddr + tmp_req->size;
+ codePhysValid = true;
+ }
+ }
+ assert(tmp_req->paddr >> 36 == 0);
+ } else if (type == ITXCode) {
+ codePhysValid = false;
+ }
+ switch(type) {
+ case ITXRead:
+ tmp_req->cmd = Read;
+ break;
+ case ITXWrite:
+ tmp_req->cmd = Write;
+ break;
+ case ITXWriteback:
+ tmp_req->cmd = Writeback;
+ break;
+ case ITXCode:
+ tmp_req->cmd = Read;
+ tmp_req->flags |= INST_READ;
+ break;
+ default:
+ fatal("Unknown ITX type");
+ }
+ }
+ } else {
+ // EOF need to return a null request
+ MemReqPtr null_req;
+ req = null_req;
+ return 0;
+ }
+ } while (!phys_val);
+ req = tmp_req;
+ assert(!req || (req->paddr >> 36) == 0);
+ return 0;
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(ITXReader)
+
+ Param<string> filename;
+
+END_DECLARE_SIM_OBJECT_PARAMS(ITXReader)
+
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(ITXReader)
+
+ INIT_PARAM(filename, "trace file")
+
+END_INIT_SIM_OBJECT_PARAMS(ITXReader)
+
+
+CREATE_SIM_OBJECT(ITXReader)
+{
+ return new ITXReader(getInstanceName(), filename);
+}
+
+REGISTER_SIM_OBJECT("ITXReader", ITXReader)
diff --git a/src/cpu/trace/reader/itx_reader.hh b/src/cpu/trace/reader/itx_reader.hh
new file mode 100644
index 000000000..a16a08085
--- /dev/null
+++ b/src/cpu/trace/reader/itx_reader.hh
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * Definition of a Intel ITX memory trace format reader.
+ */
+
+#ifndef __ITX_READER_HH__
+#define __ITX_READER_HH__
+
+#include <stdio.h>
+#include <string>
+
+#include "cpu/trace/reader/mem_trace_reader.hh"
+#include "mem/mem_req.hh"
+
+
+/**
+ * A memory trace reader for the Intel ITX memory trace format.
+ */
+class ITXReader : public MemTraceReader
+{
+ private:
+ /** Trace file. */
+ FILE *trace;
+
+ bool codeVirtValid;
+ Addr codeVirtAddr;
+ bool codePhysValid;
+ Addr codePhysAddr;
+
+ int traceFormat;
+
+ enum ITXType {
+ ITXRead,
+ ITXWrite,
+ ITXWriteback,
+ ITXCode,
+ ITXCodeComp
+ };
+
+ public:
+ /**
+ * Construct an ITXReader.
+ */
+ ITXReader(const std::string &name, const std::string &filename);
+
+ /**
+ * Read the next request from the trace. Returns the request in the
+ * provided MemReqPtr and the cycle of the request in the return value.
+ * @param req Return the next request from the trace.
+ * @return ITX traces don't store timing information, return 0
+ */
+ virtual Tick getNextReq(MemReqPtr &req);
+};
+
+#endif //__ITX_READER_HH__
+
diff --git a/src/cpu/trace/reader/m5_reader.cc b/src/cpu/trace/reader/m5_reader.cc
new file mode 100644
index 000000000..ce44672f2
--- /dev/null
+++ b/src/cpu/trace/reader/m5_reader.cc
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * Declaration of a memory trace reader for a M5 memory trace.
+ */
+
+#include "cpu/trace/reader/m5_reader.hh"
+#include "mem/trace/m5_format.hh"
+#include "mem/mem_cmd.hh"
+#include "sim/builder.hh"
+
+using namespace std;
+
+M5Reader::M5Reader(const string &name, const string &filename)
+ : MemTraceReader(name)
+{
+ traceFile.open(filename.c_str(), ios::binary);
+}
+
+Tick
+M5Reader::getNextReq(MemReqPtr &req)
+{
+ M5Format ref;
+
+ MemReqPtr tmp_req;
+ // Need to read EOF char before eof() will return true.
+ traceFile.read((char*) &ref, sizeof(ref));
+ if (!traceFile.eof()) {
+ //traceFile.read((char*) &ref, sizeof(ref));
+#ifndef NDEBUG
+ int gcount = traceFile.gcount();
+ assert(gcount != 0 || traceFile.eof());
+ assert(gcount == sizeof(ref));
+ assert(ref.cmd < 12);
+#endif
+ tmp_req = new MemReq();
+ tmp_req->paddr = ref.paddr;
+ tmp_req->asid = ref.asid;
+ // Assume asid == thread_num
+ tmp_req->thread_num = ref.asid;
+ tmp_req->cmd = (MemCmdEnum)ref.cmd;
+ tmp_req->size = ref.size;
+ tmp_req->dest = ref.dest;
+ } else {
+ ref.cycle = 0;
+ }
+ req = tmp_req;
+ return ref.cycle;
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(M5Reader)
+
+ Param<string> filename;
+
+END_DECLARE_SIM_OBJECT_PARAMS(M5Reader)
+
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(M5Reader)
+
+ INIT_PARAM(filename, "trace file")
+
+END_INIT_SIM_OBJECT_PARAMS(M5Reader)
+
+
+CREATE_SIM_OBJECT(M5Reader)
+{
+ return new M5Reader(getInstanceName(), filename);
+}
+
+REGISTER_SIM_OBJECT("M5Reader", M5Reader)
diff --git a/src/cpu/trace/reader/m5_reader.hh b/src/cpu/trace/reader/m5_reader.hh
new file mode 100644
index 000000000..974a83ffa
--- /dev/null
+++ b/src/cpu/trace/reader/m5_reader.hh
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * Definition of a memory trace reader for a M5 memory trace.
+ */
+
+#ifndef __M5_READER_HH__
+#define __M5_READER_HH__
+
+#include <fstream>
+
+#include "cpu/trace/reader/mem_trace_reader.hh"
+
+/**
+ * A memory trace reader for an M5 memory trace. @sa M5Writer.
+ */
+class M5Reader : public MemTraceReader
+{
+ /** The traceFile. */
+ std::ifstream traceFile;
+
+ std::string fn;
+
+ public:
+ /**
+ * Construct an M5 memory trace reader.
+ */
+ M5Reader(const std::string &name, const std::string &filename);
+
+
+ /**
+ * Read the next request from the trace. Returns the request in the
+ * provided MemReqPtr and the cycle of the request in the return value.
+ * @param req Return the next request from the trace.
+ * @return The cycle the reference was started.
+ */
+ virtual Tick getNextReq(MemReqPtr &req);
+};
+
+#endif // __M5_READER_HH__
diff --git a/src/cpu/trace/reader/mem_trace_reader.cc b/src/cpu/trace/reader/mem_trace_reader.cc
new file mode 100644
index 000000000..769f0be27
--- /dev/null
+++ b/src/cpu/trace/reader/mem_trace_reader.cc
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * SimObject Declaration of pure virtual MemTraceReader class.
+ */
+
+#include "cpu/trace/reader/mem_trace_reader.hh"
+#include "sim/param.hh"
+
+DEFINE_SIM_OBJECT_CLASS_NAME("MemTraceReader", MemTraceReader);
diff --git a/src/cpu/trace/reader/mem_trace_reader.hh b/src/cpu/trace/reader/mem_trace_reader.hh
new file mode 100644
index 000000000..b433cdbdd
--- /dev/null
+++ b/src/cpu/trace/reader/mem_trace_reader.hh
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * Definitions for a pure virtual interface to a memory trace reader.
+ */
+
+#ifndef __MEM_TRACE_READER_HH__
+#define __MEM_TRACE_READER_HH__
+
+#include "sim/sim_object.hh"
+#include "mem/mem_req.hh" // For MemReqPtr
+
+/**
+ * Pure virtual base class for memory trace readers.
+ */
+class MemTraceReader : public SimObject
+{
+ public:
+ /** Construct this MemoryTrace reader. */
+ MemTraceReader(const std::string &name) : SimObject(name) {}
+
+ /**
+ * Read the next request from the trace. Returns the request in the
+ * provided MemReqPtr and the cycle of the request in the return value.
+ * @param req Return the next request from the trace.
+ * @return The cycle of the request, 0 if none in trace.
+ */
+ virtual Tick getNextReq(MemReqPtr &req) = 0;
+};
+
+#endif //__MEM_TRACE_READER_HH__
diff --git a/src/cpu/trace/trace_cpu.cc b/src/cpu/trace/trace_cpu.cc
new file mode 100644
index 000000000..20d0a567f
--- /dev/null
+++ b/src/cpu/trace/trace_cpu.cc
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * Declaration of a memory trace CPU object. Uses a memory trace to drive the
+ * provided memory hierarchy.
+ */
+
+#include <algorithm> // For min
+
+#include "cpu/trace/trace_cpu.hh"
+#include "cpu/trace/reader/mem_trace_reader.hh"
+#include "mem/base_mem.hh" // For PARAM constructor
+#include "mem/mem_interface.hh"
+#include "sim/builder.hh"
+#include "sim/sim_events.hh"
+
+using namespace std;
+
+TraceCPU::TraceCPU(const string &name,
+ MemInterface *icache_interface,
+ MemInterface *dcache_interface,
+ MemTraceReader *data_trace)
+ : SimObject(name), icacheInterface(icache_interface),
+ dcacheInterface(dcache_interface),
+ dataTrace(data_trace), outstandingRequests(0), tickEvent(this)
+{
+ assert(dcacheInterface);
+ nextCycle = dataTrace->getNextReq(nextReq);
+ tickEvent.schedule(0);
+}
+
+void
+TraceCPU::tick()
+{
+ assert(outstandingRequests >= 0);
+ assert(outstandingRequests < 1000);
+ int instReqs = 0;
+ int dataReqs = 0;
+
+ while (nextReq && curTick >= nextCycle) {
+ assert(nextReq->thread_num < 4 && "Not enough threads");
+ if (nextReq->isInstRead() && icacheInterface) {
+ if (icacheInterface->isBlocked())
+ break;
+
+ nextReq->time = curTick;
+ if (nextReq->cmd == Squash) {
+ icacheInterface->squash(nextReq->asid);
+ } else {
+ ++instReqs;
+ if (icacheInterface->doEvents()) {
+ nextReq->completionEvent =
+ new TraceCompleteEvent(nextReq, this);
+ icacheInterface->access(nextReq);
+ } else {
+ icacheInterface->access(nextReq);
+ completeRequest(nextReq);
+ }
+ }
+ } else {
+ if (dcacheInterface->isBlocked())
+ break;
+
+ ++dataReqs;
+ nextReq->time = curTick;
+ if (dcacheInterface->doEvents()) {
+ nextReq->completionEvent =
+ new TraceCompleteEvent(nextReq, this);
+ dcacheInterface->access(nextReq);
+ } else {
+ dcacheInterface->access(nextReq);
+ completeRequest(nextReq);
+ }
+
+ }
+ nextCycle = dataTrace->getNextReq(nextReq);
+ }
+
+ if (!nextReq) {
+ // No more requests to send. Finish trailing events and exit.
+ if (mainEventQueue.empty()) {
+ new SimExitEvent("Finshed Memory Trace");
+ } else {
+ tickEvent.schedule(mainEventQueue.nextEventTime() + cycles(1));
+ }
+ } else {
+ tickEvent.schedule(max(curTick + cycles(1), nextCycle));
+ }
+}
+
+void
+TraceCPU::completeRequest(MemReqPtr& req)
+{
+}
+
+void
+TraceCompleteEvent::process()
+{
+ tester->completeRequest(req);
+}
+
+const char *
+TraceCompleteEvent::description()
+{
+ return "trace access complete";
+}
+
+TraceCPU::TickEvent::TickEvent(TraceCPU *c)
+ : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c)
+{
+}
+
+void
+TraceCPU::TickEvent::process()
+{
+ cpu->tick();
+}
+
+const char *
+TraceCPU::TickEvent::description()
+{
+ return "TraceCPU tick event";
+}
+
+
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(TraceCPU)
+
+ SimObjectParam<BaseMem *> icache;
+ SimObjectParam<BaseMem *> dcache;
+ SimObjectParam<MemTraceReader *> data_trace;
+
+END_DECLARE_SIM_OBJECT_PARAMS(TraceCPU)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(TraceCPU)
+
+ INIT_PARAM_DFLT(icache, "instruction cache", NULL),
+ INIT_PARAM_DFLT(dcache, "data cache", NULL),
+ INIT_PARAM_DFLT(data_trace, "data trace", NULL)
+
+END_INIT_SIM_OBJECT_PARAMS(TraceCPU)
+
+CREATE_SIM_OBJECT(TraceCPU)
+{
+ return new TraceCPU(getInstanceName(),
+ (icache) ? icache->getInterface() : NULL,
+ (dcache) ? dcache->getInterface() : NULL,
+ data_trace);
+}
+
+REGISTER_SIM_OBJECT("TraceCPU", TraceCPU)
+
diff --git a/src/cpu/trace/trace_cpu.hh b/src/cpu/trace/trace_cpu.hh
new file mode 100644
index 000000000..69ca35321
--- /dev/null
+++ b/src/cpu/trace/trace_cpu.hh
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * Declaration of a memory trace CPU object. Uses a memory trace to drive the
+ * provided memory hierarchy.
+ */
+
+#ifndef __CPU_TRACE_TRACE_CPU_HH__
+#define __CPU_TRACE_TRACE_CPU_HH__
+
+#include <string>
+
+#include "mem/mem_req.hh" // for MemReqPtr
+#include "sim/eventq.hh" // for Event
+#include "sim/sim_object.hh"
+
+// Forward declaration.
+class MemInterface;
+class MemTraceReader;
+
+/**
+ * A cpu object for running memory traces through a memory hierarchy.
+ */
+class TraceCPU : public SimObject
+{
+ private:
+ /** Interface for instruction trace requests, if any. */
+ MemInterface *icacheInterface;
+ /** Interface for data trace requests, if any. */
+ MemInterface *dcacheInterface;
+
+ /** Data reference trace. */
+ MemTraceReader *dataTrace;
+
+ /** Number of outstanding requests. */
+ int outstandingRequests;
+
+ /** Cycle of the next request, 0 if not available. */
+ Tick nextCycle;
+
+ /** Next request. */
+ MemReqPtr nextReq;
+
+ /**
+ * Event to call the TraceCPU::tick
+ */
+ class TickEvent : public Event
+ {
+ private:
+ /** The associated CPU */
+ TraceCPU *cpu;
+
+ public:
+ /**
+ * Construct this event;
+ */
+ TickEvent(TraceCPU *c);
+
+ /**
+ * Call the tick function.
+ */
+ void process();
+
+ /**
+ * Return a string description of this event.
+ */
+ const char *description();
+ };
+
+ TickEvent tickEvent;
+
+ public:
+ /**
+ * Construct a TraceCPU object.
+ */
+ TraceCPU(const std::string &name,
+ MemInterface *icache_interface,
+ MemInterface *dcache_interface,
+ MemTraceReader *data_trace);
+
+ inline Tick cycles(int numCycles) { return numCycles; }
+
+ /**
+ * Perform all the accesses for one cycle.
+ */
+ void tick();
+
+ /**
+ * Handle a completed memory request.
+ */
+ void completeRequest(MemReqPtr &req);
+};
+
+class TraceCompleteEvent : public Event
+{
+ MemReqPtr req;
+ TraceCPU *tester;
+
+ public:
+
+ TraceCompleteEvent(MemReqPtr &_req, TraceCPU *_tester)
+ : Event(&mainEventQueue), req(_req), tester(_tester)
+ {
+ setFlags(AutoDelete);
+ }
+
+ void process();
+
+ virtual const char *description();
+};
+
+#endif // __CPU_TRACE_TRACE_CPU_HH__
+
diff --git a/src/dev/alpha_access.h b/src/dev/alpha_access.h
new file mode 100644
index 000000000..5a1df6f39
--- /dev/null
+++ b/src/dev/alpha_access.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ALPHA_ACCESS_H__
+#define __ALPHA_ACCESS_H__
+
+/** @file
+ * System Console Memory Mapped Register Definition
+ */
+
+#define ALPHA_ACCESS_VERSION (1305)
+
+#ifdef CONSOLE
+typedef unsigned uint32_t;
+typedef unsigned long uint64_t;
+#endif
+
+// This structure hacked up from simos
+struct AlphaAccess
+{
+ uint32_t last_offset; // 00: must be first field
+ uint32_t version; // 04:
+ uint32_t numCPUs; // 08:
+ uint32_t intrClockFrequency; // 0C: Hz
+ uint64_t cpuClock; // 10: MHz
+ uint64_t mem_size; // 18:
+
+ // Loaded kernel
+ uint64_t kernStart; // 20:
+ uint64_t kernEnd; // 28:
+ uint64_t entryPoint; // 30:
+
+ // console disk stuff
+ uint64_t diskUnit; // 38:
+ uint64_t diskCount; // 40:
+ uint64_t diskPAddr; // 48:
+ uint64_t diskBlock; // 50:
+ uint64_t diskOperation; // 58:
+
+ // console simple output stuff
+ uint64_t outputChar; // 60: Placeholder for output
+ uint64_t inputChar; // 68: Placeholder for input
+
+ // MP boot
+ uint64_t cpuStack[64]; // 70:
+};
+
+#endif // __ALPHA_ACCESS_H__
diff --git a/src/dev/alpha_console.cc b/src/dev/alpha_console.cc
new file mode 100644
index 000000000..f24c09844
--- /dev/null
+++ b/src/dev/alpha_console.cc
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * Alpha Console Definition
+ */
+
+#include <cstddef>
+#include <string>
+
+#include "arch/alpha/system.hh"
+#include "base/inifile.hh"
+#include "base/str.hh"
+#include "base/trace.hh"
+#include "cpu/base.hh"
+#include "cpu/exec_context.hh"
+#include "dev/alpha_console.hh"
+#include "dev/platform.hh"
+#include "dev/simconsole.hh"
+#include "dev/simple_disk.hh"
+#include "mem/physical.hh"
+#include "sim/builder.hh"
+#include "sim/sim_object.hh"
+
+using namespace std;
+using namespace AlphaISA;
+
+AlphaConsole::AlphaConsole(Params *p)
+ : BasicPioDevice(p), disk(p->disk),
+ console(params()->cons), system(params()->alpha_sys), cpu(params()->cpu)
+{
+
+ pioSize = sizeof(struct AlphaAccess);
+
+ alphaAccess = new Access();
+ alphaAccess->last_offset = pioSize - 1;
+
+ alphaAccess->version = ALPHA_ACCESS_VERSION;
+ alphaAccess->diskUnit = 1;
+
+ alphaAccess->diskCount = 0;
+ alphaAccess->diskPAddr = 0;
+ alphaAccess->diskBlock = 0;
+ alphaAccess->diskOperation = 0;
+ alphaAccess->outputChar = 0;
+ alphaAccess->inputChar = 0;
+ bzero(alphaAccess->cpuStack, sizeof(alphaAccess->cpuStack));
+
+}
+
+void
+AlphaConsole::startup()
+{
+ system->setAlphaAccess(pioAddr);
+ alphaAccess->numCPUs = system->getNumCPUs();
+ alphaAccess->kernStart = system->getKernelStart();
+ alphaAccess->kernEnd = system->getKernelEnd();
+ alphaAccess->entryPoint = system->getKernelEntry();
+ alphaAccess->mem_size = system->physmem->size();
+ alphaAccess->cpuClock = cpu->frequency() / 1000000; // In MHz
+ alphaAccess->intrClockFrequency = params()->platform->intrFrequency();
+}
+
+Tick
+AlphaConsole::read(Packet *pkt)
+{
+
+ /** XXX Do we want to push the addr munging to a bus brige or something? So
+ * the device has it's physical address and then the bridge adds on whatever
+ * machine dependent address swizzle is required?
+ */
+
+ assert(pkt->result == Unknown);
+ assert(pkt->addr >= pioAddr && pkt->addr < pioAddr + pioSize);
+
+ pkt->time += pioDelay;
+ Addr daddr = pkt->addr - pioAddr;
+
+ pkt->allocate();
+
+ switch (pkt->size)
+ {
+ case sizeof(uint32_t):
+ switch (daddr)
+ {
+ case offsetof(AlphaAccess, last_offset):
+ pkt->set(alphaAccess->last_offset);
+ break;
+ case offsetof(AlphaAccess, version):
+ pkt->set(alphaAccess->version);
+ break;
+ case offsetof(AlphaAccess, numCPUs):
+ pkt->set(alphaAccess->numCPUs);
+ break;
+ case offsetof(AlphaAccess, intrClockFrequency):
+ pkt->set(alphaAccess->intrClockFrequency);
+ break;
+ default:
+ /* Old console code read in everyting as a 32bit int
+ * we now break that for better error checking.
+ */
+ pkt->result = BadAddress;
+ }
+ DPRINTF(AlphaConsole, "read: offset=%#x val=%#x\n", daddr,
+ pkt->get<uint32_t>());
+ break;
+ case sizeof(uint64_t):
+ switch (daddr)
+ {
+ case offsetof(AlphaAccess, inputChar):
+ pkt->set(console->console_in());
+ break;
+ case offsetof(AlphaAccess, cpuClock):
+ pkt->set(alphaAccess->cpuClock);
+ break;
+ case offsetof(AlphaAccess, mem_size):
+ pkt->set(alphaAccess->mem_size);
+ break;
+ case offsetof(AlphaAccess, kernStart):
+ pkt->set(alphaAccess->kernStart);
+ break;
+ case offsetof(AlphaAccess, kernEnd):
+ pkt->set(alphaAccess->kernEnd);
+ break;
+ case offsetof(AlphaAccess, entryPoint):
+ pkt->set(alphaAccess->entryPoint);
+ break;
+ case offsetof(AlphaAccess, diskUnit):
+ pkt->set(alphaAccess->diskUnit);
+ break;
+ case offsetof(AlphaAccess, diskCount):
+ pkt->set(alphaAccess->diskCount);
+ break;
+ case offsetof(AlphaAccess, diskPAddr):
+ pkt->set(alphaAccess->diskPAddr);
+ break;
+ case offsetof(AlphaAccess, diskBlock):
+ pkt->set(alphaAccess->diskBlock);
+ break;
+ case offsetof(AlphaAccess, diskOperation):
+ pkt->set(alphaAccess->diskOperation);
+ break;
+ case offsetof(AlphaAccess, outputChar):
+ pkt->set(alphaAccess->outputChar);
+ break;
+ default:
+ int cpunum = (daddr - offsetof(AlphaAccess, cpuStack)) /
+ sizeof(alphaAccess->cpuStack[0]);
+
+ if (cpunum >= 0 && cpunum < 64)
+ pkt->set(alphaAccess->cpuStack[cpunum]);
+ else
+ panic("Unknown 64bit access, %#x\n", daddr);
+ }
+ DPRINTF(AlphaConsole, "read: offset=%#x val=%#x\n", daddr,
+ pkt->get<uint64_t>());
+ break;
+ default:
+ pkt->result = BadAddress;
+ }
+ if (pkt->result == Unknown) pkt->result = Success;
+ return pioDelay;
+}
+
+Tick
+AlphaConsole::write(Packet *pkt)
+{
+ pkt->time += pioDelay;
+
+ assert(pkt->result == Unknown);
+ assert(pkt->addr >= pioAddr && pkt->addr < pioAddr + pioSize);
+ Addr daddr = pkt->addr - pioAddr;
+
+ uint64_t val = pkt->get<uint64_t>();
+ assert(pkt->size == sizeof(uint64_t));
+
+ switch (daddr) {
+ case offsetof(AlphaAccess, diskUnit):
+ alphaAccess->diskUnit = val;
+ break;
+
+ case offsetof(AlphaAccess, diskCount):
+ alphaAccess->diskCount = val;
+ break;
+
+ case offsetof(AlphaAccess, diskPAddr):
+ alphaAccess->diskPAddr = val;
+ break;
+
+ case offsetof(AlphaAccess, diskBlock):
+ alphaAccess->diskBlock = val;
+ break;
+
+ case offsetof(AlphaAccess, diskOperation):
+ if (val == 0x13)
+ disk->read(alphaAccess->diskPAddr, alphaAccess->diskBlock,
+ alphaAccess->diskCount);
+ else
+ panic("Invalid disk operation!");
+
+ break;
+
+ case offsetof(AlphaAccess, outputChar):
+ console->out((char)(val & 0xff));
+ break;
+
+ default:
+ int cpunum = (daddr - offsetof(AlphaAccess, cpuStack)) /
+ sizeof(alphaAccess->cpuStack[0]);
+ warn("%d: Trying to launch CPU number %d!", curTick, cpunum);
+ assert(val > 0 && "Must not access primary cpu");
+ if (cpunum >= 0 && cpunum < 64)
+ alphaAccess->cpuStack[cpunum] = val;
+ else
+ panic("Unknown 64bit access, %#x\n", daddr);
+ }
+
+ pkt->result = Success;
+
+ return pioDelay;
+}
+
+void
+AlphaConsole::Access::serialize(ostream &os)
+{
+ SERIALIZE_SCALAR(last_offset);
+ SERIALIZE_SCALAR(version);
+ SERIALIZE_SCALAR(numCPUs);
+ SERIALIZE_SCALAR(mem_size);
+ SERIALIZE_SCALAR(cpuClock);
+ SERIALIZE_SCALAR(intrClockFrequency);
+ SERIALIZE_SCALAR(kernStart);
+ SERIALIZE_SCALAR(kernEnd);
+ SERIALIZE_SCALAR(entryPoint);
+ SERIALIZE_SCALAR(diskUnit);
+ SERIALIZE_SCALAR(diskCount);
+ SERIALIZE_SCALAR(diskPAddr);
+ SERIALIZE_SCALAR(diskBlock);
+ SERIALIZE_SCALAR(diskOperation);
+ SERIALIZE_SCALAR(outputChar);
+ SERIALIZE_SCALAR(inputChar);
+ SERIALIZE_ARRAY(cpuStack,64);
+}
+
+void
+AlphaConsole::Access::unserialize(Checkpoint *cp, const std::string &section)
+{
+ UNSERIALIZE_SCALAR(last_offset);
+ UNSERIALIZE_SCALAR(version);
+ UNSERIALIZE_SCALAR(numCPUs);
+ UNSERIALIZE_SCALAR(mem_size);
+ UNSERIALIZE_SCALAR(cpuClock);
+ UNSERIALIZE_SCALAR(intrClockFrequency);
+ UNSERIALIZE_SCALAR(kernStart);
+ UNSERIALIZE_SCALAR(kernEnd);
+ UNSERIALIZE_SCALAR(entryPoint);
+ UNSERIALIZE_SCALAR(diskUnit);
+ UNSERIALIZE_SCALAR(diskCount);
+ UNSERIALIZE_SCALAR(diskPAddr);
+ UNSERIALIZE_SCALAR(diskBlock);
+ UNSERIALIZE_SCALAR(diskOperation);
+ UNSERIALIZE_SCALAR(outputChar);
+ UNSERIALIZE_SCALAR(inputChar);
+ UNSERIALIZE_ARRAY(cpuStack, 64);
+}
+
+void
+AlphaConsole::serialize(ostream &os)
+{
+ alphaAccess->serialize(os);
+}
+
+void
+AlphaConsole::unserialize(Checkpoint *cp, const std::string &section)
+{
+ alphaAccess->unserialize(cp, section);
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaConsole)
+
+ SimObjectParam<SimConsole *> sim_console;
+ SimObjectParam<SimpleDisk *> disk;
+ Param<Addr> pio_addr;
+ SimObjectParam<AlphaSystem *> system;
+ SimObjectParam<BaseCPU *> cpu;
+ SimObjectParam<Platform *> platform;
+ Param<Tick> pio_latency;
+
+END_DECLARE_SIM_OBJECT_PARAMS(AlphaConsole)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaConsole)
+
+ INIT_PARAM(sim_console, "The Simulator Console"),
+ INIT_PARAM(disk, "Simple Disk"),
+ INIT_PARAM(pio_addr, "Device Address"),
+ INIT_PARAM(system, "system object"),
+ INIT_PARAM(cpu, "Processor"),
+ INIT_PARAM(platform, "platform"),
+ INIT_PARAM_DFLT(pio_latency, "Programmed IO latency", 1000)
+
+END_INIT_SIM_OBJECT_PARAMS(AlphaConsole)
+
+CREATE_SIM_OBJECT(AlphaConsole)
+{
+ AlphaConsole::Params *p = new AlphaConsole::Params;
+ p->name = getInstanceName();
+ p->platform = platform;
+ p->pio_addr = pio_addr;
+ p->pio_delay = pio_latency;
+ p->cons = sim_console;
+ p->disk = disk;
+ p->alpha_sys = system;
+ p->system = system;
+ p->cpu = cpu;
+ return new AlphaConsole(p);
+}
+
+REGISTER_SIM_OBJECT("AlphaConsole", AlphaConsole)
diff --git a/src/dev/alpha_console.hh b/src/dev/alpha_console.hh
new file mode 100644
index 000000000..34d21e15c
--- /dev/null
+++ b/src/dev/alpha_console.hh
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * System Console Interface
+ */
+
+#ifndef __ALPHA_CONSOLE_HH__
+#define __ALPHA_CONSOLE_HH__
+
+#include "base/range.hh"
+#include "dev/alpha_access.h"
+#include "dev/io_device.hh"
+#include "sim/host.hh"
+#include "sim/sim_object.hh"
+
+class BaseCPU;
+class SimConsole;
+class AlphaSystem;
+class SimpleDisk;
+
+/**
+ * Memory mapped interface to the system console. This device
+ * represents a shared data region between the OS Kernel and the
+ * System Console.
+ *
+ * The system console is a small standalone program that is initially
+ * run when the system boots. It contains the necessary code to
+ * access the boot disk, to read/write from the console, and to pass
+ * boot parameters to the kernel.
+ *
+ * This version of the system console is very different from the one
+ * that would be found in a real system. Many of the functions use
+ * some sort of backdoor to get their job done. For example, reading
+ * from the boot device on a real system would require a minimal
+ * device driver to access the disk controller, but since we have a
+ * simulator here, we are able to bypass the disk controller and
+ * access the disk image directly. There are also some things like
+ * reading the kernel off the disk image into memory that are normally
+ * taken care of by the console that are now taken care of by the
+ * simulator.
+ *
+ * These shortcuts are acceptable since the system console is
+ * primarily used doing boot before the kernel has loaded its device
+ * drivers.
+ */
+class AlphaConsole : public BasicPioDevice
+{
+ protected:
+ struct Access : public AlphaAccess
+ {
+ void serialize(std::ostream &os);
+ void unserialize(Checkpoint *cp, const std::string &section);
+ };
+
+ union {
+ Access *alphaAccess;
+ uint8_t *consoleData;
+ };
+
+ /** the disk must be accessed from the console */
+ SimpleDisk *disk;
+
+ /** the system console (the terminal) is accessable from the console */
+ SimConsole *console;
+
+ /** a pointer to the system we are running in */
+ AlphaSystem *system;
+
+ /** a pointer to the CPU boot cpu */
+ BaseCPU *cpu;
+
+ public:
+ struct Params : public BasicPioDevice::Params
+ {
+ SimConsole *cons;
+ SimpleDisk *disk;
+ AlphaSystem *alpha_sys;
+ BaseCPU *cpu;
+ };
+ protected:
+ const Params *params() const {return (const Params *)_params; }
+
+ public:
+
+ /** Standard Constructor */
+ AlphaConsole(Params *p);
+
+ virtual void startup();
+
+ /**
+ * memory mapped reads and writes
+ */
+ virtual Tick read(Packet *pkt);
+ virtual Tick write(Packet *pkt);
+
+ /**
+ * standard serialization routines for checkpointing
+ */
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+};
+
+#endif // __ALPHA_CONSOLE_HH__
diff --git a/src/dev/baddev.cc b/src/dev/baddev.cc
new file mode 100644
index 000000000..66fbd8a86
--- /dev/null
+++ b/src/dev/baddev.cc
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * BadDevice implemenation
+ */
+
+#include <deque>
+#include <string>
+#include <vector>
+
+#include "base/trace.hh"
+#include "dev/baddev.hh"
+#include "dev/platform.hh"
+#include "mem/port.hh"
+#include "sim/builder.hh"
+#include "sim/system.hh"
+
+using namespace std;
+using namespace TheISA;
+
+BadDevice::BadDevice(Params *p)
+ : BasicPioDevice(p), devname(p->device_name)
+{
+ pioSize = 0xf;
+}
+
+Tick
+BadDevice::read(Packet *pkt)
+{
+ panic("Device %s not imlpmented\n", devname);
+}
+
+Tick
+BadDevice::write(Packet *pkt)
+{
+ panic("Device %s not imlpmented\n", devname);
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(BadDevice)
+
+ Param<string> devicename;
+ Param<Addr> pio_addr;
+ SimObjectParam<System *> system;
+ SimObjectParam<Platform *> platform;
+ Param<Tick> pio_latency;
+
+END_DECLARE_SIM_OBJECT_PARAMS(BadDevice)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(BadDevice)
+
+ INIT_PARAM(devicename, "Name of device to error on"),
+ INIT_PARAM(pio_addr, "Device Address"),
+ INIT_PARAM(system, "system object"),
+ INIT_PARAM(platform, "platform"),
+ INIT_PARAM_DFLT(pio_latency, "Programmed IO latency", 1000)
+
+END_INIT_SIM_OBJECT_PARAMS(BadDevice)
+
+CREATE_SIM_OBJECT(BadDevice)
+{
+ BadDevice::Params *p = new BadDevice::Params;
+ p->name =getInstanceName();
+ p->platform = platform;
+ p->pio_addr = pio_addr;
+ p->pio_delay = pio_latency;
+ p->system = system;
+ p->device_name = devicename;
+ return new BadDevice(p);
+}
+
+REGISTER_SIM_OBJECT("BadDevice", BadDevice)
diff --git a/src/dev/baddev.hh b/src/dev/baddev.hh
new file mode 100644
index 000000000..35ae0382a
--- /dev/null
+++ b/src/dev/baddev.hh
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * This devices just panics when touched. For example if you have a
+ * kernel that touches the frame buffer which isn't allowed.
+ */
+
+#ifndef __DEV_BADDEV_HH__
+#define __DEV_BADDEV_HH__
+
+#include "base/range.hh"
+#include "dev/io_device.hh"
+
+
+/**
+ * BadDevice
+ * This device just panics when accessed. It is supposed to warn
+ * the user that the kernel they are running has unsupported
+ * options (i.e. frame buffer)
+ */
+class BadDevice : public BasicPioDevice
+{
+ private:
+ std::string devname;
+
+ public:
+ struct Params : public BasicPioDevice::Params
+ {
+ std::string device_name;
+ };
+ protected:
+ const Params *params() const { return (const Params *)_params; }
+
+ public:
+ /**
+ * Constructor for the Baddev Class.
+ * @param p object parameters
+ * @param a base address of the write
+ */
+ BadDevice(Params *p);
+
+ virtual Tick read(Packet *pkt);
+ virtual Tick write(Packet *pkt);
+};
+
+#endif // __DEV_BADDEV_HH__
diff --git a/src/dev/disk_image.cc b/src/dev/disk_image.cc
new file mode 100644
index 000000000..185a8b083
--- /dev/null
+++ b/src/dev/disk_image.cc
@@ -0,0 +1,470 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * Disk Image Definitions
+ */
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <cstring>
+#include <fstream>
+#include <string>
+
+#include "base/callback.hh"
+#include "base/misc.hh"
+#include "base/trace.hh"
+#include "dev/disk_image.hh"
+#include "sim/builder.hh"
+#include "sim/sim_exit.hh"
+#include "sim/byteswap.hh"
+
+using namespace std;
+
+////////////////////////////////////////////////////////////////////////
+//
+// Raw Disk image
+//
+RawDiskImage::RawDiskImage(const string &name, const string &filename,
+ bool rd_only)
+ : DiskImage(name), disk_size(0)
+{ open(filename, rd_only); }
+
+RawDiskImage::~RawDiskImage()
+{ close(); }
+
+void
+RawDiskImage::open(const string &filename, bool rd_only)
+{
+ if (!filename.empty()) {
+ initialized = true;
+ readonly = rd_only;
+ file = filename;
+
+ ios::openmode mode = ios::in | ios::binary;
+ if (!readonly)
+ mode |= ios::out;
+ stream.open(file.c_str(), mode);
+ if (!stream.is_open())
+ panic("Error opening %s", filename);
+ }
+}
+
+void
+RawDiskImage::close()
+{
+ stream.close();
+}
+
+off_t
+RawDiskImage::size() const
+{
+ if (disk_size == 0) {
+ if (!stream.is_open())
+ panic("file not open!\n");
+ stream.seekg(0, ios::end);
+ disk_size = stream.tellg();
+ }
+
+ return disk_size / SectorSize;
+}
+
+off_t
+RawDiskImage::read(uint8_t *data, off_t offset) const
+{
+ if (!initialized)
+ panic("RawDiskImage not initialized");
+
+ if (!stream.is_open())
+ panic("file not open!\n");
+
+ if (stream.seekg(offset * SectorSize, ios::beg) < 0)
+ panic("Could not seek to location in file");
+
+ streampos pos = stream.tellg();
+ stream.read((char *)data, SectorSize);
+
+ DPRINTF(DiskImageRead, "read: offset=%d\n", (uint64_t)offset);
+ DDUMP(DiskImageRead, data, SectorSize);
+
+ return stream.tellg() - pos;
+}
+
+off_t
+RawDiskImage::write(const uint8_t *data, off_t offset)
+{
+ if (!initialized)
+ panic("RawDiskImage not initialized");
+
+ if (readonly)
+ panic("Cannot write to a read only disk image");
+
+ if (!stream.is_open())
+ panic("file not open!\n");
+
+ if (stream.seekp(offset * SectorSize, ios::beg) < 0)
+ panic("Could not seek to location in file");
+
+ DPRINTF(DiskImageWrite, "write: offset=%d\n", (uint64_t)offset);
+ DDUMP(DiskImageWrite, data, SectorSize);
+
+ streampos pos = stream.tellp();
+ stream.write((const char *)data, SectorSize);
+ return stream.tellp() - pos;
+}
+
+DEFINE_SIM_OBJECT_CLASS_NAME("DiskImage", DiskImage)
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(RawDiskImage)
+
+ Param<string> image_file;
+ Param<bool> read_only;
+
+END_DECLARE_SIM_OBJECT_PARAMS(RawDiskImage)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(RawDiskImage)
+
+ INIT_PARAM(image_file, "disk image file"),
+ INIT_PARAM_DFLT(read_only, "read only image", false)
+
+END_INIT_SIM_OBJECT_PARAMS(RawDiskImage)
+
+
+CREATE_SIM_OBJECT(RawDiskImage)
+{
+ return new RawDiskImage(getInstanceName(), image_file, read_only);
+}
+
+REGISTER_SIM_OBJECT("RawDiskImage", RawDiskImage)
+
+////////////////////////////////////////////////////////////////////////
+//
+// Copy on Write Disk image
+//
+const int CowDiskImage::VersionMajor = 1;
+const int CowDiskImage::VersionMinor = 0;
+
+CowDiskImage::CowDiskImage(const string &name, DiskImage *kid, int hash_size)
+ : DiskImage(name), child(kid), table(NULL)
+{ init(hash_size); }
+
+class CowDiskCallback : public Callback
+{
+ private:
+ CowDiskImage *image;
+
+ public:
+ CowDiskCallback(CowDiskImage *i) : image(i) {}
+ void process() { image->save(); delete this; }
+};
+
+CowDiskImage::CowDiskImage(const string &name, DiskImage *kid, int hash_size,
+ const string &file, bool read_only)
+ : DiskImage(name), filename(file), child(kid), table(NULL)
+{
+ if (!open(filename)) {
+ assert(!read_only && "why have a non-existent read only file?");
+ init(hash_size);
+ }
+
+ if (!read_only)
+ registerExitCallback(new CowDiskCallback(this));
+}
+
+CowDiskImage::~CowDiskImage()
+{
+ SectorTable::iterator i = table->begin();
+ SectorTable::iterator end = table->end();
+
+ while (i != end) {
+ delete (*i).second;
+ ++i;
+ }
+}
+
+void
+SafeRead(ifstream &stream, void *data, int count)
+{
+ stream.read((char *)data, count);
+ if (!stream.is_open())
+ panic("file not open");
+
+ if (stream.eof())
+ panic("premature end-of-file");
+
+ if (stream.bad() || stream.fail())
+ panic("error reading cowdisk image");
+}
+
+template<class T>
+void
+SafeRead(ifstream &stream, T &data)
+{
+ SafeRead(stream, &data, sizeof(data));
+}
+
+template<class T>
+void
+SafeReadSwap(ifstream &stream, T &data)
+{
+ SafeRead(stream, &data, sizeof(data));
+ data = letoh(data); //is this the proper byte order conversion?
+}
+
+bool
+CowDiskImage::open(const string &file)
+{
+ ifstream stream(file.c_str());
+ if (!stream.is_open())
+ return false;
+
+ if (stream.fail() || stream.bad())
+ panic("Error opening %s", file);
+
+ uint64_t magic;
+ SafeRead(stream, magic);
+
+ if (memcmp(&magic, "COWDISK!", sizeof(magic)) != 0)
+ panic("Could not open %s: Invalid magic", file);
+
+ uint32_t major, minor;
+ SafeReadSwap(stream, major);
+ SafeReadSwap(stream, minor);
+
+ if (major != VersionMajor && minor != VersionMinor)
+ panic("Could not open %s: invalid version %d.%d != %d.%d",
+ file, major, minor, VersionMajor, VersionMinor);
+
+ uint64_t sector_count;
+ SafeReadSwap(stream, sector_count);
+ table = new SectorTable(sector_count);
+
+
+ for (uint64_t i = 0; i < sector_count; i++) {
+ uint64_t offset;
+ SafeReadSwap(stream, offset);
+
+ Sector *sector = new Sector;
+ SafeRead(stream, sector, sizeof(Sector));
+
+ assert(table->find(offset) == table->end());
+ (*table)[offset] = sector;
+ }
+
+ stream.close();
+
+ initialized = true;
+ return true;
+}
+
+void
+CowDiskImage::init(int hash_size)
+{
+ table = new SectorTable(hash_size);
+
+ initialized = true;
+}
+
+void
+SafeWrite(ofstream &stream, const void *data, int count)
+{
+ stream.write((const char *)data, count);
+ if (!stream.is_open())
+ panic("file not open");
+
+ if (stream.eof())
+ panic("premature end-of-file");
+
+ if (stream.bad() || stream.fail())
+ panic("error reading cowdisk image");
+}
+
+template<class T>
+void
+SafeWrite(ofstream &stream, const T &data)
+{
+ SafeWrite(stream, &data, sizeof(data));
+}
+
+template<class T>
+void
+SafeWriteSwap(ofstream &stream, const T &data)
+{
+ T swappeddata = letoh(data); //is this the proper byte order conversion?
+ SafeWrite(stream, &swappeddata, sizeof(data));
+}
+void
+CowDiskImage::save()
+{
+ save(filename);
+}
+
+void
+CowDiskImage::save(const string &file)
+{
+ if (!initialized)
+ panic("RawDiskImage not initialized");
+
+ ofstream stream(file.c_str());
+ if (!stream.is_open() || stream.fail() || stream.bad())
+ panic("Error opening %s", file);
+
+ uint64_t magic;
+ memcpy(&magic, "COWDISK!", sizeof(magic));
+ SafeWrite(stream, magic);
+
+ SafeWriteSwap(stream, (uint32_t)VersionMajor);
+ SafeWriteSwap(stream, (uint32_t)VersionMinor);
+ SafeWriteSwap(stream, (uint64_t)table->size());
+
+ uint64_t size = table->size();
+ SectorTable::iterator iter = table->begin();
+ SectorTable::iterator end = table->end();
+
+ for (uint64_t i = 0; i < size; i++) {
+ if (iter == end)
+ panic("Incorrect Table Size during save of COW disk image");
+
+ SafeWriteSwap(stream, (uint64_t)(*iter).first);
+ SafeWrite(stream, (*iter).second->data, sizeof(Sector));
+ ++iter;
+ }
+
+ stream.close();
+}
+
+void
+CowDiskImage::writeback()
+{
+ SectorTable::iterator i = table->begin();
+ SectorTable::iterator end = table->end();
+
+ while (i != end) {
+ child->write((*i).second->data, (*i).first);
+ ++i;
+ }
+}
+
+off_t
+CowDiskImage::size() const
+{ return child->size(); }
+
+off_t
+CowDiskImage::read(uint8_t *data, off_t offset) const
+{
+ if (!initialized)
+ panic("CowDiskImage not initialized");
+
+ if (offset > size())
+ panic("access out of bounds");
+
+ SectorTable::const_iterator i = table->find(offset);
+ if (i == table->end())
+ return child->read(data, offset);
+ else {
+ memcpy(data, (*i).second->data, SectorSize);
+ DPRINTF(DiskImageRead, "read: offset=%d\n", (uint64_t)offset);
+ DDUMP(DiskImageRead, data, SectorSize);
+ return SectorSize;
+ }
+}
+
+off_t
+CowDiskImage::write(const uint8_t *data, off_t offset)
+{
+ if (!initialized)
+ panic("RawDiskImage not initialized");
+
+ if (offset > size())
+ panic("access out of bounds");
+
+ SectorTable::iterator i = table->find(offset);
+ if (i == table->end()) {
+ Sector *sector = new Sector;
+ memcpy(sector, data, SectorSize);
+ table->insert(make_pair(offset, sector));
+ } else {
+ memcpy((*i).second->data, data, SectorSize);
+ }
+
+ DPRINTF(DiskImageWrite, "write: offset=%d\n", (uint64_t)offset);
+ DDUMP(DiskImageWrite, data, SectorSize);
+
+ return SectorSize;
+}
+
+void
+CowDiskImage::serialize(ostream &os)
+{
+ string cowFilename = name() + ".cow";
+ SERIALIZE_SCALAR(cowFilename);
+ save(Checkpoint::dir() + "/" + cowFilename);
+}
+
+void
+CowDiskImage::unserialize(Checkpoint *cp, const string &section)
+{
+ string cowFilename;
+ UNSERIALIZE_SCALAR(cowFilename);
+ cowFilename = cp->cptDir + "/" + cowFilename;
+ open(cowFilename);
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(CowDiskImage)
+
+ SimObjectParam<DiskImage *> child;
+ Param<string> image_file;
+ Param<int> table_size;
+ Param<bool> read_only;
+
+END_DECLARE_SIM_OBJECT_PARAMS(CowDiskImage)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(CowDiskImage)
+
+ INIT_PARAM(child, "child image"),
+ INIT_PARAM_DFLT(image_file, "disk image file", ""),
+ INIT_PARAM_DFLT(table_size, "initial table size", 65536),
+ INIT_PARAM_DFLT(read_only, "don't write back to the copy-on-write file",
+ true)
+
+END_INIT_SIM_OBJECT_PARAMS(CowDiskImage)
+
+
+CREATE_SIM_OBJECT(CowDiskImage)
+{
+ if (((string)image_file).empty())
+ return new CowDiskImage(getInstanceName(), child, table_size);
+ else
+ return new CowDiskImage(getInstanceName(), child, table_size,
+ image_file, read_only);
+}
+
+REGISTER_SIM_OBJECT("CowDiskImage", CowDiskImage)
diff --git a/src/dev/disk_image.hh b/src/dev/disk_image.hh
new file mode 100644
index 000000000..648aa20c6
--- /dev/null
+++ b/src/dev/disk_image.hh
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * Disk Image Interfaces
+ */
+
+#ifndef __DISK_IMAGE_HH__
+#define __DISK_IMAGE_HH__
+
+#include <fstream>
+
+#include "base/hashmap.hh"
+#include "sim/sim_object.hh"
+
+#define SectorSize (512)
+
+/**
+ * Basic interface for accessing a disk image.
+ */
+class DiskImage : public SimObject
+{
+ protected:
+ bool initialized;
+
+ public:
+ DiskImage(const std::string &name) : SimObject(name), initialized(false) {}
+ virtual ~DiskImage() {}
+
+ virtual off_t size() const = 0;
+
+ virtual off_t read(uint8_t *data, off_t offset) const = 0;
+ virtual off_t write(const uint8_t *data, off_t offset) = 0;
+};
+
+/**
+ * Specialization for accessing a raw disk image
+ */
+class RawDiskImage : public DiskImage
+{
+ protected:
+ mutable std::fstream stream;
+ std::string file;
+ bool readonly;
+ mutable off_t disk_size;
+
+ public:
+ RawDiskImage(const std::string &name, const std::string &filename,
+ bool rd_only);
+ ~RawDiskImage();
+
+ void close();
+ void open(const std::string &filename, bool rd_only = false);
+
+ virtual off_t size() const;
+
+ virtual off_t read(uint8_t *data, off_t offset) const;
+ virtual off_t write(const uint8_t *data, off_t offset);
+};
+
+/**
+ * Specialization for accessing a copy-on-write disk image layer.
+ * A copy-on-write(COW) layer must be stacked on top of another disk
+ * image layer this layer can be another CowDiskImage, or a
+ * RawDiskImage.
+ *
+ * This object is designed to provide a mechanism for persistant
+ * changes to a main disk image, or to provide a place for temporary
+ * changes to the image to take place that later may be thrown away.
+ */
+class CowDiskImage : public DiskImage
+{
+ public:
+ static const int VersionMajor;
+ static const int VersionMinor;
+
+ protected:
+ struct Sector {
+ uint8_t data[SectorSize];
+ };
+ typedef m5::hash_map<uint64_t, Sector *> SectorTable;
+
+ protected:
+ std::string filename;
+ DiskImage *child;
+ SectorTable *table;
+
+ public:
+ CowDiskImage(const std::string &name, DiskImage *kid, int hash_size);
+ CowDiskImage(const std::string &name, DiskImage *kid, int hash_size,
+ const std::string &filename, bool read_only);
+ ~CowDiskImage();
+
+ void init(int hash_size);
+ bool open(const std::string &file);
+ void save();
+ void save(const std::string &file);
+ void writeback();
+ void serialize(std::ostream &os);
+ void unserialize(Checkpoint *cp, const std::string &section);
+
+ virtual off_t size() const;
+
+ virtual off_t read(uint8_t *data, off_t offset) const;
+ virtual off_t write(const uint8_t *data, off_t offset);
+};
+
+#endif // __DISK_IMAGE_HH__
diff --git a/src/dev/etherbus.cc b/src/dev/etherbus.cc
new file mode 100644
index 000000000..906e324d3
--- /dev/null
+++ b/src/dev/etherbus.cc
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* @file
+ * Device module for modelling an ethernet hub
+ */
+
+#include <cmath>
+#include <deque>
+#include <string>
+#include <vector>
+
+#include "base/trace.hh"
+#include "dev/etherbus.hh"
+#include "dev/etherdump.hh"
+#include "dev/etherint.hh"
+#include "dev/etherpkt.hh"
+#include "sim/builder.hh"
+#include "sim/root.hh"
+
+using namespace std;
+
+EtherBus::EtherBus(const string &name, double speed, bool loop,
+ EtherDump *packet_dump)
+ : SimObject(name), ticksPerByte(speed), loopback(loop),
+ event(&mainEventQueue, this), sender(0), dump(packet_dump)
+{
+}
+
+void
+EtherBus::txDone()
+{
+ devlist_t::iterator i = devlist.begin();
+ devlist_t::iterator end = devlist.end();
+
+ DPRINTF(Ethernet, "ethernet packet received: length=%d\n", packet->length);
+ DDUMP(EthernetData, packet->data, packet->length);
+
+ while (i != end) {
+ if (loopback || *i != sender)
+ (*i)->sendPacket(packet);
+ ++i;
+ }
+
+ sender->sendDone();
+
+ if (dump)
+ dump->dump(packet);
+
+ sender = 0;
+ packet = 0;
+}
+
+void
+EtherBus::reg(EtherInt *dev)
+{ devlist.push_back(dev); }
+
+bool
+EtherBus::send(EtherInt *sndr, EthPacketPtr &pkt)
+{
+ if (busy()) {
+ DPRINTF(Ethernet, "ethernet packet not sent, bus busy\n", curTick);
+ return false;
+ }
+
+ DPRINTF(Ethernet, "ethernet packet sent: length=%d\n", pkt->length);
+ DDUMP(EthernetData, pkt->data, pkt->length);
+
+ packet = pkt;
+ sender = sndr;
+ int delay = (int)ceil(((double)pkt->length * ticksPerByte) + 1.0);
+ DPRINTF(Ethernet, "scheduling packet: delay=%d, (rate=%f)\n",
+ delay, ticksPerByte);
+ event.schedule(curTick + delay);
+
+ return true;
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherBus)
+
+ Param<bool> loopback;
+ Param<double> speed;
+ SimObjectParam<EtherDump *> packet_dump;
+
+END_DECLARE_SIM_OBJECT_PARAMS(EtherBus)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(EtherBus)
+
+ INIT_PARAM(loopback, "send the packet back to the sending interface"),
+ INIT_PARAM(speed, "bus speed in ticks per byte"),
+ INIT_PARAM(packet_dump, "object to dump network packets to")
+
+END_INIT_SIM_OBJECT_PARAMS(EtherBus)
+
+CREATE_SIM_OBJECT(EtherBus)
+{
+ return new EtherBus(getInstanceName(), speed, loopback, packet_dump);
+}
+
+REGISTER_SIM_OBJECT("EtherBus", EtherBus)
diff --git a/src/dev/etherbus.hh b/src/dev/etherbus.hh
new file mode 100644
index 000000000..4a364abd8
--- /dev/null
+++ b/src/dev/etherbus.hh
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* @file
+ * Device module for modelling an ethernet hub
+ */
+
+#ifndef __ETHERBUS_H__
+#define __ETHERBUS_H__
+
+#include "sim/eventq.hh"
+#include "dev/etherpkt.hh"
+#include "sim/sim_object.hh"
+
+class EtherDump;
+class EtherInt;
+class EtherBus : public SimObject
+{
+ protected:
+ typedef std::list<EtherInt *> devlist_t;
+ devlist_t devlist;
+ double ticksPerByte;
+ bool loopback;
+
+ protected:
+ class DoneEvent : public Event
+ {
+ protected:
+ EtherBus *bus;
+
+ public:
+ DoneEvent(EventQueue *q, EtherBus *b)
+ : Event(q), bus(b) {}
+ virtual void process() { bus->txDone(); }
+ virtual const char *description() { return "ethernet bus completion"; }
+ };
+
+ DoneEvent event;
+ EthPacketPtr packet;
+ EtherInt *sender;
+ EtherDump *dump;
+
+ public:
+ EtherBus(const std::string &name, double speed, bool loopback,
+ EtherDump *dump);
+ virtual ~EtherBus() {}
+
+ void txDone();
+ void reg(EtherInt *dev);
+ bool busy() const { return (bool)packet; }
+ bool send(EtherInt *sender, EthPacketPtr &packet);
+};
+
+#endif // __ETHERBUS_H__
diff --git a/src/dev/etherdump.cc b/src/dev/etherdump.cc
new file mode 100644
index 000000000..cb5f0b70e
--- /dev/null
+++ b/src/dev/etherdump.cc
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* @file
+ * Simple object for creating a simple pcap style packet trace
+ */
+
+#include <sys/time.h>
+
+#include <algorithm>
+#include <string>
+
+#include "base/misc.hh"
+#include "base/output.hh"
+#include "dev/etherdump.hh"
+#include "sim/builder.hh"
+#include "sim/root.hh"
+
+using std::string;
+
+EtherDump::EtherDump(const string &name, const string &file, int max)
+ : SimObject(name), stream(file.c_str()), maxlen(max)
+{
+}
+
+#define DLT_EN10MB 1 // Ethernet (10Mb)
+#define TCPDUMP_MAGIC 0xa1b2c3d4
+#define PCAP_VERSION_MAJOR 2
+#define PCAP_VERSION_MINOR 4
+
+struct pcap_file_header {
+ uint32_t magic;
+ uint16_t version_major;
+ uint16_t version_minor;
+ int32_t thiszone; // gmt to local correction
+ uint32_t sigfigs; // accuracy of timestamps
+ uint32_t snaplen; // max length saved portion of each pkt
+ uint32_t linktype; // data link type (DLT_*)
+};
+
+struct pcap_pkthdr {
+ uint32_t seconds;
+ uint32_t microseconds;
+ uint32_t caplen; // length of portion present
+ uint32_t len; // length this packet (off wire)
+};
+
+void
+EtherDump::init()
+{
+ curtime = time(NULL);
+ struct pcap_file_header hdr;
+ hdr.magic = TCPDUMP_MAGIC;
+ hdr.version_major = PCAP_VERSION_MAJOR;
+ hdr.version_minor = PCAP_VERSION_MINOR;
+
+ hdr.thiszone = -5 * 3600;
+ hdr.snaplen = 1500;
+ hdr.sigfigs = 0;
+ hdr.linktype = DLT_EN10MB;
+
+ stream.write(reinterpret_cast<char *>(&hdr), sizeof(hdr));
+
+ /*
+ * output an empty packet with the current time so that we know
+ * when the simulation began. This allows us to correlate packets
+ * to sim_cycles.
+ */
+ pcap_pkthdr pkthdr;
+ pkthdr.seconds = curtime;
+ pkthdr.microseconds = 0;
+ pkthdr.caplen = 0;
+ pkthdr.len = 0;
+ stream.write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr));
+
+ stream.flush();
+}
+
+void
+EtherDump::dumpPacket(EthPacketPtr &packet)
+{
+ pcap_pkthdr pkthdr;
+ pkthdr.seconds = curtime + (curTick / Clock::Int::s);
+ pkthdr.microseconds = (curTick / Clock::Int::us) % ULL(1000000);
+ pkthdr.caplen = std::min(packet->length, maxlen);
+ pkthdr.len = packet->length;
+ stream.write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr));
+ stream.write(reinterpret_cast<char *>(packet->data), pkthdr.caplen);
+ stream.flush();
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherDump)
+
+ Param<string> file;
+ Param<int> maxlen;
+
+END_DECLARE_SIM_OBJECT_PARAMS(EtherDump)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(EtherDump)
+
+ INIT_PARAM(file, "file to dump packets to"),
+ INIT_PARAM(maxlen, "max portion of packet data to dump")
+
+END_INIT_SIM_OBJECT_PARAMS(EtherDump)
+
+CREATE_SIM_OBJECT(EtherDump)
+{
+ return new EtherDump(getInstanceName(), simout.resolve(file), maxlen);
+}
+
+REGISTER_SIM_OBJECT("EtherDump", EtherDump)
diff --git a/src/dev/etherdump.hh b/src/dev/etherdump.hh
new file mode 100644
index 000000000..8bba073fe
--- /dev/null
+++ b/src/dev/etherdump.hh
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* @file
+ * Simple object for creating a simple pcap style packet trace
+ */
+
+#ifndef __ETHERDUMP_H__
+#define __ETHERDUMP_H__
+
+#include <fstream>
+#include "dev/etherpkt.hh"
+#include "sim/sim_object.hh"
+
+/*
+ * Simple object for creating a simple pcap style packet trace
+ */
+class EtherDump : public SimObject
+{
+ private:
+ std::ofstream stream;
+ const int maxlen;
+ void dumpPacket(EthPacketPtr &packet);
+ void init();
+
+ Tick curtime;
+
+ public:
+ EtherDump(const std::string &name, const std::string &file, int max);
+
+ inline void dump(EthPacketPtr &pkt) { dumpPacket(pkt); }
+};
+
+#endif // __ETHERDUMP_H__
diff --git a/src/dev/etherint.cc b/src/dev/etherint.cc
new file mode 100644
index 000000000..8fb047373
--- /dev/null
+++ b/src/dev/etherint.cc
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "dev/etherint.hh"
+#include "base/misc.hh"
+#include "sim/param.hh"
+#include "sim/sim_object.hh"
+
+void
+EtherInt::setPeer(EtherInt *p)
+{
+ if (peer && peer != p)
+ panic("You cannot change the peer once it is set.\n"
+ "Current peer=%s Desired peer=%s", peer->name(), p->name());
+
+ peer = p;
+}
+
+DEFINE_SIM_OBJECT_CLASS_NAME("EtherInt", EtherInt)
+
diff --git a/src/dev/etherint.hh b/src/dev/etherint.hh
new file mode 100644
index 000000000..1f641fadb
--- /dev/null
+++ b/src/dev/etherint.hh
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* @file
+ * Class representing the actual interface between two ethernet
+ * components.
+ */
+
+#ifndef __DEV_ETHERINT_HH__
+#define __DEV_ETHERINT_HH__
+
+#include <string>
+
+#include "dev/etherpkt.hh"
+#include "sim/sim_object.hh"
+
+/*
+ * Class representing the actual interface between two ethernet
+ * components. These components are intended to attach to another
+ * ethernet interface on one side and whatever device on the other.
+ */
+class EtherInt : public SimObject
+{
+ protected:
+ EtherInt *peer;
+
+ public:
+ EtherInt(const std::string &name) : SimObject(name), peer(NULL) {}
+ virtual ~EtherInt() {}
+
+ void setPeer(EtherInt *p);
+
+ void recvDone() { peer->sendDone(); }
+ virtual void sendDone() = 0;
+
+ bool sendPacket(EthPacketPtr packet)
+ { return peer ? peer->recvPacket(packet) : true; }
+ virtual bool recvPacket(EthPacketPtr packet) = 0;
+};
+
+#endif // __DEV_ETHERINT_HH__
diff --git a/src/dev/etherlink.cc b/src/dev/etherlink.cc
new file mode 100644
index 000000000..5b6531c2e
--- /dev/null
+++ b/src/dev/etherlink.cc
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* @file
+ * Device module for modelling a fixed bandwidth full duplex ethernet link
+ */
+
+#include <cmath>
+#include <deque>
+#include <string>
+#include <vector>
+
+#include "base/random.hh"
+#include "base/trace.hh"
+#include "dev/etherdump.hh"
+#include "dev/etherint.hh"
+#include "dev/etherlink.hh"
+#include "dev/etherpkt.hh"
+#include "sim/builder.hh"
+#include "sim/serialize.hh"
+#include "sim/system.hh"
+#include "sim/root.hh"
+
+using namespace std;
+
+EtherLink::EtherLink(const string &name, EtherInt *peer0, EtherInt *peer1,
+ double rate, Tick delay, Tick delayVar, EtherDump *dump)
+ : SimObject(name)
+{
+ link[0] = new Link(name + ".link0", this, 0, rate, delay, delayVar, dump);
+ link[1] = new Link(name + ".link1", this, 1, rate, delay, delayVar, dump);
+
+ interface[0] = new Interface(name + ".int0", link[0], link[1]);
+ interface[1] = new Interface(name + ".int1", link[1], link[0]);
+
+ interface[0]->setPeer(peer0);
+ peer0->setPeer(interface[0]);
+ interface[1]->setPeer(peer1);
+ peer1->setPeer(interface[1]);
+}
+
+EtherLink::~EtherLink()
+{
+ delete link[0];
+ delete link[1];
+
+ delete interface[0];
+ delete interface[1];
+}
+
+EtherLink::Interface::Interface(const string &name, Link *tx, Link *rx)
+ : EtherInt(name), txlink(tx)
+{
+ tx->setTxInt(this);
+ rx->setRxInt(this);
+}
+
+EtherLink::Link::Link(const string &name, EtherLink *p, int num,
+ double rate, Tick delay, Tick delay_var, EtherDump *d)
+ : objName(name), parent(p), number(num), txint(NULL), rxint(NULL),
+ ticksPerByte(rate), linkDelay(delay), delayVar(delay_var), dump(d),
+ doneEvent(this)
+{ }
+
+void
+EtherLink::serialize(ostream &os)
+{
+ link[0]->serialize("link0", os);
+ link[1]->serialize("link1", os);
+}
+
+void
+EtherLink::unserialize(Checkpoint *cp, const string &section)
+{
+ link[0]->unserialize("link0", cp, section);
+ link[1]->unserialize("link1", cp, section);
+}
+
+void
+EtherLink::Link::txComplete(EthPacketPtr packet)
+{
+ DPRINTF(Ethernet, "packet received: len=%d\n", packet->length);
+ DDUMP(EthernetData, packet->data, packet->length);
+ rxint->sendPacket(packet);
+}
+
+class LinkDelayEvent : public Event
+{
+ protected:
+ EtherLink::Link *link;
+ EthPacketPtr packet;
+
+ public:
+ // non-scheduling version for createForUnserialize()
+ LinkDelayEvent();
+ LinkDelayEvent(EtherLink::Link *link, EthPacketPtr pkt, Tick when);
+
+ void process();
+
+ virtual void serialize(ostream &os);
+ virtual void unserialize(Checkpoint *cp, const string &section);
+ static Serializable *createForUnserialize(Checkpoint *cp,
+ const string &section);
+};
+
+void
+EtherLink::Link::txDone()
+{
+ if (dump)
+ dump->dump(packet);
+
+ if (linkDelay > 0) {
+ DPRINTF(Ethernet, "packet delayed: delay=%d\n", linkDelay);
+ new LinkDelayEvent(this, packet, curTick + linkDelay);
+ } else {
+ txComplete(packet);
+ }
+
+ packet = 0;
+ assert(!busy());
+
+ txint->sendDone();
+}
+
+bool
+EtherLink::Link::transmit(EthPacketPtr pkt)
+{
+ if (busy()) {
+ DPRINTF(Ethernet, "packet not sent, link busy\n");
+ return false;
+ }
+
+ DPRINTF(Ethernet, "packet sent: len=%d\n", pkt->length);
+ DDUMP(EthernetData, pkt->data, pkt->length);
+
+ packet = pkt;
+ Tick delay = (Tick)ceil(((double)pkt->length * ticksPerByte) + 1.0);
+ if (delayVar != 0) {
+ Random<Tick> var;
+ delay += var.uniform(0, delayVar);
+ }
+ DPRINTF(Ethernet, "scheduling packet: delay=%d, (rate=%f)\n",
+ delay, ticksPerByte);
+ doneEvent.schedule(curTick + delay);
+
+ return true;
+}
+
+void
+EtherLink::Link::serialize(const string &base, ostream &os)
+{
+ bool packet_exists = packet;
+ paramOut(os, base + ".packet_exists", packet_exists);
+ if (packet_exists)
+ packet->serialize(base + ".packet", os);
+
+ bool event_scheduled = doneEvent.scheduled();
+ paramOut(os, base + ".event_scheduled", event_scheduled);
+ if (event_scheduled) {
+ Tick event_time = doneEvent.when();
+ paramOut(os, base + ".event_time", event_time);
+ }
+
+}
+
+void
+EtherLink::Link::unserialize(const string &base, Checkpoint *cp,
+ const string &section)
+{
+ bool packet_exists;
+ paramIn(cp, section, base + ".packet_exists", packet_exists);
+ if (packet_exists) {
+ packet = new EthPacketData(16384);
+ packet->unserialize(base + ".packet", cp, section);
+ }
+
+ bool event_scheduled;
+ paramIn(cp, section, base + ".event_scheduled", event_scheduled);
+ if (event_scheduled) {
+ Tick event_time;
+ paramIn(cp, section, base + ".event_time", event_time);
+ doneEvent.schedule(event_time);
+ }
+}
+
+LinkDelayEvent::LinkDelayEvent()
+ : Event(&mainEventQueue), link(NULL)
+{
+ setFlags(AutoSerialize);
+ setFlags(AutoDelete);
+}
+
+LinkDelayEvent::LinkDelayEvent(EtherLink::Link *l, EthPacketPtr p, Tick when)
+ : Event(&mainEventQueue), link(l), packet(p)
+{
+ setFlags(AutoSerialize);
+ setFlags(AutoDelete);
+ schedule(when);
+}
+
+void
+LinkDelayEvent::process()
+{
+ link->txComplete(packet);
+}
+
+void
+LinkDelayEvent::serialize(ostream &os)
+{
+ paramOut(os, "type", string("LinkDelayEvent"));
+ Event::serialize(os);
+
+ EtherLink *parent = link->parent;
+ bool number = link->number;
+ SERIALIZE_OBJPTR(parent);
+ SERIALIZE_SCALAR(number);
+
+ packet->serialize("packet", os);
+}
+
+
+void
+LinkDelayEvent::unserialize(Checkpoint *cp, const string &section)
+{
+ Event::unserialize(cp, section);
+
+ EtherLink *parent;
+ bool number;
+ UNSERIALIZE_OBJPTR(parent);
+ UNSERIALIZE_SCALAR(number);
+
+ link = parent->link[number];
+
+ packet = new EthPacketData(16384);
+ packet->unserialize("packet", cp, section);
+}
+
+
+Serializable *
+LinkDelayEvent::createForUnserialize(Checkpoint *cp, const string &section)
+{
+ return new LinkDelayEvent();
+}
+
+REGISTER_SERIALIZEABLE("LinkDelayEvent", LinkDelayEvent)
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherLink)
+
+ SimObjectParam<EtherInt *> int1;
+ SimObjectParam<EtherInt *> int2;
+ Param<double> speed;
+ Param<Tick> delay;
+ Param<Tick> delay_var;
+ SimObjectParam<EtherDump *> dump;
+
+END_DECLARE_SIM_OBJECT_PARAMS(EtherLink)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(EtherLink)
+
+ INIT_PARAM(int1, "interface 1"),
+ INIT_PARAM(int2, "interface 2"),
+ INIT_PARAM(speed, "link speed in bits per second"),
+ INIT_PARAM(delay, "transmit delay of packets in us"),
+ INIT_PARAM(delay_var, "Difference in amount of time to traverse wire"),
+ INIT_PARAM(dump, "object to dump network packets to")
+
+END_INIT_SIM_OBJECT_PARAMS(EtherLink)
+
+CREATE_SIM_OBJECT(EtherLink)
+{
+ return new EtherLink(getInstanceName(), int1, int2, speed, delay, delay_var,
+ dump);
+}
+
+REGISTER_SIM_OBJECT("EtherLink", EtherLink)
diff --git a/src/dev/etherlink.hh b/src/dev/etherlink.hh
new file mode 100644
index 000000000..570444e1b
--- /dev/null
+++ b/src/dev/etherlink.hh
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* @file
+ * Device module for modelling a fixed bandwidth full duplex ethernet link
+ */
+
+#ifndef __DEV_ETHERLINK_HH__
+#define __DEV_ETHERLINK_HH__
+
+#include "dev/etherint.hh"
+#include "dev/etherpkt.hh"
+#include "sim/eventq.hh"
+#include "sim/host.hh"
+#include "sim/sim_object.hh"
+
+class EtherDump;
+class Checkpoint;
+/*
+ * Model for a fixed bandwidth full duplex ethernet link
+ */
+class EtherLink : public SimObject
+{
+ protected:
+ class Interface;
+
+ friend class LinkDelayEvent;
+ /*
+ * Model for a single uni-directional link
+ */
+ class Link
+ {
+ protected:
+ std::string objName;
+
+ EtherLink *parent;
+ int number;
+
+ Interface *txint;
+ Interface *rxint;
+
+ double ticksPerByte;
+ Tick linkDelay;
+ Tick delayVar;
+ EtherDump *dump;
+
+ protected:
+ /*
+ * Transfer is complete
+ */
+ EthPacketPtr packet;
+ void txDone();
+ typedef EventWrapper<Link, &Link::txDone> DoneEvent;
+ friend void DoneEvent::process();
+ DoneEvent doneEvent;
+
+ friend class LinkDelayEvent;
+ void txComplete(EthPacketPtr packet);
+
+ public:
+ Link(const std::string &name, EtherLink *p, int num,
+ double rate, Tick delay, Tick delay_var, EtherDump *dump);
+ ~Link() {}
+
+ const std::string name() const { return objName; }
+
+ bool busy() const { return (bool)packet; }
+ bool transmit(EthPacketPtr packet);
+
+ void setTxInt(Interface *i) { assert(!txint); txint = i; }
+ void setRxInt(Interface *i) { assert(!rxint); rxint = i; }
+
+ void serialize(const std::string &base, std::ostream &os);
+ void unserialize(const std::string &base, Checkpoint *cp,
+ const std::string &section);
+ };
+
+ /*
+ * Interface at each end of the link
+ */
+ class Interface : public EtherInt
+ {
+ private:
+ Link *txlink;
+
+ public:
+ Interface(const std::string &name, Link *txlink, Link *rxlink);
+ bool recvPacket(EthPacketPtr packet) { return txlink->transmit(packet); }
+ void sendDone() { peer->sendDone(); }
+ };
+
+ Link *link[2];
+ EtherInt *interface[2];
+
+ public:
+ EtherLink(const std::string &name, EtherInt *peer0, EtherInt *peer1,
+ double rate, Tick delay, Tick delayVar, EtherDump *dump);
+ virtual ~EtherLink();
+
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+
+};
+
+#endif // __ETHERLINK_HH__
diff --git a/src/dev/etherpkt.cc b/src/dev/etherpkt.cc
new file mode 100644
index 000000000..85e18e981
--- /dev/null
+++ b/src/dev/etherpkt.cc
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <iostream>
+
+#include "base/misc.hh"
+#include "dev/etherpkt.hh"
+#include "sim/serialize.hh"
+
+using namespace std;
+
+void
+EthPacketData::serialize(const string &base, ostream &os)
+{
+ paramOut(os, base + ".length", length);
+ paramOut(os, base + ".slack", slack);
+ arrayParamOut(os, base + ".data", data, length);
+}
+
+void
+EthPacketData::unserialize(const string &base, Checkpoint *cp,
+ const string &section)
+{
+ paramIn(cp, section, base + ".length", length);
+ paramIn(cp, section, base + ".slack", slack);
+ if (length)
+ arrayParamIn(cp, section, base + ".data", data, length);
+}
diff --git a/src/dev/etherpkt.hh b/src/dev/etherpkt.hh
new file mode 100644
index 000000000..01741b3d5
--- /dev/null
+++ b/src/dev/etherpkt.hh
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* @file
+ * Reference counted class containing ethernet packet data
+ */
+
+#ifndef __ETHERPKT_HH__
+#define __ETHERPKT_HH__
+
+#include <iosfwd>
+#include <memory>
+#include <assert.h>
+
+#include "base/refcnt.hh"
+#include "sim/host.hh"
+
+/*
+ * Reference counted class containing ethernet packet data
+ */
+class Checkpoint;
+class EthPacketData : public RefCounted
+{
+ public:
+ /*
+ * Pointer to packet data will be deleted
+ */
+ uint8_t *data;
+
+ /*
+ * Length of the current packet
+ */
+ int length;
+
+ /*
+ * Extra space taken up by the packet in whatever data structure
+ * it is in.
+ *
+ * NOTE: This can only be use by *one* data structure at a time!
+ */
+ int slack;
+
+ public:
+ EthPacketData() : data(NULL), length(0), slack(0) { }
+ explicit EthPacketData(size_t size)
+ : data(new uint8_t[size]), length(0), slack(0) { }
+ EthPacketData(std::auto_ptr<uint8_t> d, int l, int s = 0)
+ : data(d.release()), length(l), slack(s) { }
+ ~EthPacketData() { if (data) delete [] data; }
+
+ public:
+ void serialize(const std::string &base, std::ostream &os);
+ void unserialize(const std::string &base, Checkpoint *cp,
+ const std::string &section);
+};
+
+typedef RefCountingPtr<EthPacketData> EthPacketPtr;
+
+#endif // __ETHERPKT_HH__
diff --git a/src/dev/ethertap.cc b/src/dev/ethertap.cc
new file mode 100644
index 000000000..b5abb1d62
--- /dev/null
+++ b/src/dev/ethertap.cc
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* @file
+ * Interface to connect a simulated ethernet device to the real world
+ */
+
+#if defined(__OpenBSD__) || defined(__APPLE__)
+#include <sys/param.h>
+#endif
+#include <netinet/in.h>
+
+#include <unistd.h>
+
+#include <deque>
+#include <string>
+
+#include "base/misc.hh"
+#include "base/pollevent.hh"
+#include "base/socket.hh"
+#include "base/trace.hh"
+#include "dev/etherdump.hh"
+#include "dev/etherint.hh"
+#include "dev/etherpkt.hh"
+#include "dev/ethertap.hh"
+#include "sim/builder.hh"
+
+using namespace std;
+
+/**
+ */
+class TapListener
+{
+ protected:
+ /**
+ */
+ class Event : public PollEvent
+ {
+ protected:
+ TapListener *listener;
+
+ public:
+ Event(TapListener *l, int fd, int e)
+ : PollEvent(fd, e), listener(l) {}
+
+ virtual void process(int revent) { listener->accept(); }
+ };
+
+ friend class Event;
+ Event *event;
+
+ protected:
+ ListenSocket listener;
+ EtherTap *tap;
+ int port;
+
+ public:
+ TapListener(EtherTap *t, int p)
+ : event(NULL), tap(t), port(p) {}
+ ~TapListener() { if (event) delete event; }
+
+ void accept();
+ void listen();
+};
+
+void
+TapListener::listen()
+{
+ while (!listener.listen(port, true)) {
+ DPRINTF(Ethernet, "TapListener(listen): Can't bind port %d\n", port);
+ port++;
+ }
+
+ ccprintf(cerr, "Listening for tap connection on port %d\n", port);
+ event = new Event(this, listener.getfd(), POLLIN|POLLERR);
+ pollQueue.schedule(event);
+}
+
+void
+TapListener::accept()
+{
+ if (!listener.islistening())
+ panic("TapListener(accept): cannot accept if we're not listening!");
+
+ int sfd = listener.accept(true);
+ if (sfd != -1)
+ tap->attach(sfd);
+}
+
+/**
+ */
+class TapEvent : public PollEvent
+{
+ protected:
+ EtherTap *tap;
+
+ public:
+ TapEvent(EtherTap *_tap, int fd, int e)
+ : PollEvent(fd, e), tap(_tap) {}
+ virtual void process(int revent) { tap->process(revent); }
+};
+
+EtherTap::EtherTap(const string &name, EtherDump *d, int port, int bufsz)
+ : EtherInt(name), event(NULL), socket(-1), buflen(bufsz), dump(d),
+ txEvent(this)
+{
+ buffer = new char[buflen];
+ listener = new TapListener(this, port);
+ listener->listen();
+}
+
+EtherTap::~EtherTap()
+{
+ if (event)
+ delete event;
+ if (buffer)
+ delete [] buffer;
+
+ delete listener;
+}
+
+void
+EtherTap::attach(int fd)
+{
+ if (socket != -1)
+ close(fd);
+
+ buffer_offset = 0;
+ data_len = 0;
+ socket = fd;
+ DPRINTF(Ethernet, "EtherTap attached\n");
+ event = new TapEvent(this, socket, POLLIN|POLLERR);
+ pollQueue.schedule(event);
+}
+
+void
+EtherTap::detach()
+{
+ DPRINTF(Ethernet, "EtherTap detached\n");
+ delete event;
+ event = 0;
+ close(socket);
+ socket = -1;
+}
+
+bool
+EtherTap::recvPacket(EthPacketPtr packet)
+{
+ if (dump)
+ dump->dump(packet);
+
+ DPRINTF(Ethernet, "EtherTap output len=%d\n", packet->length);
+ DDUMP(EthernetData, packet->data, packet->length);
+ u_int32_t len = htonl(packet->length);
+ write(socket, &len, sizeof(len));
+ write(socket, packet->data, packet->length);
+
+ recvDone();
+
+ return true;
+}
+
+void
+EtherTap::sendDone()
+{}
+
+void
+EtherTap::process(int revent)
+{
+ if (revent & POLLERR) {
+ detach();
+ return;
+ }
+
+ char *data = buffer + sizeof(u_int32_t);
+ if (!(revent & POLLIN))
+ return;
+
+ if (buffer_offset < data_len + sizeof(u_int32_t)) {
+ int len = read(socket, buffer + buffer_offset, buflen - buffer_offset);
+ if (len == 0) {
+ detach();
+ return;
+ }
+
+ buffer_offset += len;
+
+ if (data_len == 0)
+ data_len = ntohl(*(u_int32_t *)buffer);
+
+ DPRINTF(Ethernet, "Received data from peer: len=%d buffer_offset=%d "
+ "data_len=%d\n", len, buffer_offset, data_len);
+ }
+
+ while (data_len != 0 && buffer_offset >= data_len + sizeof(u_int32_t)) {
+ EthPacketPtr packet;
+ packet = new EthPacketData(data_len);
+ packet->length = data_len;
+ memcpy(packet->data, data, data_len);
+
+ buffer_offset -= data_len + sizeof(u_int32_t);
+ assert(buffer_offset >= 0);
+ if (buffer_offset > 0) {
+ memmove(buffer, data + data_len, buffer_offset);
+ data_len = ntohl(*(u_int32_t *)buffer);
+ } else
+ data_len = 0;
+
+ DPRINTF(Ethernet, "EtherTap input len=%d\n", packet->length);
+ DDUMP(EthernetData, packet->data, packet->length);
+ if (!sendPacket(packet)) {
+ DPRINTF(Ethernet, "bus busy...buffer for retransmission\n");
+ packetBuffer.push(packet);
+ if (!txEvent.scheduled())
+ txEvent.schedule(curTick + retryTime);
+ } else if (dump) {
+ dump->dump(packet);
+ }
+ }
+}
+
+void
+EtherTap::retransmit()
+{
+ if (packetBuffer.empty())
+ return;
+
+ EthPacketPtr packet = packetBuffer.front();
+ if (sendPacket(packet)) {
+ if (dump)
+ dump->dump(packet);
+ DPRINTF(Ethernet, "EtherTap retransmit\n");
+ packetBuffer.front() = NULL;
+ packetBuffer.pop();
+ }
+
+ if (!packetBuffer.empty() && !txEvent.scheduled())
+ txEvent.schedule(curTick + retryTime);
+}
+
+//=====================================================================
+
+void
+EtherTap::serialize(ostream &os)
+{
+ SERIALIZE_SCALAR(socket);
+ SERIALIZE_SCALAR(buflen);
+ uint8_t *buffer = (uint8_t *)this->buffer;
+ SERIALIZE_ARRAY(buffer, buflen);
+ SERIALIZE_SCALAR(buffer_offset);
+ SERIALIZE_SCALAR(data_len);
+
+ bool tapevent_present = false;
+ if (event) {
+ tapevent_present = true;
+ SERIALIZE_SCALAR(tapevent_present);
+ event->serialize(os);
+ }
+ else {
+ SERIALIZE_SCALAR(tapevent_present);
+ }
+}
+
+void
+EtherTap::unserialize(Checkpoint *cp, const std::string &section)
+{
+ UNSERIALIZE_SCALAR(socket);
+ UNSERIALIZE_SCALAR(buflen);
+ uint8_t *buffer = (uint8_t *)this->buffer;
+ UNSERIALIZE_ARRAY(buffer, buflen);
+ UNSERIALIZE_SCALAR(buffer_offset);
+ UNSERIALIZE_SCALAR(data_len);
+
+ bool tapevent_present;
+ UNSERIALIZE_SCALAR(tapevent_present);
+ if (tapevent_present) {
+ event = new TapEvent(this, socket, POLLIN|POLLERR);
+
+ event->unserialize(cp,section);
+
+ if (event->queued()) {
+ pollQueue.schedule(event);
+ }
+ }
+}
+
+//=====================================================================
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherTap)
+
+ SimObjectParam<EtherInt *> peer;
+ SimObjectParam<EtherDump *> dump;
+ Param<unsigned> port;
+ Param<unsigned> bufsz;
+
+END_DECLARE_SIM_OBJECT_PARAMS(EtherTap)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(EtherTap)
+
+ INIT_PARAM_DFLT(peer, "peer interface", NULL),
+ INIT_PARAM_DFLT(dump, "object to dump network packets to", NULL),
+ INIT_PARAM_DFLT(port, "tap port", 3500),
+ INIT_PARAM_DFLT(bufsz, "tap buffer size", 10000)
+
+END_INIT_SIM_OBJECT_PARAMS(EtherTap)
+
+
+CREATE_SIM_OBJECT(EtherTap)
+{
+ EtherTap *tap = new EtherTap(getInstanceName(), dump, port, bufsz);
+
+ if (peer) {
+ tap->setPeer(peer);
+ peer->setPeer(tap);
+ }
+
+ return tap;
+}
+
+REGISTER_SIM_OBJECT("EtherTap", EtherTap)
diff --git a/src/dev/ethertap.hh b/src/dev/ethertap.hh
new file mode 100644
index 000000000..40ce6af0b
--- /dev/null
+++ b/src/dev/ethertap.hh
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* @file
+ * Interface to connect a simulated ethernet device to the real world
+ */
+
+#ifndef __ETHERTAP_HH__
+#define __ETHERTAP_HH__
+
+#include <queue>
+#include <string>
+
+#include "dev/etherint.hh"
+#include "dev/etherpkt.hh"
+#include "sim/eventq.hh"
+#include "base/pollevent.hh"
+#include "sim/sim_object.hh"
+
+class TapEvent;
+class TapListener;
+
+/*
+ * Interface to connect a simulated ethernet device to the real world
+ */
+class EtherTap : public EtherInt
+{
+ protected:
+ friend class TapEvent;
+ TapEvent *event;
+
+ protected:
+ friend class TapListener;
+ TapListener *listener;
+ int socket;
+ char *buffer;
+ int buflen;
+ int32_t buffer_offset;
+ int32_t data_len;
+
+ EtherDump *dump;
+
+ void attach(int fd);
+ void detach();
+
+ protected:
+ std::string device;
+ std::queue<EthPacketPtr> packetBuffer;
+
+ void process(int revent);
+ void enqueue(EthPacketData *packet);
+ void retransmit();
+
+ /*
+ */
+ class TxEvent : public Event
+ {
+ protected:
+ EtherTap *tap;
+
+ public:
+ TxEvent(EtherTap *_tap)
+ : Event(&mainEventQueue), tap(_tap) {}
+ void process() { tap->retransmit(); }
+ virtual const char *description() { return "retransmit event"; }
+ };
+
+ friend class TxEvent;
+ TxEvent txEvent;
+
+ public:
+ EtherTap(const std::string &name, EtherDump *dump, int port, int bufsz);
+ virtual ~EtherTap();
+
+ virtual bool recvPacket(EthPacketPtr packet);
+ virtual void sendDone();
+
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+};
+
+#endif // __ETHERTAP_HH__
diff --git a/src/dev/ide_atareg.h b/src/dev/ide_atareg.h
new file mode 100644
index 000000000..5320529c8
--- /dev/null
+++ b/src/dev/ide_atareg.h
@@ -0,0 +1,276 @@
+/* $OpenBSD: atareg.h,v 1.12 2004/09/24 07:15:22 grange Exp $ */
+/* $NetBSD: atareg.h,v 1.5 1999/01/18 20:06:24 bouyer Exp $ */
+
+/*
+ * Copyright (c) 1998, 2001 Manuel Bouyer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Manuel Bouyer.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _DEV_ATA_ATAREG_H_
+#define _DEV_ATA_ATAREG_H_
+
+#if defined(linux)
+#include <endian.h>
+#else
+#include <machine/endian.h>
+#endif
+
+#define ATA_BYTE_ORDER LITTLE_ENDIAN
+
+/*
+ * Drive parameter structure for ATA/ATAPI.
+ * Bit fields: WDC_* : common to ATA/ATAPI
+ * ATA_* : ATA only
+ * ATAPI_* : ATAPI only.
+ */
+struct ataparams {
+ /* drive info */
+ uint16_t atap_config; /* 0: general configuration */
+#define WDC_CFG_ATAPI_MASK 0xc000
+#define WDC_CFG_ATAPI 0x8000
+#define ATA_CFG_REMOVABLE 0x0080
+#define ATA_CFG_FIXED 0x0040
+#define ATAPI_CFG_TYPE_MASK 0x1f00
+#define ATAPI_CFG_TYPE(x) (((x) & ATAPI_CFG_TYPE_MASK) >> 8)
+#define ATAPI_CFG_TYPE_DIRECT 0x00
+#define ATAPI_CFG_TYPE_SEQUENTIAL 0x01
+#define ATAPI_CFG_TYPE_CDROM 0x05
+#define ATAPI_CFG_TYPE_OPTICAL 0x07
+#define ATAPI_CFG_TYPE_NODEVICE 0x1F
+#define ATAPI_CFG_REMOV 0x0080
+#define ATAPI_CFG_DRQ_MASK 0x0060
+#define ATAPI_CFG_STD_DRQ 0x0000
+#define ATAPI_CFG_IRQ_DRQ 0x0020
+#define ATAPI_CFG_ACCEL_DRQ 0x0040
+#define ATAPI_CFG_CMD_MASK 0x0003
+#define ATAPI_CFG_CMD_12 0x0000
+#define ATAPI_CFG_CMD_16 0x0001
+/* words 1-9 are ATA only */
+ uint16_t atap_cylinders; /* 1: # of non-removable cylinders */
+ uint16_t __reserved1;
+ uint16_t atap_heads; /* 3: # of heads */
+ uint16_t __retired1[2]; /* 4-5: # of unform. bytes/track */
+ uint16_t atap_sectors; /* 6: # of sectors */
+ uint16_t __retired2[3];
+
+ uint8_t atap_serial[20]; /* 10-19: serial number */
+ uint16_t __retired3[2];
+ uint16_t __obsolete1;
+ uint8_t atap_revision[8]; /* 23-26: firmware revision */
+ uint8_t atap_model[40]; /* 27-46: model number */
+ uint16_t atap_multi; /* 47: maximum sectors per irq (ATA) */
+ uint16_t __reserved2;
+ uint8_t atap_vendor; /* 49: vendor */
+ uint8_t atap_capabilities1; /* 49: capability flags */
+#define WDC_CAP_IORDY 0x0800
+#define WDC_CAP_IORDY_DSBL 0x0400
+#define WDC_CAP_LBA 0x0200
+#define WDC_CAP_DMA 0x0100
+#define ATA_CAP_STBY 0x2000
+#define ATAPI_CAP_INTERL_DMA 0x8000
+#define ATAPI_CAP_CMD_QUEUE 0x4000
+#define ATAPI_CAP_OVERLP 0x2000
+#define ATAPI_CAP_ATA_RST 0x1000
+ uint16_t atap_capabilities2; /* 50: capability flags (ATA) */
+#if ATA_BYTE_ORDER == LITTLE_ENDIAN
+ uint8_t __junk2;
+ uint8_t atap_oldpiotiming; /* 51: old PIO timing mode */
+ uint8_t __junk3;
+ uint8_t atap_olddmatiming; /* 52: old DMA timing mode (ATA) */
+#else
+ uint8_t atap_oldpiotiming; /* 51: old PIO timing mode */
+ uint8_t __junk2;
+ uint8_t atap_olddmatiming; /* 52: old DMA timing mode (ATA) */
+ uint8_t __junk3;
+#endif
+ uint16_t atap_extensions; /* 53: extensions supported */
+#define WDC_EXT_UDMA_MODES 0x0004
+#define WDC_EXT_MODES 0x0002
+#define WDC_EXT_GEOM 0x0001
+/* words 54-62 are ATA only */
+ uint16_t atap_curcylinders; /* 54: current logical cylinders */
+ uint16_t atap_curheads; /* 55: current logical heads */
+ uint16_t atap_cursectors; /* 56: current logical sectors/tracks */
+ uint16_t atap_curcapacity[2]; /* 57-58: current capacity */
+ uint8_t atap_curmulti; /* 59: current multi-sector setting */
+ uint8_t atap_curmulti_valid; /* 59: current multi-sector setting */
+#define WDC_MULTI_VALID 0x0100
+#define WDC_MULTI_MASK 0x00ff
+ uint32_t atap_capacity; /* 60-61: total capacity (LBA only) */
+ uint16_t __retired4;
+#if ATA_BYTE_ORDER == LITTLE_ENDIAN
+ uint8_t atap_dmamode_supp; /* 63: multiword DMA mode supported */
+ uint8_t atap_dmamode_act; /* multiword DMA mode active */
+ uint8_t atap_piomode_supp; /* 64: PIO mode supported */
+ uint8_t __junk4;
+#else
+ uint8_t atap_dmamode_act; /* multiword DMA mode active */
+ uint8_t atap_dmamode_supp; /* 63: multiword DMA mode supported */
+ uint8_t __junk4;
+ uint8_t atap_piomode_supp; /* 64: PIO mode supported */
+#endif
+ uint16_t atap_dmatiming_mimi; /* 65: minimum DMA cycle time */
+ uint16_t atap_dmatiming_recom; /* 66: recommended DMA cycle time */
+ uint16_t atap_piotiming; /* 67: mini PIO cycle time without FC */
+ uint16_t atap_piotiming_iordy; /* 68: mini PIO cycle time with IORDY FC */
+ uint16_t __reserved3[2];
+/* words 71-72 are ATAPI only */
+ uint16_t atap_pkt_br; /* 71: time (ns) to bus release */
+ uint16_t atap_pkt_bsyclr; /* 72: tme to clear BSY after service */
+ uint16_t __reserved4[2];
+ uint16_t atap_queuedepth; /* 75: */
+#define WDC_QUEUE_DEPTH_MASK 0x1f
+ uint16_t atap_sata_caps; /* 76: SATA capabilities */
+#define SATA_SIGNAL_GEN1 0x0002 /* SATA Gen-1 signaling speed */
+#define SATA_SIGNAL_GEN2 0x0004 /* SATA Gen-2 signaling speed */
+#define SATA_NATIVE_CMDQ 0x0100 /* native command queuing */
+#define SATA_HOST_PWR_MGMT 0x0200 /* power management (host) */
+ uint16_t atap_sata_reserved; /* 77: reserved */
+ uint16_t atap_sata_features_supp;/* 78: SATA features supported */
+#define SATA_NONZERO_OFFSETS 0x0002 /* non-zero buffer offsets */
+#define SATA_DMA_SETUP_AUTO 0x0004 /* DMA setup auto-activate */
+#define SATA_DRIVE_PWR_MGMT 0x0008 /* power management (device) */
+ uint16_t atap_sata_features_en; /* 79: SATA features enabled */
+ uint16_t atap_ata_major; /* 80: Major version number */
+#define WDC_VER_ATA1 0x0002
+#define WDC_VER_ATA2 0x0004
+#define WDC_VER_ATA3 0x0008
+#define WDC_VER_ATA4 0x0010
+#define WDC_VER_ATA5 0x0020
+#define WDC_VER_ATA6 0x0040
+#define WDC_VER_ATA7 0x0080
+#define WDC_VER_ATA8 0x0100
+#define WDC_VER_ATA9 0x0200
+#define WDC_VER_ATA10 0x0400
+#define WDC_VER_ATA11 0x0800
+#define WDC_VER_ATA12 0x1000
+#define WDC_VER_ATA13 0x2000
+#define WDC_VER_ATA14 0x4000
+ uint16_t atap_ata_minor; /* 81: Minor version number */
+ uint16_t atap_cmd_set1; /* 82: command set supported */
+#define WDC_CMD1_NOP 0x4000
+#define WDC_CMD1_RB 0x2000
+#define WDC_CMD1_WB 0x1000
+#define WDC_CMD1_HPA 0x0400
+#define WDC_CMD1_DVRST 0x0200
+#define WDC_CMD1_SRV 0x0100
+#define WDC_CMD1_RLSE 0x0080
+#define WDC_CMD1_AHEAD 0x0040
+#define WDC_CMD1_CACHE 0x0020
+#define WDC_CMD1_PKT 0x0010
+#define WDC_CMD1_PM 0x0008
+#define WDC_CMD1_REMOV 0x0004
+#define WDC_CMD1_SEC 0x0002
+#define WDC_CMD1_SMART 0x0001
+ uint16_t atap_cmd_set2; /* 83: command set supported */
+#define ATAPI_CMD2_FCE 0x2000 /* Flush Cache Ext supported */
+#define ATAPI_CMD2_FC 0x1000 /* Flush Cache supported */
+#define ATAPI_CMD2_DCO 0x0800 /* Device Configuration Overlay supported */
+#define ATAPI_CMD2_48AD 0x0400 /* 48bit address supported */
+#define ATAPI_CMD2_AAM 0x0200 /* Automatic Acoustic Management supported */
+#define ATAPI_CMD2_SM 0x0100 /* Set Max security extension supported */
+#define ATAPI_CMD2_SF 0x0040 /* Set Features subcommand required */
+#define ATAPI_CMD2_PUIS 0x0020 /* Power up in standby supported */
+#define WDC_CMD2_RMSN 0x0010
+#define ATA_CMD2_APM 0x0008
+#define ATA_CMD2_CFA 0x0004
+#define ATA_CMD2_RWQ 0x0002
+#define WDC_CMD2_DM 0x0001 /* Download Microcode supported */
+ uint16_t atap_cmd_ext; /* 84: command/features supp. ext. */
+#define ATAPI_CMDE_MSER 0x0004 /* Media serial number supported */
+#define ATAPI_CMDE_TEST 0x0002 /* SMART self-test supported */
+#define ATAPI_CMDE_SLOG 0x0001 /* SMART error logging supported */
+ uint16_t atap_cmd1_en; /* 85: cmd/features enabled */
+/* bits are the same as atap_cmd_set1 */
+ uint16_t atap_cmd2_en; /* 86: cmd/features enabled */
+/* bits are the same as atap_cmd_set2 */
+ uint16_t atap_cmd_def; /* 87: cmd/features default */
+/* bits are NOT the same as atap_cmd_ext */
+#if ATA_BYTE_ORDER == LITTLE_ENDIAN
+ uint8_t atap_udmamode_supp; /* 88: Ultra-DMA mode supported */
+ uint8_t atap_udmamode_act; /* Ultra-DMA mode active */
+#else
+ uint8_t atap_udmamode_act; /* Ultra-DMA mode active */
+ uint8_t atap_udmamode_supp; /* 88: Ultra-DMA mode supported */
+#endif
+/* 89-92 are ATA-only */
+ uint16_t atap_seu_time; /* 89: Sec. Erase Unit compl. time */
+ uint16_t atap_eseu_time; /* 90: Enhanced SEU compl. time */
+ uint16_t atap_apm_val; /* 91: current APM value */
+ uint16_t atap_mpasswd_rev; /* 92: Master Password revision */
+ uint16_t atap_hwreset_res; /* 93: Hardware reset value */
+#define ATA_HWRES_CBLID 0x2000 /* CBLID above Vih */
+#define ATA_HWRES_D1_PDIAG 0x0800 /* Device 1 PDIAG detect OK */
+#define ATA_HWRES_D1_CSEL 0x0400 /* Device 1 used CSEL for address */
+#define ATA_HWRES_D1_JUMP 0x0200 /* Device 1 jumpered to address */
+#define ATA_HWRES_D0_SEL 0x0040 /* Device 0 responds when Dev 1 selected */
+#define ATA_HWRES_D0_DASP 0x0020 /* Device 0 DASP detect OK */
+#define ATA_HWRES_D0_PDIAG 0x0010 /* Device 0 PDIAG detect OK */
+#define ATA_HWRES_D0_DIAG 0x0008 /* Device 0 diag OK */
+#define ATA_HWRES_D0_CSEL 0x0004 /* Device 0 used CSEL for address */
+#define ATA_HWRES_D0_JUMP 0x0002 /* Device 0 jumpered to address */
+#if ATA_BYTE_ORDER == LITTLE_ENDIAN
+ uint8_t atap_acoustic_val; /* 94: Current acoustic level */
+ uint8_t atap_acoustic_def; /* recommended level */
+#else
+ uint8_t atap_acoustic_def; /* recommended level */
+ uint8_t atap_acoustic_val; /* 94: Current acoustic level */
+#endif
+ uint16_t __reserved6[5]; /* 95-99: reserved */
+ uint16_t atap_max_lba[4]; /* 100-103: Max. user LBA add */
+ uint16_t __reserved7[23]; /* 104-126: reserved */
+ uint16_t atap_rmsn_supp; /* 127: remov. media status notif. */
+#define WDC_RMSN_SUPP_MASK 0x0003
+#define WDC_RMSN_SUPP 0x0001
+ uint16_t atap_sec_st; /* 128: security status */
+#define WDC_SEC_LEV_MAX 0x0100
+#define WDC_SEC_ESE_SUPP 0x0020
+#define WDC_SEC_EXP 0x0010
+#define WDC_SEC_FROZEN 0x0008
+#define WDC_SEC_LOCKED 0x0004
+#define WDC_SEC_EN 0x0002
+#define WDC_SEC_SUPP 0x0001
+ uint16_t __reserved8[31]; /* 129-159: vendor specific */
+ uint16_t atap_cfa_power; /* 160: CFA powermode */
+#define ATAPI_CFA_MAX_MASK 0x0FFF
+#define ATAPI_CFA_MODE1_DIS 0x1000 /* CFA Mode 1 Disabled */
+#define ATAPI_CFA_MODE1_REQ 0x2000 /* CFA Mode 1 Required */
+#define ATAPI_CFA_WORD160 0x8000 /* Word 160 supported */
+ uint16_t __reserved9[15]; /* 161-175: reserved for CFA */
+ uint8_t atap_media_serial[60]; /* 176-205: media serial number */
+ uint16_t __reserved10[49]; /* 206-254: reserved */
+#if ATA_BYTE_ORDER == LITTLE_ENDIAN
+ uint8_t atap_signature; /* 255: Signature */
+ uint8_t atap_checksum; /* Checksum */
+#else
+ uint8_t atap_checksum; /* Checksum */
+ uint8_t atap_signature; /* 255: Signature */
+#endif
+};
+
+#undef ATA_BYTE_ORDER
+#endif /* !_DEV_ATA_ATAREG_H_ */
diff --git a/src/dev/ide_ctrl.cc b/src/dev/ide_ctrl.cc
new file mode 100644
index 000000000..cedd5c53e
--- /dev/null
+++ b/src/dev/ide_ctrl.cc
@@ -0,0 +1,814 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <cstddef>
+#include <cstdlib>
+#include <string>
+#include <vector>
+
+#include "base/trace.hh"
+#include "cpu/intr_control.hh"
+#include "dev/ide_ctrl.hh"
+#include "dev/ide_disk.hh"
+#include "dev/pciconfigall.hh"
+#include "dev/pcireg.h"
+#include "dev/platform.hh"
+#include "mem/packet.hh"
+#include "sim/builder.hh"
+#include "sim/sim_object.hh"
+#include "sim/byteswap.hh"
+
+using namespace std;
+
+////
+// Initialization and destruction
+////
+
+IdeController::IdeController(Params *p)
+ : PciDev(p)
+{
+ // initialize the PIO interface addresses
+ pri_cmd_addr = 0;
+ pri_cmd_size = BARSize[0];
+
+ pri_ctrl_addr = 0;
+ pri_ctrl_size = BARSize[1];
+
+ sec_cmd_addr = 0;
+ sec_cmd_size = BARSize[2];
+
+ sec_ctrl_addr = 0;
+ sec_ctrl_size = BARSize[3];
+
+ // initialize the bus master interface (BMI) address to be configured
+ // via PCI
+ bmi_addr = 0;
+ bmi_size = BARSize[4];
+
+ // zero out all of the registers
+ memset(bmi_regs.data, 0, sizeof(bmi_regs));
+ memset(config_regs.data, 0, sizeof(config_regs.data));
+
+ // setup initial values
+ // enable both channels
+ config_regs.idetim0 = htole((uint16_t)IDETIM_DECODE_EN);
+ config_regs.idetim1 = htole((uint16_t)IDETIM_DECODE_EN);
+ bmi_regs.bmis0 = DMA1CAP | DMA0CAP;
+ bmi_regs.bmis1 = DMA1CAP | DMA0CAP;
+
+ // reset all internal variables
+ io_enabled = false;
+ bm_enabled = false;
+ memset(cmd_in_progress, 0, sizeof(cmd_in_progress));
+
+ // setup the disks attached to controller
+ memset(disks, 0, sizeof(disks));
+ dev[0] = 0;
+ dev[1] = 0;
+
+ if (params()->disks.size() > 3)
+ panic("IDE controllers support a maximum of 4 devices attached!\n");
+
+ for (int i = 0; i < params()->disks.size(); i++) {
+ disks[i] = params()->disks[i];
+ disks[i]->setController(this);
+ }
+}
+
+IdeController::~IdeController()
+{
+ for (int i = 0; i < 4; i++)
+ if (disks[i])
+ delete disks[i];
+}
+
+////
+// Utility functions
+///
+
+void
+IdeController::parseAddr(const Addr &addr, Addr &offset, IdeChannel &channel,
+ IdeRegType &reg_type)
+{
+ offset = addr;
+
+ if (addr >= pri_cmd_addr && addr < (pri_cmd_addr + pri_cmd_size)) {
+ offset -= pri_cmd_addr;
+ reg_type = COMMAND_BLOCK;
+ channel = PRIMARY;
+ } else if (addr >= pri_ctrl_addr &&
+ addr < (pri_ctrl_addr + pri_ctrl_size)) {
+ offset -= pri_ctrl_addr;
+ reg_type = CONTROL_BLOCK;
+ channel = PRIMARY;
+ } else if (addr >= sec_cmd_addr &&
+ addr < (sec_cmd_addr + sec_cmd_size)) {
+ offset -= sec_cmd_addr;
+ reg_type = COMMAND_BLOCK;
+ channel = SECONDARY;
+ } else if (addr >= sec_ctrl_addr &&
+ addr < (sec_ctrl_addr + sec_ctrl_size)) {
+ offset -= sec_ctrl_addr;
+ reg_type = CONTROL_BLOCK;
+ channel = SECONDARY;
+ } else if (addr >= bmi_addr && addr < (bmi_addr + bmi_size)) {
+ offset -= bmi_addr;
+ reg_type = BMI_BLOCK;
+ channel = (offset < BMIC1) ? PRIMARY : SECONDARY;
+ } else {
+ panic("IDE controller access to invalid address: %#x\n", addr);
+ }
+}
+
+int
+IdeController::getDisk(IdeChannel channel)
+{
+ int disk = 0;
+ uint8_t *devBit = &dev[0];
+
+ if (channel == SECONDARY) {
+ disk += 2;
+ devBit = &dev[1];
+ }
+
+ disk += *devBit;
+
+ assert(*devBit == 0 || *devBit == 1);
+
+ return disk;
+}
+
+int
+IdeController::getDisk(IdeDisk *diskPtr)
+{
+ for (int i = 0; i < 4; i++) {
+ if ((long)diskPtr == (long)disks[i])
+ return i;
+ }
+ return -1;
+}
+
+bool
+IdeController::isDiskSelected(IdeDisk *diskPtr)
+{
+ for (int i = 0; i < 4; i++) {
+ if ((long)diskPtr == (long)disks[i]) {
+ // is disk is on primary or secondary channel
+ int channel = i/2;
+ // is disk the master or slave
+ int devID = i%2;
+
+ return (dev[channel] == devID);
+ }
+ }
+ panic("Unable to find disk by pointer!!\n");
+}
+
+////
+// Command completion
+////
+
+void
+IdeController::setDmaComplete(IdeDisk *disk)
+{
+ int diskNum = getDisk(disk);
+
+ if (diskNum < 0)
+ panic("Unable to find disk based on pointer %#x\n", disk);
+
+ if (diskNum < 2) {
+ // clear the start/stop bit in the command register
+ bmi_regs.bmic0 &= ~SSBM;
+ // clear the bus master active bit in the status register
+ bmi_regs.bmis0 &= ~BMIDEA;
+ // set the interrupt bit
+ bmi_regs.bmis0 |= IDEINTS;
+ } else {
+ // clear the start/stop bit in the command register
+ bmi_regs.bmic1 &= ~SSBM;
+ // clear the bus master active bit in the status register
+ bmi_regs.bmis1 &= ~BMIDEA;
+ // set the interrupt bit
+ bmi_regs.bmis1 |= IDEINTS;
+ }
+}
+
+
+////
+// Read and write handling
+////
+
+void
+IdeController::readConfig(int offset, uint8_t *data)
+{
+ if (offset < PCI_DEVICE_SPECIFIC) {
+ PciDev::readConfig(offset, data);
+ } else if (offset >= IDE_CTRL_CONF_START &&
+ (offset + 1) <= IDE_CTRL_CONF_END) {
+
+ switch (offset) {
+ case IDE_CTRL_CONF_DEV_TIMING:
+ *data = config_regs.sidetim;
+ break;
+ case IDE_CTRL_CONF_UDMA_CNTRL:
+ *data = config_regs.udmactl;
+ break;
+ case IDE_CTRL_CONF_PRIM_TIMING+1:
+ *data = htole(config_regs.idetim0) >> 8;
+ break;
+ case IDE_CTRL_CONF_SEC_TIMING+1:
+ *data = htole(config_regs.idetim1) >> 8;
+ break;
+ case IDE_CTRL_CONF_IDE_CONFIG:
+ *data = htole(config_regs.ideconfig) & 0xFF;
+ break;
+ case IDE_CTRL_CONF_IDE_CONFIG+1:
+ *data = htole(config_regs.ideconfig) >> 8;
+ break;
+ default:
+ panic("Invalid PCI configuration read for size 1 at offset: %#x!\n",
+ offset);
+ }
+
+ } else {
+ panic("Read of unimplemented PCI config. register: %x\n", offset);
+ }
+ DPRINTF(IdeCtrl, "PCI read offset: %#x size: 1 data: %#x\n",
+ offset, (uint32_t)*data);
+}
+
+void
+IdeController::readConfig(int offset, uint16_t *data)
+{
+ if (offset < PCI_DEVICE_SPECIFIC) {
+ PciDev::readConfig(offset, data);
+ } else if (offset >= IDE_CTRL_CONF_START &&
+ (offset + 2) <= IDE_CTRL_CONF_END) {
+
+ switch (offset) {
+ case IDE_CTRL_CONF_PRIM_TIMING:
+ *data = config_regs.idetim0;
+ break;
+ case IDE_CTRL_CONF_SEC_TIMING:
+ *data = config_regs.idetim1;
+ break;
+ case IDE_CTRL_CONF_UDMA_TIMING:
+ *data = config_regs.udmatim;
+ break;
+ case IDE_CTRL_CONF_IDE_CONFIG:
+ *data = config_regs.ideconfig;
+ break;
+ default:
+ panic("Invalid PCI configuration read for size 2 offset: %#x!\n",
+ offset);
+ }
+
+ } else {
+ panic("Read of unimplemented PCI config. register: %x\n", offset);
+ }
+ DPRINTF(IdeCtrl, "PCI read offset: %#x size: 2 data: %#x\n", offset, *data);
+}
+
+void
+IdeController::readConfig(int offset, uint32_t *data)
+{
+ if (offset < PCI_DEVICE_SPECIFIC) {
+ PciDev::readConfig(offset, data);
+ } else {
+ panic("Read of unimplemented PCI config. register: %x\n", offset);
+ }
+ DPRINTF(IdeCtrl, "PCI read offset: %#x size: 4 data: %#x\n", offset, *data);
+}
+void
+IdeController::writeConfig(int offset, const uint8_t data)
+{
+ if (offset < PCI_DEVICE_SPECIFIC) {
+ PciDev::writeConfig(offset, data);
+ } else if (offset >= IDE_CTRL_CONF_START &&
+ (offset + 1) <= IDE_CTRL_CONF_END) {
+
+ switch (offset) {
+ case IDE_CTRL_CONF_DEV_TIMING:
+ config_regs.sidetim = data;
+ break;
+ case IDE_CTRL_CONF_UDMA_CNTRL:
+ config_regs.udmactl = data;
+ break;
+ case IDE_CTRL_CONF_IDE_CONFIG:
+ config_regs.ideconfig = (config_regs.ideconfig & 0xFF00) | (data);
+ break;
+ case IDE_CTRL_CONF_IDE_CONFIG+1:
+ config_regs.ideconfig = (config_regs.ideconfig & 0x00FF) | data << 8;
+ break;
+ default:
+ panic("Invalid PCI configuration write for size 1 offset: %#x!\n",
+ offset);
+ }
+
+ } else {
+ panic("Read of unimplemented PCI config. register: %x\n", offset);
+ }
+ DPRINTF(IdeCtrl, "PCI write offset: %#x size: 1 data: %#x\n",
+ offset, (uint32_t)data);
+}
+
+void
+IdeController::writeConfig(int offset, const uint16_t data)
+{
+ if (offset < PCI_DEVICE_SPECIFIC) {
+ PciDev::writeConfig(offset, data);
+ } else if (offset >= IDE_CTRL_CONF_START &&
+ (offset + 2) <= IDE_CTRL_CONF_END) {
+
+ switch (offset) {
+ case IDE_CTRL_CONF_PRIM_TIMING:
+ config_regs.idetim0 = data;
+ break;
+ case IDE_CTRL_CONF_SEC_TIMING:
+ config_regs.idetim1 = data;
+ break;
+ case IDE_CTRL_CONF_UDMA_TIMING:
+ config_regs.udmatim = data;
+ break;
+ case IDE_CTRL_CONF_IDE_CONFIG:
+ config_regs.ideconfig = data;
+ break;
+ default:
+ panic("Invalid PCI configuration write for size 2 offset: %#x!\n",
+ offset);
+ }
+
+ } else {
+ panic("Write of unimplemented PCI config. register: %x\n", offset);
+ }
+ DPRINTF(IdeCtrl, "PCI write offset: %#x size: 2 data: %#x\n", offset, data);
+
+ /* Trap command register writes and enable IO/BM as appropriate. */
+ if (offset == PCI_COMMAND) {
+ if (letoh(config.command) & PCI_CMD_IOSE)
+ io_enabled = true;
+ else
+ io_enabled = false;
+
+ if (letoh(config.command) & PCI_CMD_BME)
+ bm_enabled = true;
+ else
+ bm_enabled = false;
+ }
+
+}
+
+void
+IdeController::writeConfig(int offset, const uint32_t data)
+{
+ if (offset < PCI_DEVICE_SPECIFIC) {
+ PciDev::writeConfig(offset, data);
+ } else {
+ panic("Read of unimplemented PCI config. register: %x\n", offset);
+ }
+
+ DPRINTF(IdeCtrl, "PCI write offset: %#x size: 4 data: %#x\n", offset, data);
+
+ switch(offset) {
+ case PCI0_BASE_ADDR0:
+ if (BARAddrs[0] != 0)
+ pri_cmd_addr = BARAddrs[0];
+ break;
+
+ case PCI0_BASE_ADDR1:
+ if (BARAddrs[1] != 0)
+ pri_ctrl_addr = BARAddrs[1];
+ break;
+
+ case PCI0_BASE_ADDR2:
+ if (BARAddrs[2] != 0)
+ sec_cmd_addr = BARAddrs[2];
+ break;
+
+ case PCI0_BASE_ADDR3:
+ if (BARAddrs[3] != 0)
+ sec_ctrl_addr = BARAddrs[3];
+ break;
+
+ case PCI0_BASE_ADDR4:
+ if (BARAddrs[4] != 0)
+ bmi_addr = BARAddrs[4];
+ break;
+ }
+}
+
+Tick
+IdeController::read(Packet *pkt)
+{
+ Addr offset;
+ IdeChannel channel;
+ IdeRegType reg_type;
+ int disk;
+
+ pkt->time += pioDelay;
+ pkt->allocate();
+ if (pkt->size != 1 && pkt->size != 2 && pkt->size !=4)
+ panic("Bad IDE read size: %d\n", pkt->size);
+
+ parseAddr(pkt->addr, offset, channel, reg_type);
+
+ if (!io_enabled) {
+ pkt->result = Success;
+ return pioDelay;
+ }
+
+ switch (reg_type) {
+ case BMI_BLOCK:
+ switch (pkt->size) {
+ case sizeof(uint8_t):
+ pkt->set(bmi_regs.data[offset]);
+ break;
+ case sizeof(uint16_t):
+ pkt->set(*(uint16_t*)&bmi_regs.data[offset]);
+ break;
+ case sizeof(uint32_t):
+ pkt->set(*(uint32_t*)&bmi_regs.data[offset]);
+ break;
+ default:
+ panic("IDE read of BMI reg invalid size: %#x\n", pkt->size);
+ }
+ break;
+
+ case COMMAND_BLOCK:
+ case CONTROL_BLOCK:
+ disk = getDisk(channel);
+
+ if (disks[disk] == NULL) {
+ pkt->set<uint8_t>(0);
+ break;
+ }
+
+ switch (offset) {
+ case DATA_OFFSET:
+ switch (pkt->size) {
+ case sizeof(uint16_t):
+ disks[disk]->read(offset, reg_type, pkt->getPtr<uint8_t>());
+ break;
+
+ case sizeof(uint32_t):
+ disks[disk]->read(offset, reg_type, pkt->getPtr<uint8_t>());
+ disks[disk]->read(offset, reg_type,
+ pkt->getPtr<uint8_t>() + sizeof(uint16_t));
+ break;
+
+ default:
+ panic("IDE read of data reg invalid size: %#x\n", pkt->size);
+ }
+ break;
+ default:
+ if (pkt->size == sizeof(uint8_t)) {
+ disks[disk]->read(offset, reg_type, pkt->getPtr<uint8_t>());
+ } else
+ panic("IDE read of command reg of invalid size: %#x\n", pkt->size);
+ }
+ break;
+ default:
+ panic("IDE controller read of unknown register block type!\n");
+ }
+ if (pkt->size == 1)
+ DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n",
+ offset, pkt->size, (uint32_t)pkt->get<uint8_t>());
+ else if (pkt->size == 2)
+ DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n",
+ offset, pkt->size, pkt->get<uint16_t>());
+ else
+ DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n",
+ offset, pkt->size, pkt->get<uint32_t>());
+
+ pkt->result = Success;
+ return pioDelay;
+}
+
+Tick
+IdeController::write(Packet *pkt)
+{
+ Addr offset;
+ IdeChannel channel;
+ IdeRegType reg_type;
+ int disk;
+ uint8_t oldVal, newVal;
+
+ pkt->time += pioDelay;
+
+ parseAddr(pkt->addr, offset, channel, reg_type);
+
+ if (!io_enabled) {
+ pkt->result = Success;
+ DPRINTF(IdeCtrl, "io not enabled\n");
+ return pioDelay;
+ }
+
+ switch (reg_type) {
+ case BMI_BLOCK:
+ if (!bm_enabled) {
+ pkt->result = Success;
+ return pioDelay;
+ }
+
+ switch (offset) {
+ // Bus master IDE command register
+ case BMIC1:
+ case BMIC0:
+ if (pkt->size != sizeof(uint8_t))
+ panic("Invalid BMIC write size: %x\n", pkt->size);
+
+ // select the current disk based on DEV bit
+ disk = getDisk(channel);
+
+ oldVal = bmi_regs.chan[channel].bmic;
+ newVal = pkt->get<uint8_t>();
+
+ // if a DMA transfer is in progress, R/W control cannot change
+ if (oldVal & SSBM) {
+ if ((oldVal & RWCON) ^ (newVal & RWCON)) {
+ (oldVal & RWCON) ? newVal |= RWCON : newVal &= ~RWCON;
+ }
+ }
+
+ // see if the start/stop bit is being changed
+ if ((oldVal & SSBM) ^ (newVal & SSBM)) {
+ if (oldVal & SSBM) {
+ // stopping DMA transfer
+ DPRINTF(IdeCtrl, "Stopping DMA transfer\n");
+
+ // clear the BMIDEA bit
+ bmi_regs.chan[channel].bmis =
+ bmi_regs.chan[channel].bmis & ~BMIDEA;
+
+ if (disks[disk] == NULL)
+ panic("DMA stop for disk %d which does not exist\n",
+ disk);
+
+ // inform the disk of the DMA transfer abort
+ disks[disk]->abortDma();
+ } else {
+ // starting DMA transfer
+ DPRINTF(IdeCtrl, "Starting DMA transfer\n");
+
+ // set the BMIDEA bit
+ bmi_regs.chan[channel].bmis =
+ bmi_regs.chan[channel].bmis | BMIDEA;
+
+ if (disks[disk] == NULL)
+ panic("DMA start for disk %d which does not exist\n",
+ disk);
+
+ // inform the disk of the DMA transfer start
+ disks[disk]->startDma(letoh(bmi_regs.chan[channel].bmidtp));
+ }
+ }
+
+ // update the register value
+ bmi_regs.chan[channel].bmic = newVal;
+ break;
+
+ // Bus master IDE status register
+ case BMIS0:
+ case BMIS1:
+ if (pkt->size != sizeof(uint8_t))
+ panic("Invalid BMIS write size: %x\n", pkt->size);
+
+ oldVal = bmi_regs.chan[channel].bmis;
+ newVal = pkt->get<uint8_t>();
+
+ // the BMIDEA bit is RO
+ newVal |= (oldVal & BMIDEA);
+
+ // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each
+ if ((oldVal & IDEINTS) && (newVal & IDEINTS))
+ newVal &= ~IDEINTS; // clear the interrupt?
+ else
+ (oldVal & IDEINTS) ? newVal |= IDEINTS : newVal &= ~IDEINTS;
+
+ if ((oldVal & IDEDMAE) && (newVal & IDEDMAE))
+ newVal &= ~IDEDMAE;
+ else
+ (oldVal & IDEDMAE) ? newVal |= IDEDMAE : newVal &= ~IDEDMAE;
+
+ bmi_regs.chan[channel].bmis = newVal;
+ break;
+
+ // Bus master IDE descriptor table pointer register
+ case BMIDTP0:
+ case BMIDTP1:
+ {
+ if (pkt->size != sizeof(uint32_t))
+ panic("Invalid BMIDTP write size: %x\n", pkt->size);
+
+ bmi_regs.chan[channel].bmidtp = htole(pkt->get<uint32_t>() & ~0x3);
+ }
+ break;
+
+ default:
+ if (pkt->size != sizeof(uint8_t) &&
+ pkt->size != sizeof(uint16_t) &&
+ pkt->size != sizeof(uint32_t))
+ panic("IDE controller write of invalid write size: %x\n",
+ pkt->size);
+
+ // do a default copy of data into the registers
+ memcpy(&bmi_regs.data[offset], pkt->getPtr<uint8_t>(), pkt->size);
+ }
+ break;
+ case COMMAND_BLOCK:
+ if (offset == IDE_SELECT_OFFSET) {
+ uint8_t *devBit = &dev[channel];
+ *devBit = (letoh(pkt->get<uint8_t>()) & IDE_SELECT_DEV_BIT) ? 1 : 0;
+ }
+ // fall-through ok!
+ case CONTROL_BLOCK:
+ disk = getDisk(channel);
+
+ if (disks[disk] == NULL)
+ break;
+
+ switch (offset) {
+ case DATA_OFFSET:
+ switch (pkt->size) {
+ case sizeof(uint16_t):
+ disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>());
+ break;
+
+ case sizeof(uint32_t):
+ disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>());
+ disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>() +
+ sizeof(uint16_t));
+ break;
+ default:
+ panic("IDE write of data reg invalid size: %#x\n", pkt->size);
+ }
+ break;
+ default:
+ if (pkt->size == sizeof(uint8_t)) {
+ disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>());
+ } else
+ panic("IDE write of command reg of invalid size: %#x\n", pkt->size);
+ }
+ break;
+ default:
+ panic("IDE controller write of unknown register block type!\n");
+ }
+
+ if (pkt->size == 1)
+ DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n",
+ offset, pkt->size, (uint32_t)pkt->get<uint8_t>());
+ else if (pkt->size == 2)
+ DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n",
+ offset, pkt->size, pkt->get<uint16_t>());
+ else
+ DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n",
+ offset, pkt->size, pkt->get<uint32_t>());
+
+
+ pkt->result = Success;
+ return pioDelay;
+}
+
+////
+// Serialization
+////
+
+void
+IdeController::serialize(std::ostream &os)
+{
+ // Serialize the PciDev base class
+ PciDev::serialize(os);
+
+ // Serialize register addresses and sizes
+ SERIALIZE_SCALAR(pri_cmd_addr);
+ SERIALIZE_SCALAR(pri_cmd_size);
+ SERIALIZE_SCALAR(pri_ctrl_addr);
+ SERIALIZE_SCALAR(pri_ctrl_size);
+ SERIALIZE_SCALAR(sec_cmd_addr);
+ SERIALIZE_SCALAR(sec_cmd_size);
+ SERIALIZE_SCALAR(sec_ctrl_addr);
+ SERIALIZE_SCALAR(sec_ctrl_size);
+ SERIALIZE_SCALAR(bmi_addr);
+ SERIALIZE_SCALAR(bmi_size);
+
+ // Serialize registers
+ SERIALIZE_ARRAY(bmi_regs.data,
+ sizeof(bmi_regs.data) / sizeof(bmi_regs.data[0]));
+ SERIALIZE_ARRAY(dev, sizeof(dev) / sizeof(dev[0]));
+ SERIALIZE_ARRAY(config_regs.data,
+ sizeof(config_regs.data) / sizeof(config_regs.data[0]));
+
+ // Serialize internal state
+ SERIALIZE_SCALAR(io_enabled);
+ SERIALIZE_SCALAR(bm_enabled);
+ SERIALIZE_ARRAY(cmd_in_progress,
+ sizeof(cmd_in_progress) / sizeof(cmd_in_progress[0]));
+}
+
+void
+IdeController::unserialize(Checkpoint *cp, const std::string &section)
+{
+ // Unserialize the PciDev base class
+ PciDev::unserialize(cp, section);
+
+ // Unserialize register addresses and sizes
+ UNSERIALIZE_SCALAR(pri_cmd_addr);
+ UNSERIALIZE_SCALAR(pri_cmd_size);
+ UNSERIALIZE_SCALAR(pri_ctrl_addr);
+ UNSERIALIZE_SCALAR(pri_ctrl_size);
+ UNSERIALIZE_SCALAR(sec_cmd_addr);
+ UNSERIALIZE_SCALAR(sec_cmd_size);
+ UNSERIALIZE_SCALAR(sec_ctrl_addr);
+ UNSERIALIZE_SCALAR(sec_ctrl_size);
+ UNSERIALIZE_SCALAR(bmi_addr);
+ UNSERIALIZE_SCALAR(bmi_size);
+
+ // Unserialize registers
+ UNSERIALIZE_ARRAY(bmi_regs.data,
+ sizeof(bmi_regs.data) / sizeof(bmi_regs.data[0]));
+ UNSERIALIZE_ARRAY(dev, sizeof(dev) / sizeof(dev[0]));
+ UNSERIALIZE_ARRAY(config_regs.data,
+ sizeof(config_regs.data) / sizeof(config_regs.data[0]));
+
+ // Unserialize internal state
+ UNSERIALIZE_SCALAR(io_enabled);
+ UNSERIALIZE_SCALAR(bm_enabled);
+ UNSERIALIZE_ARRAY(cmd_in_progress,
+ sizeof(cmd_in_progress) / sizeof(cmd_in_progress[0]));
+ pioPort->sendStatusChange(Port::RangeChange);
+}
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeController)
+
+ SimObjectParam<System *> system;
+ SimObjectParam<Platform *> platform;
+ SimObjectParam<PciConfigAll *> configspace;
+ SimObjectParam<PciConfigData *> configdata;
+ Param<uint32_t> pci_bus;
+ Param<uint32_t> pci_dev;
+ Param<uint32_t> pci_func;
+ Param<Tick> pio_latency;
+ SimObjectVectorParam<IdeDisk *> disks;
+
+END_DECLARE_SIM_OBJECT_PARAMS(IdeController)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(IdeController)
+
+ INIT_PARAM(system, "System pointer"),
+ INIT_PARAM(platform, "Platform pointer"),
+ INIT_PARAM(configspace, "PCI Configspace"),
+ INIT_PARAM(configdata, "PCI Config data"),
+ INIT_PARAM(pci_bus, "PCI bus ID"),
+ INIT_PARAM(pci_dev, "PCI device number"),
+ INIT_PARAM(pci_func, "PCI function code"),
+ INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
+ INIT_PARAM(disks, "IDE disks attached to this controller")
+
+END_INIT_SIM_OBJECT_PARAMS(IdeController)
+
+CREATE_SIM_OBJECT(IdeController)
+{
+ IdeController::Params *params = new IdeController::Params;
+ params->name = getInstanceName();
+ params->platform = platform;
+ params->system = system;
+ params->configSpace = configspace;
+ params->configData = configdata;
+ params->busNum = pci_bus;
+ params->deviceNum = pci_dev;
+ params->functionNum = pci_func;
+ params->pio_delay = pio_latency;
+ params->disks = disks;
+ return new IdeController(params);
+}
+
+REGISTER_SIM_OBJECT("IdeController", IdeController)
+
+#endif //DOXYGEN_SHOULD_SKIP_THIS
diff --git a/src/dev/ide_ctrl.hh b/src/dev/ide_ctrl.hh
new file mode 100644
index 000000000..dda2cbb66
--- /dev/null
+++ b/src/dev/ide_ctrl.hh
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * Simple PCI IDE controller with bus mastering capability and UDMA
+ * modeled after controller in the Intel PIIX4 chip
+ */
+
+#ifndef __IDE_CTRL_HH__
+#define __IDE_CTRL_HH__
+
+#include "dev/pcidev.hh"
+#include "dev/pcireg.h"
+#include "dev/io_device.hh"
+
+#define BMIC0 0x0 // Bus master IDE command register
+#define BMIS0 0x2 // Bus master IDE status register
+#define BMIDTP0 0x4 // Bus master IDE descriptor table pointer register
+#define BMIC1 0x8 // Bus master IDE command register
+#define BMIS1 0xa // Bus master IDE status register
+#define BMIDTP1 0xc // Bus master IDE descriptor table pointer register
+
+// Bus master IDE command register bit fields
+#define RWCON 0x08 // Bus master read/write control
+#define SSBM 0x01 // Start/stop bus master
+
+// Bus master IDE status register bit fields
+#define DMA1CAP 0x40 // Drive 1 DMA capable
+#define DMA0CAP 0x20 // Drive 0 DMA capable
+#define IDEINTS 0x04 // IDE Interrupt Status
+#define IDEDMAE 0x02 // IDE DMA error
+#define BMIDEA 0x01 // Bus master IDE active
+
+// IDE Command byte fields
+#define IDE_SELECT_OFFSET (6)
+#define IDE_SELECT_DEV_BIT 0x10
+
+#define IDE_FEATURE_OFFSET IDE_ERROR_OFFSET
+#define IDE_COMMAND_OFFSET IDE_STATUS_OFFSET
+
+// IDE Timing Register bit fields
+#define IDETIM_DECODE_EN 0x8000
+
+// PCI device specific register byte offsets
+#define IDE_CTRL_CONF_START 0x40
+#define IDE_CTRL_CONF_END ((IDE_CTRL_CONF_START) + sizeof(config_regs))
+
+#define IDE_CTRL_CONF_PRIM_TIMING 0x40
+#define IDE_CTRL_CONF_SEC_TIMING 0x42
+#define IDE_CTRL_CONF_DEV_TIMING 0x44
+#define IDE_CTRL_CONF_UDMA_CNTRL 0x48
+#define IDE_CTRL_CONF_UDMA_TIMING 0x4A
+#define IDE_CTRL_CONF_IDE_CONFIG 0x54
+
+
+enum IdeRegType {
+ COMMAND_BLOCK,
+ CONTROL_BLOCK,
+ BMI_BLOCK
+};
+
+class IdeDisk;
+class IntrControl;
+class PciConfigAll;
+class Platform;
+
+/**
+ * Device model for an Intel PIIX4 IDE controller
+ */
+
+class IdeController : public PciDev
+{
+ friend class IdeDisk;
+
+ enum IdeChannel {
+ PRIMARY = 0,
+ SECONDARY = 1
+ };
+
+ private:
+ /** Primary command block registers */
+ Addr pri_cmd_addr;
+ Addr pri_cmd_size;
+ /** Primary control block registers */
+ Addr pri_ctrl_addr;
+ Addr pri_ctrl_size;
+ /** Secondary command block registers */
+ Addr sec_cmd_addr;
+ Addr sec_cmd_size;
+ /** Secondary control block registers */
+ Addr sec_ctrl_addr;
+ Addr sec_ctrl_size;
+ /** Bus master interface (BMI) registers */
+ Addr bmi_addr;
+ Addr bmi_size;
+
+ private:
+ /** Registers used for bus master interface */
+ union {
+ uint8_t data[16];
+
+ struct {
+ uint8_t bmic0;
+ uint8_t reserved_0;
+ uint8_t bmis0;
+ uint8_t reserved_1;
+ uint32_t bmidtp0;
+ uint8_t bmic1;
+ uint8_t reserved_2;
+ uint8_t bmis1;
+ uint8_t reserved_3;
+ uint32_t bmidtp1;
+ };
+
+ struct {
+ uint8_t bmic;
+ uint8_t reserved_4;
+ uint8_t bmis;
+ uint8_t reserved_5;
+ uint32_t bmidtp;
+ } chan[2];
+
+ } bmi_regs;
+ /** Shadows of the device select bit */
+ uint8_t dev[2];
+ /** Registers used in device specific PCI configuration */
+ union {
+ uint8_t data[22];
+
+ struct {
+ uint16_t idetim0;
+ uint16_t idetim1;
+ uint8_t sidetim;
+ uint8_t reserved_0[3];
+ uint8_t udmactl;
+ uint8_t reserved_1;
+ uint16_t udmatim;
+ uint8_t reserved_2[8];
+ uint16_t ideconfig;
+ };
+ } config_regs;
+
+ // Internal management variables
+ bool io_enabled;
+ bool bm_enabled;
+ bool cmd_in_progress[4];
+
+ private:
+ /** IDE disks connected to controller */
+ IdeDisk *disks[4];
+
+ private:
+ /** Parse the access address to pass on to device */
+ void parseAddr(const Addr &addr, Addr &offset, IdeChannel &channel,
+ IdeRegType &reg_type);
+
+ /** Select the disk based on the channel and device bit */
+ int getDisk(IdeChannel channel);
+
+ /** Select the disk based on a pointer */
+ int getDisk(IdeDisk *diskPtr);
+
+ public:
+ /** See if a disk is selected based on its pointer */
+ bool isDiskSelected(IdeDisk *diskPtr);
+
+ public:
+ struct Params : public PciDev::Params
+ {
+ /** Array of disk objects */
+ std::vector<IdeDisk *> disks;
+ };
+ const Params *params() const { return (const Params *)_params; }
+
+ public:
+ IdeController(Params *p);
+ ~IdeController();
+
+ virtual void writeConfig(int offset, const uint8_t data);
+ virtual void writeConfig(int offset, const uint16_t data);
+ virtual void writeConfig(int offset, const uint32_t data);
+ virtual void readConfig(int offset, uint8_t *data);
+ virtual void readConfig(int offset, uint16_t *data);
+ virtual void readConfig(int offset, uint32_t *data);
+
+ void setDmaComplete(IdeDisk *disk);
+
+ /**
+ * Read a done field for a given target.
+ * @param pkt Packet describing what is to be read
+ * @return The amount of time to complete this request
+ */
+ virtual Tick read(Packet *pkt);
+
+ /**
+ * Write a done field for a given target.
+ * @param pkt Packet describing what is to be written
+ * @return The amount of time to complete this request
+ */
+ virtual Tick write(Packet *pkt);
+
+ /**
+ * Serialize this object to the given output stream.
+ * @param os The stream to serialize to.
+ */
+ virtual void serialize(std::ostream &os);
+
+ /**
+ * Reconstruct the state of this object from a checkpoint.
+ * @param cp The checkpoint use.
+ * @param section The section name of this object
+ */
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+
+};
+#endif // __IDE_CTRL_HH_
diff --git a/src/dev/ide_disk.cc b/src/dev/ide_disk.cc
new file mode 100644
index 000000000..909f35c60
--- /dev/null
+++ b/src/dev/ide_disk.cc
@@ -0,0 +1,1146 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * Device model implementation for an IDE disk
+ */
+
+#include <cerrno>
+#include <cstring>
+#include <deque>
+#include <string>
+
+#include "base/chunk_generator.hh"
+#include "base/cprintf.hh" // csprintf
+#include "base/trace.hh"
+#include "dev/disk_image.hh"
+#include "dev/ide_disk.hh"
+#include "dev/ide_ctrl.hh"
+#include "dev/tsunami.hh"
+#include "dev/tsunami_pchip.hh"
+#include "sim/builder.hh"
+#include "sim/sim_object.hh"
+#include "sim/root.hh"
+#include "arch/isa_traits.hh"
+
+using namespace std;
+using namespace TheISA;
+
+IdeDisk::IdeDisk(const string &name, DiskImage *img,
+ int id, Tick delay)
+ : SimObject(name), ctrl(NULL), image(img), diskDelay(delay),
+ dmaTransferEvent(this), dmaReadCG(NULL), dmaReadWaitEvent(this),
+ dmaWriteCG(NULL), dmaWriteWaitEvent(this), dmaPrdReadEvent(this),
+ dmaReadEvent(this), dmaWriteEvent(this)
+{
+ // Reset the device state
+ reset(id);
+
+ // fill out the drive ID structure
+ memset(&driveID, 0, sizeof(struct ataparams));
+
+ // Calculate LBA and C/H/S values
+ uint16_t cylinders;
+ uint8_t heads;
+ uint8_t sectors;
+
+ uint32_t lba_size = image->size();
+ if (lba_size >= 16383*16*63) {
+ cylinders = 16383;
+ heads = 16;
+ sectors = 63;
+ } else {
+ if (lba_size >= 63)
+ sectors = 63;
+ else
+ sectors = lba_size;
+
+ if ((lba_size / sectors) >= 16)
+ heads = 16;
+ else
+ heads = (lba_size / sectors);
+
+ cylinders = lba_size / (heads * sectors);
+ }
+
+ // Setup the model name
+ strncpy((char *)driveID.atap_model, "5MI EDD si k",
+ sizeof(driveID.atap_model));
+ // Set the maximum multisector transfer size
+ driveID.atap_multi = MAX_MULTSECT;
+ // IORDY supported, IORDY disabled, LBA enabled, DMA enabled
+ driveID.atap_capabilities1 = 0x7;
+ // UDMA support, EIDE support
+ driveID.atap_extensions = 0x6;
+ // Setup default C/H/S settings
+ driveID.atap_cylinders = cylinders;
+ driveID.atap_sectors = sectors;
+ driveID.atap_heads = heads;
+ // Setup the current multisector transfer size
+ driveID.atap_curmulti = MAX_MULTSECT;
+ driveID.atap_curmulti_valid = 0x1;
+ // Number of sectors on disk
+ driveID.atap_capacity = lba_size;
+ // Multiword DMA mode 2 and below supported
+ driveID.atap_dmamode_supp = 0x400;
+ // Set PIO mode 4 and 3 supported
+ driveID.atap_piomode_supp = 0x3;
+ // Set DMA mode 4 and below supported
+ driveID.atap_udmamode_supp = 0x1f;
+ // Statically set hardware config word
+ driveID.atap_hwreset_res = 0x4001;
+
+ //arbitrary for now...
+ driveID.atap_ata_major = WDC_VER_ATA7;
+}
+
+IdeDisk::~IdeDisk()
+{
+ // destroy the data buffer
+ delete [] dataBuffer;
+}
+
+void
+IdeDisk::reset(int id)
+{
+ // initialize the data buffer and shadow registers
+ dataBuffer = new uint8_t[MAX_DMA_SIZE];
+
+ memset(dataBuffer, 0, MAX_DMA_SIZE);
+ memset(&cmdReg, 0, sizeof(CommandReg_t));
+ memset(&curPrd.entry, 0, sizeof(PrdEntry_t));
+
+ curPrdAddr = 0;
+ curSector = 0;
+ cmdBytes = 0;
+ cmdBytesLeft = 0;
+ drqBytesLeft = 0;
+ dmaRead = false;
+ intrPending = false;
+
+ // set the device state to idle
+ dmaState = Dma_Idle;
+
+ if (id == DEV0) {
+ devState = Device_Idle_S;
+ devID = DEV0;
+ } else if (id == DEV1) {
+ devState = Device_Idle_NS;
+ devID = DEV1;
+ } else {
+ panic("Invalid device ID: %#x\n", id);
+ }
+
+ // set the device ready bit
+ status = STATUS_DRDY_BIT;
+
+ /* The error register must be set to 0x1 on start-up to
+ indicate that no diagnostic error was detected */
+ cmdReg.error = 0x1;
+}
+
+////
+// Utility functions
+////
+
+bool
+IdeDisk::isDEVSelect()
+{
+ return ctrl->isDiskSelected(this);
+}
+
+Addr
+IdeDisk::pciToDma(Addr pciAddr)
+{
+ if (ctrl)
+ return ctrl->plat->pciToDma(pciAddr);
+ else
+ panic("Access to unset controller!\n");
+}
+
+////
+// Device registers read/write
+////
+
+void
+IdeDisk::read(const Addr &offset, IdeRegType reg_type, uint8_t *data)
+{
+ DevAction_t action = ACT_NONE;
+
+ switch (reg_type) {
+ case COMMAND_BLOCK:
+ switch (offset) {
+ // Data transfers occur two bytes at a time
+ case DATA_OFFSET:
+ *(uint16_t*)data = cmdReg.data;
+ action = ACT_DATA_READ_SHORT;
+ break;
+ case ERROR_OFFSET:
+ *data = cmdReg.error;
+ break;
+ case NSECTOR_OFFSET:
+ *data = cmdReg.sec_count;
+ break;
+ case SECTOR_OFFSET:
+ *data = cmdReg.sec_num;
+ break;
+ case LCYL_OFFSET:
+ *data = cmdReg.cyl_low;
+ break;
+ case HCYL_OFFSET:
+ *data = cmdReg.cyl_high;
+ break;
+ case DRIVE_OFFSET:
+ *data = cmdReg.drive;
+ break;
+ case STATUS_OFFSET:
+ *data = status;
+ action = ACT_STAT_READ;
+ break;
+ default:
+ panic("Invalid IDE command register offset: %#x\n", offset);
+ }
+ break;
+ case CONTROL_BLOCK:
+ if (offset == ALTSTAT_OFFSET)
+ *data = status;
+ else
+ panic("Invalid IDE control register offset: %#x\n", offset);
+ break;
+ default:
+ panic("Unknown register block!\n");
+ }
+ DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset,
+ (uint32_t)*data);
+
+ if (action != ACT_NONE)
+ updateState(action);
+}
+
+void
+IdeDisk::write(const Addr &offset, IdeRegType reg_type, const uint8_t *data)
+{
+ DevAction_t action = ACT_NONE;
+
+ switch (reg_type) {
+ case COMMAND_BLOCK:
+ switch (offset) {
+ case DATA_OFFSET:
+ cmdReg.data = *(uint16_t*)data;
+ action = ACT_DATA_WRITE_SHORT;
+ break;
+ case FEATURES_OFFSET:
+ break;
+ case NSECTOR_OFFSET:
+ cmdReg.sec_count = *data;
+ break;
+ case SECTOR_OFFSET:
+ cmdReg.sec_num = *data;
+ break;
+ case LCYL_OFFSET:
+ cmdReg.cyl_low = *data;
+ break;
+ case HCYL_OFFSET:
+ cmdReg.cyl_high = *data;
+ break;
+ case DRIVE_OFFSET:
+ cmdReg.drive = *data;
+ action = ACT_SELECT_WRITE;
+ break;
+ case COMMAND_OFFSET:
+ cmdReg.command = *data;
+ action = ACT_CMD_WRITE;
+ break;
+ default:
+ panic("Invalid IDE command register offset: %#x\n", offset);
+ }
+ break;
+ case CONTROL_BLOCK:
+ if (offset == CONTROL_OFFSET) {
+ if (*data & CONTROL_RST_BIT) {
+ // force the device into the reset state
+ devState = Device_Srst;
+ action = ACT_SRST_SET;
+ } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT))
+ action = ACT_SRST_CLEAR;
+
+ nIENBit = (*data & CONTROL_IEN_BIT) ? true : false;
+ }
+ else
+ panic("Invalid IDE control register offset: %#x\n", offset);
+ break;
+ default:
+ panic("Unknown register block!\n");
+ }
+
+ DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset,
+ (uint32_t)*data);
+ if (action != ACT_NONE)
+ updateState(action);
+}
+
+////
+// Perform DMA transactions
+////
+
+void
+IdeDisk::doDmaTransfer()
+{
+ if (dmaState != Dma_Transfer || devState != Transfer_Data_Dma)
+ panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
+ dmaState, devState);
+
+ if (ctrl->dmaPending()) {
+ dmaTransferEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
+ return;
+ } else
+ ctrl->dmaRead(curPrdAddr, sizeof(PrdEntry_t), &dmaPrdReadEvent,
+ (uint8_t*)&curPrd.entry);
+}
+
+void
+IdeDisk::dmaPrdReadDone()
+{
+ DPRINTF(IdeDisk,
+ "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n",
+ curPrd.getBaseAddr(), pciToDma(curPrd.getBaseAddr()),
+ curPrd.getByteCount(), (cmdBytesLeft/SectorSize),
+ curPrd.getEOT(), curSector);
+
+ // the prd pointer has already been translated, so just do an increment
+ curPrdAddr = curPrdAddr + sizeof(PrdEntry_t);
+
+ if (dmaRead)
+ doDmaDataRead();
+ else
+ doDmaDataWrite();
+}
+
+void
+IdeDisk::doDmaDataRead()
+{
+ /** @todo we need to figure out what the delay actually will be */
+ Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
+
+ DPRINTF(IdeDisk, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n",
+ diskDelay, totalDiskDelay);
+
+ dmaReadWaitEvent.schedule(curTick + totalDiskDelay);
+}
+
+void
+IdeDisk::regStats()
+{
+ using namespace Stats;
+ dmaReadFullPages
+ .name(name() + ".dma_read_full_pages")
+ .desc("Number of full page size DMA reads (not PRD).")
+ ;
+ dmaReadBytes
+ .name(name() + ".dma_read_bytes")
+ .desc("Number of bytes transfered via DMA reads (not PRD).")
+ ;
+ dmaReadTxs
+ .name(name() + ".dma_read_txs")
+ .desc("Number of DMA read transactions (not PRD).")
+ ;
+
+ dmaWriteFullPages
+ .name(name() + ".dma_write_full_pages")
+ .desc("Number of full page size DMA writes.")
+ ;
+ dmaWriteBytes
+ .name(name() + ".dma_write_bytes")
+ .desc("Number of bytes transfered via DMA writes.")
+ ;
+ dmaWriteTxs
+ .name(name() + ".dma_write_txs")
+ .desc("Number of DMA write transactions.")
+ ;
+}
+
+void
+IdeDisk::doDmaRead()
+{
+
+ if (!dmaReadCG) {
+ // clear out the data buffer
+ memset(dataBuffer, 0, MAX_DMA_SIZE);
+ dmaReadCG = new ChunkGenerator(curPrd.getBaseAddr(),
+ curPrd.getByteCount(), TheISA::PageBytes);
+
+ }
+ if (ctrl->dmaPending()) {
+ panic("shouldn't be reentant??");
+ dmaReadWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
+ return;
+ } else if (!dmaReadCG->done()) {
+ assert(dmaReadCG->complete() < MAX_DMA_SIZE);
+ ctrl->dmaRead(pciToDma(dmaReadCG->addr()), dmaReadCG->size(),
+ &dmaReadWaitEvent, dataBuffer + dmaReadCG->complete());
+ dmaReadBytes += dmaReadCG->size();
+ dmaReadTxs++;
+ if (dmaReadCG->size() == TheISA::PageBytes)
+ dmaReadFullPages++;
+ dmaReadCG->next();
+ } else {
+ assert(dmaReadCG->done());
+ delete dmaReadCG;
+ dmaReadCG = NULL;
+ dmaReadDone();
+ }
+}
+
+void
+IdeDisk::dmaReadDone()
+{
+
+ uint32_t bytesWritten = 0;
+
+
+ // write the data to the disk image
+ for (bytesWritten = 0; bytesWritten < curPrd.getByteCount();
+ bytesWritten += SectorSize) {
+
+ cmdBytesLeft -= SectorSize;
+ writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten));
+ }
+
+ // check for the EOT
+ if (curPrd.getEOT()) {
+ assert(cmdBytesLeft == 0);
+ dmaState = Dma_Idle;
+ updateState(ACT_DMA_DONE);
+ } else {
+ doDmaTransfer();
+ }
+}
+
+void
+IdeDisk::doDmaDataWrite()
+{
+ /** @todo we need to figure out what the delay actually will be */
+ Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
+ uint32_t bytesRead = 0;
+
+ DPRINTF(IdeDisk, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n",
+ diskDelay, totalDiskDelay);
+
+ memset(dataBuffer, 0, MAX_DMA_SIZE);
+ assert(cmdBytesLeft <= MAX_DMA_SIZE);
+ while (bytesRead < curPrd.getByteCount()) {
+ readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead));
+ bytesRead += SectorSize;
+ cmdBytesLeft -= SectorSize;
+ }
+
+ dmaWriteWaitEvent.schedule(curTick + totalDiskDelay);
+}
+
+void
+IdeDisk::doDmaWrite()
+{
+
+ if (!dmaWriteCG) {
+ // clear out the data buffer
+ dmaWriteCG = new ChunkGenerator(curPrd.getBaseAddr(),
+ curPrd.getByteCount(), TheISA::PageBytes);
+ }
+ if (ctrl->dmaPending()) {
+ panic("shouldn't be reentant??");
+ dmaWriteWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
+ return;
+ } else if (!dmaWriteCG->done()) {
+ assert(dmaWriteCG->complete() < MAX_DMA_SIZE);
+ ctrl->dmaWrite(pciToDma(dmaWriteCG->addr()), dmaWriteCG->size(),
+ &dmaWriteWaitEvent, dataBuffer + dmaWriteCG->complete());
+ dmaWriteBytes += dmaWriteCG->size();
+ dmaWriteTxs++;
+ if (dmaWriteCG->size() == TheISA::PageBytes)
+ dmaWriteFullPages++;
+ dmaWriteCG->next();
+ } else {
+ assert(dmaWriteCG->done());
+ delete dmaWriteCG;
+ dmaWriteCG = NULL;
+ dmaWriteDone();
+ }
+}
+
+void
+IdeDisk::dmaWriteDone()
+{
+ // check for the EOT
+ if (curPrd.getEOT()) {
+ assert(cmdBytesLeft == 0);
+ dmaState = Dma_Idle;
+ updateState(ACT_DMA_DONE);
+ } else {
+ doDmaTransfer();
+ }
+}
+
+////
+// Disk utility routines
+///
+
+void
+IdeDisk::readDisk(uint32_t sector, uint8_t *data)
+{
+ uint32_t bytesRead = image->read(data, sector);
+
+ if (bytesRead != SectorSize)
+ panic("Can't read from %s. Only %d of %d read. errno=%d\n",
+ name(), bytesRead, SectorSize, errno);
+}
+
+void
+IdeDisk::writeDisk(uint32_t sector, uint8_t *data)
+{
+ uint32_t bytesWritten = image->write(data, sector);
+
+ if (bytesWritten != SectorSize)
+ panic("Can't write to %s. Only %d of %d written. errno=%d\n",
+ name(), bytesWritten, SectorSize, errno);
+}
+
+////
+// Setup and handle commands
+////
+
+void
+IdeDisk::startDma(const uint32_t &prdTableBase)
+{
+ if (dmaState != Dma_Start)
+ panic("Inconsistent DMA state, should be in Dma_Start!\n");
+
+ if (devState != Transfer_Data_Dma)
+ panic("Inconsistent device state for DMA start!\n");
+
+ // PRD base address is given by bits 31:2
+ curPrdAddr = pciToDma((Addr)(prdTableBase & ~ULL(0x3)));
+
+ dmaState = Dma_Transfer;
+
+ // schedule dma transfer (doDmaTransfer)
+ dmaTransferEvent.schedule(curTick + 1);
+}
+
+void
+IdeDisk::abortDma()
+{
+ if (dmaState == Dma_Idle)
+ panic("Inconsistent DMA state, should be Start or Transfer!");
+
+ if (devState != Transfer_Data_Dma && devState != Prepare_Data_Dma)
+ panic("Inconsistent device state, should be Transfer or Prepare!\n");
+
+ updateState(ACT_CMD_ERROR);
+}
+
+void
+IdeDisk::startCommand()
+{
+ DevAction_t action = ACT_NONE;
+ uint32_t size = 0;
+ dmaRead = false;
+
+ // Decode commands
+ switch (cmdReg.command) {
+ // Supported non-data commands
+ case WDSF_READ_NATIVE_MAX:
+ size = image->size() - 1;
+ cmdReg.sec_num = (size & 0xff);
+ cmdReg.cyl_low = ((size & 0xff00) >> 8);
+ cmdReg.cyl_high = ((size & 0xff0000) >> 16);
+ cmdReg.head = ((size & 0xf000000) >> 24);
+
+ devState = Command_Execution;
+ action = ACT_CMD_COMPLETE;
+ break;
+
+ case WDCC_RECAL:
+ case WDCC_IDP:
+ case WDCC_STANDBY_IMMED:
+ case WDCC_FLUSHCACHE:
+ case WDSF_VERIFY:
+ case WDSF_SEEK:
+ case SET_FEATURES:
+ case WDCC_SETMULTI:
+ devState = Command_Execution;
+ action = ACT_CMD_COMPLETE;
+ break;
+
+ // Supported PIO data-in commands
+ case WDCC_IDENTIFY:
+ cmdBytes = cmdBytesLeft = sizeof(struct ataparams);
+ devState = Prepare_Data_In;
+ action = ACT_DATA_READY;
+ break;
+
+ case WDCC_READMULTI:
+ case WDCC_READ:
+ if (!(cmdReg.drive & DRIVE_LBA_BIT))
+ panic("Attempt to perform CHS access, only supports LBA\n");
+
+ if (cmdReg.sec_count == 0)
+ cmdBytes = cmdBytesLeft = (256 * SectorSize);
+ else
+ cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
+
+ curSector = getLBABase();
+
+ /** @todo make this a scheduled event to simulate disk delay */
+ devState = Prepare_Data_In;
+ action = ACT_DATA_READY;
+ break;
+
+ // Supported PIO data-out commands
+ case WDCC_WRITEMULTI:
+ case WDCC_WRITE:
+ if (!(cmdReg.drive & DRIVE_LBA_BIT))
+ panic("Attempt to perform CHS access, only supports LBA\n");
+
+ if (cmdReg.sec_count == 0)
+ cmdBytes = cmdBytesLeft = (256 * SectorSize);
+ else
+ cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
+
+ curSector = getLBABase();
+
+ devState = Prepare_Data_Out;
+ action = ACT_DATA_READY;
+ break;
+
+ // Supported DMA commands
+ case WDCC_WRITEDMA:
+ dmaRead = true; // a write to the disk is a DMA read from memory
+ case WDCC_READDMA:
+ if (!(cmdReg.drive & DRIVE_LBA_BIT))
+ panic("Attempt to perform CHS access, only supports LBA\n");
+
+ if (cmdReg.sec_count == 0)
+ cmdBytes = cmdBytesLeft = (256 * SectorSize);
+ else
+ cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
+
+ curSector = getLBABase();
+
+ devState = Prepare_Data_Dma;
+ action = ACT_DMA_READY;
+ break;
+
+ default:
+ panic("Unsupported ATA command: %#x\n", cmdReg.command);
+ }
+
+ if (action != ACT_NONE) {
+ // set the BSY bit
+ status |= STATUS_BSY_BIT;
+ // clear the DRQ bit
+ status &= ~STATUS_DRQ_BIT;
+ // clear the DF bit
+ status &= ~STATUS_DF_BIT;
+
+ updateState(action);
+ }
+}
+
+////
+// Handle setting and clearing interrupts
+////
+
+void
+IdeDisk::intrPost()
+{
+ DPRINTF(IdeDisk, "Posting Interrupt\n");
+ if (intrPending)
+ panic("Attempt to post an interrupt with one pending\n");
+
+ intrPending = true;
+
+ // talk to controller to set interrupt
+ if (ctrl) {
+ ctrl->bmi_regs.bmis0 |= IDEINTS;
+ ctrl->intrPost();
+ }
+}
+
+void
+IdeDisk::intrClear()
+{
+ DPRINTF(IdeDisk, "Clearing Interrupt\n");
+ if (!intrPending)
+ panic("Attempt to clear a non-pending interrupt\n");
+
+ intrPending = false;
+
+ // talk to controller to clear interrupt
+ if (ctrl)
+ ctrl->intrClear();
+}
+
+////
+// Manage the device internal state machine
+////
+
+void
+IdeDisk::updateState(DevAction_t action)
+{
+ switch (devState) {
+ case Device_Srst:
+ if (action == ACT_SRST_SET) {
+ // set the BSY bit
+ status |= STATUS_BSY_BIT;
+ } else if (action == ACT_SRST_CLEAR) {
+ // clear the BSY bit
+ status &= ~STATUS_BSY_BIT;
+
+ // reset the device state
+ reset(devID);
+ }
+ break;
+
+ case Device_Idle_S:
+ if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
+ devState = Device_Idle_NS;
+ } else if (action == ACT_CMD_WRITE) {
+ startCommand();
+ }
+
+ break;
+
+ case Device_Idle_SI:
+ if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
+ devState = Device_Idle_NS;
+ intrClear();
+ } else if (action == ACT_STAT_READ || isIENSet()) {
+ devState = Device_Idle_S;
+ intrClear();
+ } else if (action == ACT_CMD_WRITE) {
+ intrClear();
+ startCommand();
+ }
+
+ break;
+
+ case Device_Idle_NS:
+ if (action == ACT_SELECT_WRITE && isDEVSelect()) {
+ if (!isIENSet() && intrPending) {
+ devState = Device_Idle_SI;
+ intrPost();
+ }
+ if (isIENSet() || !intrPending) {
+ devState = Device_Idle_S;
+ }
+ }
+ break;
+
+ case Command_Execution:
+ if (action == ACT_CMD_COMPLETE) {
+ // clear the BSY bit
+ setComplete();
+
+ if (!isIENSet()) {
+ devState = Device_Idle_SI;
+ intrPost();
+ } else {
+ devState = Device_Idle_S;
+ }
+ }
+ break;
+
+ case Prepare_Data_In:
+ if (action == ACT_CMD_ERROR) {
+ // clear the BSY bit
+ setComplete();
+
+ if (!isIENSet()) {
+ devState = Device_Idle_SI;
+ intrPost();
+ } else {
+ devState = Device_Idle_S;
+ }
+ } else if (action == ACT_DATA_READY) {
+ // clear the BSY bit
+ status &= ~STATUS_BSY_BIT;
+ // set the DRQ bit
+ status |= STATUS_DRQ_BIT;
+
+ // copy the data into the data buffer
+ if (cmdReg.command == WDCC_IDENTIFY) {
+ // Reset the drqBytes for this block
+ drqBytesLeft = sizeof(struct ataparams);
+
+ memcpy((void *)dataBuffer, (void *)&driveID,
+ sizeof(struct ataparams));
+ } else {
+ // Reset the drqBytes for this block
+ drqBytesLeft = SectorSize;
+
+ readDisk(curSector++, dataBuffer);
+ }
+
+ // put the first two bytes into the data register
+ memcpy((void *)&cmdReg.data, (void *)dataBuffer,
+ sizeof(uint16_t));
+
+ if (!isIENSet()) {
+ devState = Data_Ready_INTRQ_In;
+ intrPost();
+ } else {
+ devState = Transfer_Data_In;
+ }
+ }
+ break;
+
+ case Data_Ready_INTRQ_In:
+ if (action == ACT_STAT_READ) {
+ devState = Transfer_Data_In;
+ intrClear();
+ }
+ break;
+
+ case Transfer_Data_In:
+ if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) {
+ if (action == ACT_DATA_READ_BYTE) {
+ panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
+ } else {
+ drqBytesLeft -= 2;
+ cmdBytesLeft -= 2;
+
+ // copy next short into data registers
+ if (drqBytesLeft)
+ memcpy((void *)&cmdReg.data,
+ (void *)&dataBuffer[SectorSize - drqBytesLeft],
+ sizeof(uint16_t));
+ }
+
+ if (drqBytesLeft == 0) {
+ if (cmdBytesLeft == 0) {
+ // Clear the BSY bit
+ setComplete();
+ devState = Device_Idle_S;
+ } else {
+ devState = Prepare_Data_In;
+ // set the BSY_BIT
+ status |= STATUS_BSY_BIT;
+ // clear the DRQ_BIT
+ status &= ~STATUS_DRQ_BIT;
+
+ /** @todo change this to a scheduled event to simulate
+ disk delay */
+ updateState(ACT_DATA_READY);
+ }
+ }
+ }
+ break;
+
+ case Prepare_Data_Out:
+ if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) {
+ // clear the BSY bit
+ setComplete();
+
+ if (!isIENSet()) {
+ devState = Device_Idle_SI;
+ intrPost();
+ } else {
+ devState = Device_Idle_S;
+ }
+ } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) {
+ // clear the BSY bit
+ status &= ~STATUS_BSY_BIT;
+ // set the DRQ bit
+ status |= STATUS_DRQ_BIT;
+
+ // clear the data buffer to get it ready for writes
+ memset(dataBuffer, 0, MAX_DMA_SIZE);
+
+ // reset the drqBytes for this block
+ drqBytesLeft = SectorSize;
+
+ if (cmdBytesLeft == cmdBytes || isIENSet()) {
+ devState = Transfer_Data_Out;
+ } else {
+ devState = Data_Ready_INTRQ_Out;
+ intrPost();
+ }
+ }
+ break;
+
+ case Data_Ready_INTRQ_Out:
+ if (action == ACT_STAT_READ) {
+ devState = Transfer_Data_Out;
+ intrClear();
+ }
+ break;
+
+ case Transfer_Data_Out:
+ if (action == ACT_DATA_WRITE_BYTE ||
+ action == ACT_DATA_WRITE_SHORT) {
+
+ if (action == ACT_DATA_READ_BYTE) {
+ panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
+ } else {
+ // copy the latest short into the data buffer
+ memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft],
+ (void *)&cmdReg.data,
+ sizeof(uint16_t));
+
+ drqBytesLeft -= 2;
+ cmdBytesLeft -= 2;
+ }
+
+ if (drqBytesLeft == 0) {
+ // copy the block to the disk
+ writeDisk(curSector++, dataBuffer);
+
+ // set the BSY bit
+ status |= STATUS_BSY_BIT;
+ // set the seek bit
+ status |= STATUS_SEEK_BIT;
+ // clear the DRQ bit
+ status &= ~STATUS_DRQ_BIT;
+
+ devState = Prepare_Data_Out;
+
+ /** @todo change this to a scheduled event to simulate
+ disk delay */
+ updateState(ACT_DATA_READY);
+ }
+ }
+ break;
+
+ case Prepare_Data_Dma:
+ if (action == ACT_CMD_ERROR) {
+ // clear the BSY bit
+ setComplete();
+
+ if (!isIENSet()) {
+ devState = Device_Idle_SI;
+ intrPost();
+ } else {
+ devState = Device_Idle_S;
+ }
+ } else if (action == ACT_DMA_READY) {
+ // clear the BSY bit
+ status &= ~STATUS_BSY_BIT;
+ // set the DRQ bit
+ status |= STATUS_DRQ_BIT;
+
+ devState = Transfer_Data_Dma;
+
+ if (dmaState != Dma_Idle)
+ panic("Inconsistent DMA state, should be Dma_Idle\n");
+
+ dmaState = Dma_Start;
+ // wait for the write to the DMA start bit
+ }
+ break;
+
+ case Transfer_Data_Dma:
+ if (action == ACT_CMD_ERROR || action == ACT_DMA_DONE) {
+ // clear the BSY bit
+ setComplete();
+ // set the seek bit
+ status |= STATUS_SEEK_BIT;
+ // clear the controller state for DMA transfer
+ ctrl->setDmaComplete(this);
+
+ if (!isIENSet()) {
+ devState = Device_Idle_SI;
+ intrPost();
+ } else {
+ devState = Device_Idle_S;
+ }
+ }
+ break;
+
+ default:
+ panic("Unknown IDE device state: %#x\n", devState);
+ }
+}
+
+void
+IdeDisk::serialize(ostream &os)
+{
+ // Check all outstanding events to see if they are scheduled
+ // these are all mutually exclusive
+ Tick reschedule = 0;
+ Events_t event = None;
+
+ int eventCount = 0;
+
+ if (dmaTransferEvent.scheduled()) {
+ reschedule = dmaTransferEvent.when();
+ event = Transfer;
+ eventCount++;
+ }
+ if (dmaReadWaitEvent.scheduled()) {
+ reschedule = dmaReadWaitEvent.when();
+ event = ReadWait;
+ eventCount++;
+ }
+ if (dmaWriteWaitEvent.scheduled()) {
+ reschedule = dmaWriteWaitEvent.when();
+ event = WriteWait;
+ eventCount++;
+ }
+ if (dmaPrdReadEvent.scheduled()) {
+ reschedule = dmaPrdReadEvent.when();
+ event = PrdRead;
+ eventCount++;
+ }
+ if (dmaReadEvent.scheduled()) {
+ reschedule = dmaReadEvent.when();
+ event = DmaRead;
+ eventCount++;
+ }
+ if (dmaWriteEvent.scheduled()) {
+ reschedule = dmaWriteEvent.when();
+ event = DmaWrite;
+ eventCount++;
+ }
+
+ assert(eventCount <= 1);
+
+ SERIALIZE_SCALAR(reschedule);
+ SERIALIZE_ENUM(event);
+
+ // Serialize device registers
+ SERIALIZE_SCALAR(cmdReg.data);
+ SERIALIZE_SCALAR(cmdReg.sec_count);
+ SERIALIZE_SCALAR(cmdReg.sec_num);
+ SERIALIZE_SCALAR(cmdReg.cyl_low);
+ SERIALIZE_SCALAR(cmdReg.cyl_high);
+ SERIALIZE_SCALAR(cmdReg.drive);
+ SERIALIZE_SCALAR(cmdReg.command);
+ SERIALIZE_SCALAR(status);
+ SERIALIZE_SCALAR(nIENBit);
+ SERIALIZE_SCALAR(devID);
+
+ // Serialize the PRD related information
+ SERIALIZE_SCALAR(curPrd.entry.baseAddr);
+ SERIALIZE_SCALAR(curPrd.entry.byteCount);
+ SERIALIZE_SCALAR(curPrd.entry.endOfTable);
+ SERIALIZE_SCALAR(curPrdAddr);
+
+ /** @todo need to serialized chunk generator stuff!! */
+ // Serialize current transfer related information
+ SERIALIZE_SCALAR(cmdBytesLeft);
+ SERIALIZE_SCALAR(cmdBytes);
+ SERIALIZE_SCALAR(drqBytesLeft);
+ SERIALIZE_SCALAR(curSector);
+ SERIALIZE_SCALAR(dmaRead);
+ SERIALIZE_SCALAR(intrPending);
+ SERIALIZE_ENUM(devState);
+ SERIALIZE_ENUM(dmaState);
+ SERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
+}
+
+void
+IdeDisk::unserialize(Checkpoint *cp, const string &section)
+{
+ // Reschedule events that were outstanding
+ // these are all mutually exclusive
+ Tick reschedule = 0;
+ Events_t event = None;
+
+ UNSERIALIZE_SCALAR(reschedule);
+ UNSERIALIZE_ENUM(event);
+
+ switch (event) {
+ case None : break;
+ case Transfer : dmaTransferEvent.schedule(reschedule); break;
+ case ReadWait : dmaReadWaitEvent.schedule(reschedule); break;
+ case WriteWait : dmaWriteWaitEvent.schedule(reschedule); break;
+ case PrdRead : dmaPrdReadEvent.schedule(reschedule); break;
+ case DmaRead : dmaReadEvent.schedule(reschedule); break;
+ case DmaWrite : dmaWriteEvent.schedule(reschedule); break;
+ }
+
+ // Unserialize device registers
+ UNSERIALIZE_SCALAR(cmdReg.data);
+ UNSERIALIZE_SCALAR(cmdReg.sec_count);
+ UNSERIALIZE_SCALAR(cmdReg.sec_num);
+ UNSERIALIZE_SCALAR(cmdReg.cyl_low);
+ UNSERIALIZE_SCALAR(cmdReg.cyl_high);
+ UNSERIALIZE_SCALAR(cmdReg.drive);
+ UNSERIALIZE_SCALAR(cmdReg.command);
+ UNSERIALIZE_SCALAR(status);
+ UNSERIALIZE_SCALAR(nIENBit);
+ UNSERIALIZE_SCALAR(devID);
+
+ // Unserialize the PRD related information
+ UNSERIALIZE_SCALAR(curPrd.entry.baseAddr);
+ UNSERIALIZE_SCALAR(curPrd.entry.byteCount);
+ UNSERIALIZE_SCALAR(curPrd.entry.endOfTable);
+ UNSERIALIZE_SCALAR(curPrdAddr);
+
+ /** @todo need to serialized chunk generator stuff!! */
+ // Unserialize current transfer related information
+ UNSERIALIZE_SCALAR(cmdBytes);
+ UNSERIALIZE_SCALAR(cmdBytesLeft);
+ UNSERIALIZE_SCALAR(drqBytesLeft);
+ UNSERIALIZE_SCALAR(curSector);
+ UNSERIALIZE_SCALAR(dmaRead);
+ UNSERIALIZE_SCALAR(intrPending);
+ UNSERIALIZE_ENUM(devState);
+ UNSERIALIZE_ENUM(dmaState);
+ UNSERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
+}
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+enum DriveID { master, slave };
+static const char *DriveID_strings[] = { "master", "slave" };
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeDisk)
+
+ SimObjectParam<DiskImage *> image;
+ SimpleEnumParam<DriveID> driveID;
+ Param<int> delay;
+
+END_DECLARE_SIM_OBJECT_PARAMS(IdeDisk)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(IdeDisk)
+
+ INIT_PARAM(image, "Disk image"),
+ INIT_ENUM_PARAM(driveID, "Drive ID (0=master 1=slave)", DriveID_strings),
+ INIT_PARAM_DFLT(delay, "Fixed disk delay in microseconds", 1)
+
+END_INIT_SIM_OBJECT_PARAMS(IdeDisk)
+
+
+CREATE_SIM_OBJECT(IdeDisk)
+{
+ return new IdeDisk(getInstanceName(), image, driveID, delay);
+}
+
+REGISTER_SIM_OBJECT("IdeDisk", IdeDisk)
+
+#endif //DOXYGEN_SHOULD_SKIP_THIS
diff --git a/src/dev/ide_disk.hh b/src/dev/ide_disk.hh
new file mode 100644
index 000000000..5379e5e73
--- /dev/null
+++ b/src/dev/ide_disk.hh
@@ -0,0 +1,367 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * Device model for an IDE disk
+ */
+
+#ifndef __IDE_DISK_HH__
+#define __IDE_DISK_HH__
+
+#include "base/statistics.hh"
+#include "dev/disk_image.hh"
+#include "dev/ide_atareg.h"
+#include "dev/ide_ctrl.hh"
+#include "dev/ide_wdcreg.h"
+#include "dev/io_device.hh"
+#include "sim/eventq.hh"
+
+#define DMA_BACKOFF_PERIOD 200
+
+#define MAX_DMA_SIZE (131072) // 128K
+#define MAX_MULTSECT (128)
+
+#define PRD_BASE_MASK 0xfffffffe
+#define PRD_COUNT_MASK 0xfffe
+#define PRD_EOT_MASK 0x8000
+
+typedef struct PrdEntry {
+ uint32_t baseAddr;
+ uint16_t byteCount;
+ uint16_t endOfTable;
+} PrdEntry_t;
+
+class PrdTableEntry {
+ public:
+ PrdEntry_t entry;
+
+ uint32_t getBaseAddr()
+ {
+ return (entry.baseAddr & PRD_BASE_MASK);
+ }
+
+ uint32_t getByteCount()
+ {
+ return ((entry.byteCount == 0) ? MAX_DMA_SIZE :
+ (entry.byteCount & PRD_COUNT_MASK));
+ }
+
+ uint16_t getEOT()
+ {
+ return (entry.endOfTable & PRD_EOT_MASK);
+ }
+};
+
+#define DATA_OFFSET (0)
+#define ERROR_OFFSET (1)
+#define FEATURES_OFFSET (1)
+#define NSECTOR_OFFSET (2)
+#define SECTOR_OFFSET (3)
+#define LCYL_OFFSET (4)
+#define HCYL_OFFSET (5)
+#define SELECT_OFFSET (6)
+#define DRIVE_OFFSET (6)
+#define STATUS_OFFSET (7)
+#define COMMAND_OFFSET (7)
+
+#define CONTROL_OFFSET (2)
+#define ALTSTAT_OFFSET (2)
+
+#define SELECT_DEV_BIT 0x10
+#define CONTROL_RST_BIT 0x04
+#define CONTROL_IEN_BIT 0x02
+#define STATUS_BSY_BIT 0x80
+#define STATUS_DRDY_BIT 0x40
+#define STATUS_DRQ_BIT 0x08
+#define STATUS_SEEK_BIT 0x10
+#define STATUS_DF_BIT 0x20
+#define DRIVE_LBA_BIT 0x40
+
+#define DEV0 (0)
+#define DEV1 (1)
+
+typedef struct CommandReg {
+ uint16_t data;
+ uint8_t error;
+ uint8_t sec_count;
+ uint8_t sec_num;
+ uint8_t cyl_low;
+ uint8_t cyl_high;
+ union {
+ uint8_t drive;
+ uint8_t head;
+ };
+ uint8_t command;
+} CommandReg_t;
+
+typedef enum Events {
+ None = 0,
+ Transfer,
+ ReadWait,
+ WriteWait,
+ PrdRead,
+ DmaRead,
+ DmaWrite
+} Events_t;
+
+typedef enum DevAction {
+ ACT_NONE = 0,
+ ACT_CMD_WRITE,
+ ACT_CMD_COMPLETE,
+ ACT_CMD_ERROR,
+ ACT_SELECT_WRITE,
+ ACT_STAT_READ,
+ ACT_DATA_READY,
+ ACT_DATA_READ_BYTE,
+ ACT_DATA_READ_SHORT,
+ ACT_DATA_WRITE_BYTE,
+ ACT_DATA_WRITE_SHORT,
+ ACT_DMA_READY,
+ ACT_DMA_DONE,
+ ACT_SRST_SET,
+ ACT_SRST_CLEAR
+} DevAction_t;
+
+typedef enum DevState {
+ // Device idle
+ Device_Idle_S = 0,
+ Device_Idle_SI,
+ Device_Idle_NS,
+
+ // Software reset
+ Device_Srst,
+
+ // Non-data commands
+ Command_Execution,
+
+ // PIO data-in (data to host)
+ Prepare_Data_In,
+ Data_Ready_INTRQ_In,
+ Transfer_Data_In,
+
+ // PIO data-out (data from host)
+ Prepare_Data_Out,
+ Data_Ready_INTRQ_Out,
+ Transfer_Data_Out,
+
+ // DMA protocol
+ Prepare_Data_Dma,
+ Transfer_Data_Dma
+} DevState_t;
+
+typedef enum DmaState {
+ Dma_Idle = 0,
+ Dma_Start,
+ Dma_Transfer
+} DmaState_t;
+
+class PhysicalMemory;
+class IdeController;
+
+/**
+ * IDE Disk device model
+ */
+class IdeDisk : public SimObject
+{
+ protected:
+ /** The IDE controller for this disk. */
+ IdeController *ctrl;
+ /** The image that contains the data of this disk. */
+ DiskImage *image;
+
+ protected:
+ /** The disk delay in microseconds. */
+ int diskDelay;
+
+ private:
+ /** Drive identification structure for this disk */
+ struct ataparams driveID;
+ /** Data buffer for transfers */
+ uint8_t *dataBuffer;
+ /** Number of bytes in command data transfer */
+ uint32_t cmdBytes;
+ /** Number of bytes left in command data transfer */
+ uint32_t cmdBytesLeft;
+ /** Number of bytes left in DRQ block */
+ uint32_t drqBytesLeft;
+ /** Current sector in access */
+ uint32_t curSector;
+ /** Command block registers */
+ CommandReg_t cmdReg;
+ /** Status register */
+ uint8_t status;
+ /** Interrupt enable bit */
+ bool nIENBit;
+ /** Device state */
+ DevState_t devState;
+ /** Dma state */
+ DmaState_t dmaState;
+ /** Dma transaction is a read */
+ bool dmaRead;
+ /** PRD table base address */
+ uint32_t curPrdAddr;
+ /** PRD entry */
+ PrdTableEntry curPrd;
+ /** Device ID (master=0/slave=1) */
+ int devID;
+ /** Interrupt pending */
+ bool intrPending;
+
+ Stats::Scalar<> dmaReadFullPages;
+ Stats::Scalar<> dmaReadBytes;
+ Stats::Scalar<> dmaReadTxs;
+ Stats::Scalar<> dmaWriteFullPages;
+ Stats::Scalar<> dmaWriteBytes;
+ Stats::Scalar<> dmaWriteTxs;
+
+ public:
+ /**
+ * Create and initialize this Disk.
+ * @param name The name of this disk.
+ * @param img The disk image of this disk.
+ * @param id The disk ID (master=0/slave=1)
+ * @param disk_delay The disk delay in milliseconds
+ */
+ IdeDisk(const std::string &name, DiskImage *img, int id, Tick disk_delay);
+
+ /**
+ * Delete the data buffer.
+ */
+ ~IdeDisk();
+
+ /**
+ * Reset the device state
+ */
+ void reset(int id);
+
+ /**
+ * Register Statistics
+ */
+ void regStats();
+
+ /**
+ * Set the controller for this device
+ * @param c The IDE controller
+ */
+ void setController(IdeController *c) {
+ if (ctrl) panic("Cannot change the controller once set!\n");
+ ctrl = c;
+ }
+
+ // Device register read/write
+ void read(const Addr &offset, IdeRegType regtype, uint8_t *data);
+ void write(const Addr &offset, IdeRegType regtype, const uint8_t *data);
+
+ // Start/abort functions
+ void startDma(const uint32_t &prdTableBase);
+ void abortDma();
+
+ private:
+ void startCommand();
+
+ // Interrupt management
+ void intrPost();
+ void intrClear();
+
+ // DMA stuff
+ void doDmaTransfer();
+ friend class EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer>;
+ EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer> dmaTransferEvent;
+
+ void doDmaDataRead();
+
+ void doDmaRead();
+ ChunkGenerator *dmaReadCG;
+ friend class EventWrapper<IdeDisk, &IdeDisk::doDmaRead>;
+ EventWrapper<IdeDisk, &IdeDisk::doDmaRead> dmaReadWaitEvent;
+
+ void doDmaDataWrite();
+
+ void doDmaWrite();
+ ChunkGenerator *dmaWriteCG;
+ friend class EventWrapper<IdeDisk, &IdeDisk::doDmaWrite>;
+ EventWrapper<IdeDisk, &IdeDisk::doDmaWrite> dmaWriteWaitEvent;
+
+ void dmaPrdReadDone();
+ friend class EventWrapper<IdeDisk, &IdeDisk::dmaPrdReadDone>;
+ EventWrapper<IdeDisk, &IdeDisk::dmaPrdReadDone> dmaPrdReadEvent;
+
+ void dmaReadDone();
+ friend class EventWrapper<IdeDisk, &IdeDisk::dmaReadDone>;
+ EventWrapper<IdeDisk, &IdeDisk::dmaReadDone> dmaReadEvent;
+
+ void dmaWriteDone();
+ friend class EventWrapper<IdeDisk, &IdeDisk::dmaWriteDone>;
+ EventWrapper<IdeDisk, &IdeDisk::dmaWriteDone> dmaWriteEvent;
+
+ // Disk image read/write
+ void readDisk(uint32_t sector, uint8_t *data);
+ void writeDisk(uint32_t sector, uint8_t *data);
+
+ // State machine management
+ void updateState(DevAction_t action);
+
+ // Utility functions
+ bool isBSYSet() { return (status & STATUS_BSY_BIT); }
+ bool isIENSet() { return nIENBit; }
+ bool isDEVSelect();
+
+ void setComplete()
+ {
+ // clear out the status byte
+ status = 0;
+ // set the DRDY bit
+ status |= STATUS_DRDY_BIT;
+ // set the SEEK bit
+ status |= STATUS_SEEK_BIT;
+ }
+
+ uint32_t getLBABase()
+ {
+ return (Addr)(((cmdReg.head & 0xf) << 24) | (cmdReg.cyl_high << 16) |
+ (cmdReg.cyl_low << 8) | (cmdReg.sec_num));
+ }
+
+ inline Addr pciToDma(Addr pciAddr);
+
+ /**
+ * Serialize this object to the given output stream.
+ * @param os The stream to serialize to.
+ */
+ void serialize(std::ostream &os);
+
+ /**
+ * Reconstruct the state of this object from a checkpoint.
+ * @param cp The checkpoint to use.
+ * @param section The section name describing this object.
+ */
+ void unserialize(Checkpoint *cp, const std::string &section);
+};
+
+
+#endif // __IDE_DISK_HH__
diff --git a/src/dev/ide_wdcreg.h b/src/dev/ide_wdcreg.h
new file mode 100644
index 000000000..ed7475ec8
--- /dev/null
+++ b/src/dev/ide_wdcreg.h
@@ -0,0 +1,197 @@
+/* $OpenBSD: wdcreg.h,v 1.13 2004/09/24 07:05:44 grange Exp $ */
+/* $NetBSD: wdcreg.h,v 1.22 1999/03/07 14:02:54 bouyer Exp $ */
+
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)wdreg.h 7.1 (Berkeley) 5/9/91
+ */
+
+#ifndef _DEV_IC_WDCREG_H_
+#define _DEV_IC_WDCREG_H_
+
+/*
+ * Controller register (wdr_ctlr)
+ */
+#define WDCTL_4BIT 0x08 /* use four head bits (wd1003) */
+#define WDCTL_RST 0x04 /* reset the controller */
+#define WDCTL_IDS 0x02 /* disable controller interrupts */
+
+/*
+ * Status bits.
+ */
+#define WDCS_BSY 0x80 /* busy */
+#define WDCS_DRDY 0x40 /* drive ready */
+#define WDCS_DWF 0x20 /* drive write fault */
+#define WDCS_DSC 0x10 /* drive seek complete */
+#define WDCS_DRQ 0x08 /* data request */
+#define WDCS_CORR 0x04 /* corrected data */
+#define WDCS_IDX 0x02 /* index */
+#define WDCS_ERR 0x01 /* error */
+#define WDCS_BITS "\020\010BSY\007DRDY\006DWF\005DSC\004DRQ\003CORR\002IDX\001ERR"
+
+/*
+ * Error bits.
+ */
+#define WDCE_BBK 0x80 /* bad block detected */
+#define WDCE_CRC 0x80 /* CRC error (Ultra-DMA only) */
+#define WDCE_UNC 0x40 /* uncorrectable data error */
+#define WDCE_MC 0x20 /* media changed */
+#define WDCE_IDNF 0x10 /* id not found */
+#define WDCE_MCR 0x08 /* media change requested */
+#define WDCE_ABRT 0x04 /* aborted command */
+#define WDCE_TK0NF 0x02 /* track 0 not found */
+#define WDCE_AMNF 0x01 /* address mark not found */
+
+/*
+ * Commands for Disk Controller.
+ */
+#define WDCC_NOP 0x00 /* NOP - Always fail with "aborted command" */
+#define WDCC_RECAL 0x10 /* disk restore code -- resets cntlr */
+
+#define WDCC_READ 0x20 /* disk read code */
+#define WDCC_WRITE 0x30 /* disk write code */
+#define WDCC__LONG 0x02 /* modifier -- access ecc bytes */
+#define WDCC__NORETRY 0x01 /* modifier -- no retrys */
+
+#define WDCC_FORMAT 0x50 /* disk format code */
+#define WDCC_DIAGNOSE 0x90 /* controller diagnostic */
+#define WDCC_IDP 0x91 /* initialize drive parameters */
+
+#define WDCC_READMULTI 0xc4 /* read multiple */
+#define WDCC_WRITEMULTI 0xc5 /* write multiple */
+#define WDCC_SETMULTI 0xc6 /* set multiple mode */
+
+#define WDCC_READDMA 0xc8 /* read with DMA */
+#define WDCC_WRITEDMA 0xca /* write with DMA */
+
+#define WDCC_ACKMC 0xdb /* acknowledge media change */
+#define WDCC_LOCK 0xde /* lock drawer */
+#define WDCC_UNLOCK 0xdf /* unlock drawer */
+
+#define WDCC_FLUSHCACHE 0xe7 /* Flush cache */
+#define WDCC_IDENTIFY 0xec /* read parameters from controller */
+#define SET_FEATURES 0xef /* set features */
+
+#define WDCC_IDLE 0xe3 /* set idle timer & enter idle mode */
+#define WDCC_IDLE_IMMED 0xe1 /* enter idle mode */
+#define WDCC_SLEEP 0xe6 /* enter sleep mode */
+#define WDCC_STANDBY 0xe2 /* set standby timer & enter standby mode */
+#define WDCC_STANDBY_IMMED 0xe0 /* enter standby mode */
+#define WDCC_CHECK_PWR 0xe5 /* check power mode */
+
+#define WDCC_READ_EXT 0x24 /* read 48-bit addressing */
+#define WDCC_WRITE_EXT 0x34 /* write 48-bit addressing */
+
+#define WDCC_READMULTI_EXT 0x29 /* read multiple 48-bit addressing */
+#define WDCC_WRITEMULTI_EXT 0x39 /* write multiple 48-bit addressing */
+
+#define WDCC_READDMA_EXT 0x25 /* read 48-bit addressing with DMA */
+#define WDCC_WRITEDMA_EXT 0x35 /* write 48-bit addressing with DMA */
+
+#define WDCC_FLUSHCACHE_EXT 0xea /* 48-bit addressing flush cache */
+
+/* Subcommands for SET_FEATURES (features register ) */
+#define WDSF_8BIT_PIO_EN 0x01 /* Enable 8bit PIO (CFA featureset) */
+#define WDSF_EN_WR_CACHE 0x02
+#define WDSF_SET_MODE 0x03
+#define WDSF_REASSIGN_EN 0x04 /* Obsolete in ATA-6 */
+#define WDSF_APM_EN 0x05 /* Enable Adv. Power Management */
+#define WDSF_PUIS_EN 0x06 /* Enable Power-Up In Standby */
+#define WDSF_PUIS_SPINUP 0x07 /* Power-Up In Standby spin-up */
+#define WDSF_CFA_MODE1_EN 0x0A /* Enable CFA power mode 1 */
+#define WDSF_RMSN_DS 0x31 /* Disable Removable Media Status */
+#define WDSF_RETRY_DS 0x33 /* Obsolete in ATA-6 */
+#define WDSF_AAM_EN 0x42 /* Enable Autom. Acoustic Management */
+#define WDSF_SET_CACHE_SGMT 0x54 /* Obsolete in ATA-6 */
+#define WDSF_READAHEAD_DS 0x55 /* Disable read look-ahead */
+#define WDSF_RLSE_EN 0x5D /* Enable release interrupt */
+#define WDSF_SRV_EN 0x5E /* Enable SERVICE interrupt */
+#define WDSF_POD_DS 0x66
+#define WDSF_ECC_DS 0x77
+#define WDSF_8BIT_PIO_DS 0x81 /* Disable 8bit PIO (CFA featureset) */
+#define WDSF_WRITE_CACHE_DS 0x82
+#define WDSF_REASSIGN_DS 0x84
+#define WDSF_APM_DS 0x85 /* Disable Adv. Power Management */
+#define WDSF_PUIS_DS 0x86 /* Disable Power-Up In Standby */
+#define WDSF_ECC_EN 0x88
+#define WDSF_CFA_MODE1_DS 0x8A /* Disable CFA power mode 1 */
+#define WDSF_RMSN_EN 0x95 /* Enable Removable Media Status */
+#define WDSF_RETRY_EN 0x99 /* Obsolete in ATA-6 */
+#define WDSF_SET_CURRENT 0x9A /* Obsolete in ATA-6 */
+#define WDSF_READAHEAD_EN 0xAA
+#define WDSF_PREFETCH_SET 0xAB /* Obsolete in ATA-6 */
+#define WDSF_AAM_DS 0xC2 /* Disable Autom. Acoustic Management */
+#define WDSF_POD_EN 0xCC
+#define WDSF_RLSE_DS 0xDD /* Disable release interrupt */
+#define WDSF_SRV_DS 0xDE /* Disable SERVICE interrupt */
+#define WDSF_READ_NATIVE_MAX 0xF8
+#define WDSF_SEEK 0x70
+#define WDSF_VERIFY 0x40
+
+/* parameters uploaded to device/heads register */
+#define WDSD_IBM 0xa0 /* forced to 512 byte sector, ecc */
+#define WDSD_CHS 0x00 /* cylinder/head/sector addressing */
+#define WDSD_LBA 0x40 /* logical block addressing */
+
+/* Commands for ATAPI devices */
+#define ATAPI_CHECK_POWER_MODE 0xe5
+#define ATAPI_EXEC_DRIVE_DIAGS 0x90
+#define ATAPI_IDLE_IMMEDIATE 0xe1
+#define ATAPI_NOP 0x00
+#define ATAPI_PKT_CMD 0xa0
+#define ATAPI_IDENTIFY_DEVICE 0xa1
+#define ATAPI_SOFT_RESET 0x08
+#define ATAPI_DEVICE_RESET 0x08 /* ATA/ATAPI-5 name for soft reset */
+#define ATAPI_SLEEP 0xe6
+#define ATAPI_STANDBY_IMMEDIATE 0xe0
+#define ATAPI_SMART 0xB0 /* SMART operations */
+#define ATAPI_SETMAX 0xF9 /* Set Max Address */
+#define ATAPI_WRITEEXT 0x34 /* Write sectors Ext */
+#define ATAPI_SETMAXEXT 0x37 /* Set Max Address Ext */
+#define ATAPI_WRITEMULTIEXT 0x39 /* Write Multi Ext */
+
+/* Bytes used by ATAPI_PACKET_COMMAND ( feature register) */
+#define ATAPI_PKT_CMD_FTRE_DMA 0x01
+#define ATAPI_PKT_CMD_FTRE_OVL 0x02
+
+/* ireason */
+#define WDCI_CMD 0x01 /* command(1) or data(0) */
+#define WDCI_IN 0x02 /* transfer to(1) or from(0) the host */
+#define WDCI_RELEASE 0x04 /* bus released until completion */
+
+#define PHASE_CMDOUT (WDCS_DRQ | WDCI_CMD)
+#define PHASE_DATAIN (WDCS_DRQ | WDCI_IN)
+#define PHASE_DATAOUT WDCS_DRQ
+#define PHASE_COMPLETED (WDCI_IN | WDCI_CMD)
+#define PHASE_ABORTED 0
+
+#endif /* !_DEV_IC_WDCREG_H_ */
diff --git a/src/dev/io_device.cc b/src/dev/io_device.cc
new file mode 100644
index 000000000..634b11b7e
--- /dev/null
+++ b/src/dev/io_device.cc
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "dev/io_device.hh"
+#include "sim/builder.hh"
+
+
+PioPort::PioPort(PioDevice *dev, Platform *p)
+ : device(dev), platform(p)
+{ }
+
+
+Tick
+PioPort::recvAtomic(Packet *pkt)
+{
+ return device->recvAtomic(pkt);
+}
+
+void
+PioPort::recvFunctional(Packet *pkt)
+{
+ device->recvAtomic(pkt);
+}
+
+void
+PioPort::getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
+{
+ snoop.clear();
+ device->addressRanges(resp);
+}
+
+
+Packet *
+PioPort::recvRetry()
+{
+ Packet* pkt = transmitList.front();
+ transmitList.pop_front();
+ return pkt;
+}
+
+
+void
+PioPort::SendEvent::process()
+{
+ if (port->Port::sendTiming(packet) == Success)
+ return;
+
+ port->transmitList.push_back(packet);
+}
+
+
+bool
+PioPort::recvTiming(Packet *pkt)
+{
+ device->recvAtomic(pkt);
+ sendTiming(pkt, pkt->time - pkt->req->getTime());
+ return Success;
+}
+
+PioDevice::~PioDevice()
+{
+ if (pioPort)
+ delete pioPort;
+}
+
+void
+PioDevice::init()
+{
+ if (!pioPort)
+ panic("Pio port not connected to anything!");
+ pioPort->sendStatusChange(Port::RangeChange);
+}
+
+void
+BasicPioDevice::addressRanges(AddrRangeList &range_list)
+{
+ assert(pioSize != 0);
+ range_list.clear();
+ range_list.push_back(RangeSize(pioAddr, pioSize));
+}
+
+
+DmaPort::DmaPort(DmaDevice *dev, Platform *p)
+ : device(dev), platform(p), pendingCount(0)
+{ }
+
+bool
+DmaPort::recvTiming(Packet *pkt)
+{
+ if (pkt->senderState) {
+ DmaReqState *state;
+ state = (DmaReqState*)pkt->senderState;
+ state->completionEvent->schedule(pkt->time - pkt->req->getTime());
+ delete pkt->req;
+ delete pkt;
+ } else {
+ delete pkt->req;
+ delete pkt;
+ }
+
+ return Success;
+}
+
+DmaDevice::DmaDevice(Params *p)
+ : PioDevice(p), dmaPort(NULL)
+{ }
+
+void
+DmaPort::SendEvent::process()
+{
+ if (port->Port::sendTiming(packet) == Success)
+ return;
+
+ port->transmitList.push_back(packet);
+}
+
+Packet *
+DmaPort::recvRetry()
+{
+ Packet* pkt = transmitList.front();
+ transmitList.pop_front();
+ return pkt;
+}
+void
+DmaPort::dmaAction(Command cmd, Addr addr, int size, Event *event,
+ uint8_t *data)
+{
+
+ assert(event);
+
+ int prevSize = 0;
+ Packet basePkt;
+ Request baseReq(false);
+
+ basePkt.flags = 0;
+ basePkt.coherence = NULL;
+ basePkt.senderState = NULL;
+ basePkt.dest = Packet::Broadcast;
+ basePkt.cmd = cmd;
+ basePkt.result = Unknown;
+ basePkt.req = NULL;
+// baseReq.nicReq = true;
+ baseReq.setTime(curTick);
+
+ for (ChunkGenerator gen(addr, size, peerBlockSize());
+ !gen.done(); gen.next()) {
+ Packet *pkt = new Packet(basePkt);
+ Request *req = new Request(baseReq);
+ pkt->addr = gen.addr();
+ pkt->size = gen.size();
+ pkt->req = req;
+ pkt->req->setPaddr(pkt->addr);
+ pkt->req->setSize(pkt->size);
+ // Increment the data pointer on a write
+ if (data)
+ pkt->dataStatic(data + prevSize) ;
+ prevSize += pkt->size;
+ // Set the last bit of the dma as the final packet for this dma
+ // and set it's completion event.
+ if (prevSize == size) {
+ DmaReqState *state = new DmaReqState(event, true);
+
+ pkt->senderState = (void*)state;
+ }
+ assert(pendingCount >= 0);
+ pendingCount++;
+ sendDma(pkt);
+ }
+ // since this isn't getting used and we want a check to make sure that all
+ // packets had data in them at some point.
+ basePkt.dataStatic((uint8_t*)NULL);
+}
+
+
+void
+DmaPort::sendDma(Packet *pkt)
+{
+ // some kind of selction between access methods
+ // more work is going to have to be done to make
+ // switching actually work
+ /* MemState state = device->platform->system->memState;
+
+ if (state == Timing) {
+ if (sendTiming(pkt) == Failure)
+ transmitList.push_back(&packet);
+ } else if (state == Atomic) {*/
+ sendAtomic(pkt);
+ if (pkt->senderState) {
+ DmaReqState *state = (DmaReqState*)pkt->senderState;
+ state->completionEvent->schedule(curTick + (pkt->time - pkt->req->getTime()) +1);
+ }
+ pendingCount--;
+ assert(pendingCount >= 0);
+ delete pkt->req;
+ delete pkt;
+
+/* } else if (state == Functional) {
+ sendFunctional(pkt);
+ // Is this correct???
+ completionEvent->schedule(pkt->req->responseTime - pkt->req->requestTime);
+ completionEvent == NULL;
+ } else
+ panic("Unknown memory command state.");
+ */
+}
+
+DmaDevice::~DmaDevice()
+{
+ if (dmaPort)
+ delete dmaPort;
+}
+
+
diff --git a/src/dev/io_device.hh b/src/dev/io_device.hh
new file mode 100644
index 000000000..6efa9ef63
--- /dev/null
+++ b/src/dev/io_device.hh
@@ -0,0 +1,335 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __DEV_IO_DEVICE_HH__
+#define __DEV_IO_DEVICE_HH__
+
+#include "base/chunk_generator.hh"
+#include "mem/mem_object.hh"
+#include "mem/packet_impl.hh"
+#include "sim/eventq.hh"
+#include "sim/sim_object.hh"
+
+class Platform;
+class PioDevice;
+class DmaDevice;
+class System;
+
+/**
+ * The PioPort class is a programmed i/o port that all devices that are
+ * sensitive to an address range use. The port takes all the memory
+ * access types and roles them into one read() and write() call that the device
+ * must respond to. The device must also provide the addressRanges() function
+ * with which it returns the address ranges it is interested in. An extra
+ * sendTiming() function is implemented which takes an delay. In this way the
+ * device can immediatly call sendTiming(pkt, time) after processing a request
+ * and the request will be handled by the port even if the port bus the device
+ * connects to is blocked.
+ */
+class PioPort : public Port
+{
+ protected:
+ /** The device that this port serves. */
+ PioDevice *device;
+
+ /** The platform that device/port are in. This is used to select which mode
+ * we are currently operating in. */
+ Platform *platform;
+
+ /** A list of outgoing timing response packets that haven't been serviced
+ * yet. */
+ std::list<Packet*> transmitList;
+
+ /** The current status of the peer(bus) that we are connected to. */
+ Status peerStatus;
+
+ virtual bool recvTiming(Packet *pkt);
+
+ virtual Tick recvAtomic(Packet *pkt);
+
+ virtual void recvFunctional(Packet *pkt) ;
+
+ virtual void recvStatusChange(Status status)
+ { peerStatus = status; }
+
+ virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop);
+
+ /**
+ * This class is used to implemented sendTiming() with a delay. When a delay
+ * is requested a new event is created. When the event time expires it
+ * attempts to send the packet. If it cannot, the packet is pushed onto the
+ * transmit list to be sent when recvRetry() is called. */
+ class SendEvent : public Event
+ {
+ PioPort *port;
+ Packet *packet;
+
+ SendEvent(PioPort *p, Packet *pkt, Tick t)
+ : Event(&mainEventQueue), port(p), packet(pkt)
+ { schedule(curTick + t); }
+
+ virtual void process();
+
+ virtual const char *description()
+ { return "Future scheduled sendTiming event"; }
+
+ friend class PioPort;
+ };
+
+ /** Schedule a sendTiming() event to be called in the future. */
+ void sendTiming(Packet *pkt, Tick time)
+ { new PioPort::SendEvent(this, pkt, time); }
+
+ /** This function pops the last element off the transmit list and sends it.*/
+ virtual Packet *recvRetry();
+
+ public:
+ PioPort(PioDevice *dev, Platform *p);
+
+ friend class PioPort::SendEvent;
+};
+
+
+struct DmaReqState
+{
+ Event *completionEvent;
+ bool final;
+ DmaReqState(Event *ce, bool f)
+ : completionEvent(ce), final(f)
+ {}
+};
+
+class DmaPort : public Port
+{
+ protected:
+ DmaDevice *device;
+ std::list<Packet*> transmitList;
+
+ /** The platform that device/port are in. This is used to select which mode
+ * we are currently operating in. */
+ Platform *platform;
+
+ /** Number of outstanding packets the dma port has. */
+ int pendingCount;
+
+ virtual bool recvTiming(Packet *pkt);
+ virtual Tick recvAtomic(Packet *pkt)
+ { panic("dma port shouldn't be used for pio access."); }
+ virtual void recvFunctional(Packet *pkt)
+ { panic("dma port shouldn't be used for pio access."); }
+
+ virtual void recvStatusChange(Status status)
+ { ; }
+
+ virtual Packet *recvRetry() ;
+
+ virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
+ { resp.clear(); snoop.clear(); }
+
+ class SendEvent : public Event
+ {
+ DmaPort *port;
+ Packet *packet;
+
+ SendEvent(PioPort *p, Packet *pkt, Tick t)
+ : Event(&mainEventQueue), packet(pkt)
+ { schedule(curTick + t); }
+
+ virtual void process();
+
+ virtual const char *description()
+ { return "Future scheduled sendTiming event"; }
+
+ friend class DmaPort;
+ };
+
+ void sendDma(Packet *pkt);
+
+ public:
+ DmaPort(DmaDevice *dev, Platform *p);
+
+ void dmaAction(Command cmd, Addr addr, int size, Event *event,
+ uint8_t *data = NULL);
+
+ bool dmaPending() { return pendingCount > 0; }
+
+ friend class DmaPort::SendEvent;
+
+};
+
+/**
+ * This device is the base class which all devices senstive to an address range
+ * inherit from. There are three pure virtual functions which all devices must
+ * implement addressRanges(), read(), and write(). The magic do choose which
+ * mode we are in, etc is handled by the PioPort so the device doesn't have to
+ * bother.
+ */
+
+class PioDevice : public MemObject
+{
+ protected:
+
+ /** The platform we are in. This is used to decide what type of memory
+ * transaction we should perform. */
+ Platform *platform;
+
+ /** The pioPort that handles the requests for us and provides us requests
+ * that it sees. */
+ PioPort *pioPort;
+
+ virtual void addressRanges(AddrRangeList &range_list) = 0;
+
+ /** As far as the devices are concerned they only accept atomic transactions
+ * which are converted to either a write or a read. */
+ Tick recvAtomic(Packet *pkt)
+ { return pkt->cmd == Read ? this->read(pkt) : this->write(pkt); }
+
+ /** Pure virtual function that the device must implement. Called when a read
+ * command is recieved by the port.
+ * @param pkt Packet describing this request
+ * @return number of ticks it took to complete
+ */
+ virtual Tick read(Packet *pkt) = 0;
+
+ /** Pure virtual function that the device must implement. Called when a
+ * write command is recieved by the port.
+ * @param pkt Packet describing this request
+ * @return number of ticks it took to complete
+ */
+ virtual Tick write(Packet *pkt) = 0;
+
+ public:
+ /** Params struct which is extended through each device based on the
+ * parameters it needs. Since we are re-writing everything, we might as well
+ * start from the bottom this time. */
+
+ struct Params
+ {
+ std::string name;
+ Platform *platform;
+ System *system;
+ };
+
+ protected:
+ Params *_params;
+
+ public:
+ const Params *params() const { return _params; }
+
+ PioDevice(Params *p)
+ : MemObject(p->name), platform(p->platform), pioPort(NULL),
+ _params(p)
+ {}
+
+ virtual ~PioDevice();
+
+ virtual void init();
+
+ virtual Port *getPort(const std::string &if_name)
+ {
+ if (if_name == "pio") {
+ if (pioPort != NULL)
+ panic("pio port already connected to.");
+ pioPort = new PioPort(this, params()->platform);
+ return pioPort;
+ } else
+ return NULL;
+ }
+ friend class PioPort;
+
+};
+
+class BasicPioDevice : public PioDevice
+{
+ public:
+ struct Params : public PioDevice::Params
+ {
+ Addr pio_addr;
+ Tick pio_delay;
+ };
+
+ protected:
+ /** Address that the device listens to. */
+ Addr pioAddr;
+
+ /** Size that the device's address range. */
+ Addr pioSize;
+
+ /** Delay that the device experinces on an access. */
+ Tick pioDelay;
+
+ public:
+ BasicPioDevice(Params *p)
+ : PioDevice(p), pioAddr(p->pio_addr), pioSize(0), pioDelay(p->pio_delay)
+ {}
+
+ /** return the address ranges that this device responds to.
+ * @params range_list range list to populate with ranges
+ */
+ void addressRanges(AddrRangeList &range_list);
+
+};
+
+class DmaDevice : public PioDevice
+{
+ protected:
+ DmaPort *dmaPort;
+
+ public:
+ DmaDevice(Params *p);
+ virtual ~DmaDevice();
+
+ void dmaWrite(Addr addr, int size, Event *event, uint8_t *data)
+ { dmaPort->dmaAction(Write, addr, size, event, data) ; }
+
+ void dmaRead(Addr addr, int size, Event *event, uint8_t *data = NULL)
+ { dmaPort->dmaAction(Read, addr, size, event, data); }
+
+ bool dmaPending() { return dmaPort->dmaPending(); }
+
+ virtual Port *getPort(const std::string &if_name)
+ {
+ if (if_name == "pio") {
+ if (pioPort != NULL)
+ panic("pio port already connected to.");
+ pioPort = new PioPort(this, params()->platform);
+ return pioPort;
+ } else if (if_name == "dma") {
+ if (dmaPort != NULL)
+ panic("dma port already connected to.");
+ dmaPort = new DmaPort(this, params()->platform);
+ return dmaPort;
+ } else
+ return NULL;
+ }
+
+ friend class DmaPort;
+};
+
+
+#endif // __DEV_IO_DEVICE_HH__
diff --git a/src/dev/isa_fake.cc b/src/dev/isa_fake.cc
new file mode 100644
index 000000000..9717226b7
--- /dev/null
+++ b/src/dev/isa_fake.cc
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * Isa Fake Device implementation
+ */
+
+#include <deque>
+#include <string>
+#include <vector>
+
+#include "base/trace.hh"
+#include "dev/isa_fake.hh"
+#include "mem/packet.hh"
+#include "sim/builder.hh"
+#include "sim/system.hh"
+
+using namespace std;
+
+IsaFake::IsaFake(Params *p)
+ : BasicPioDevice(p)
+{
+ pioSize = p->pio_size;
+}
+
+Tick
+IsaFake::read(Packet *pkt)
+{
+ assert(pkt->result == Unknown);
+ assert(pkt->addr >= pioAddr && pkt->addr < pioAddr + pioSize);
+
+ pkt->time += pioDelay;
+
+ DPRINTF(Tsunami, "read va=%#x size=%d\n", pkt->addr, pkt->size);
+
+ switch (pkt->size) {
+ pkt->set(0xFFFFFFFFFFFFFFFFULL);
+ break;
+ case sizeof(uint32_t):
+ pkt->set((uint32_t)0xFFFFFFFF);
+ break;
+ case sizeof(uint16_t):
+ pkt->set((uint16_t)0xFFFF);
+ break;
+ case sizeof(uint8_t):
+ pkt->set((uint8_t)0xFF);
+ break;
+ default:
+ panic("invalid access size(?) for PCI configspace!\n");
+ }
+ pkt->result = Success;
+ return pioDelay;
+}
+
+Tick
+IsaFake::write(Packet *pkt)
+{
+ pkt->time += pioDelay;
+ DPRINTF(Tsunami, "write - va=%#x size=%d \n", pkt->addr, pkt->size);
+ pkt->result = Success;
+ return pioDelay;
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(IsaFake)
+
+ Param<Addr> pio_addr;
+ Param<Tick> pio_latency;
+ Param<Addr> pio_size;
+ SimObjectParam<Platform *> platform;
+ SimObjectParam<System *> system;
+
+END_DECLARE_SIM_OBJECT_PARAMS(IsaFake)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(IsaFake)
+
+ INIT_PARAM(pio_addr, "Device Address"),
+ INIT_PARAM(pio_latency, "Programmed IO latency"),
+ INIT_PARAM(pio_size, "Size of address range"),
+ INIT_PARAM(platform, "platform"),
+ INIT_PARAM(system, "system object")
+
+END_INIT_SIM_OBJECT_PARAMS(IsaFake)
+
+CREATE_SIM_OBJECT(IsaFake)
+{
+ IsaFake::Params *p = new IsaFake::Params;
+ p->name = getInstanceName();
+ p->pio_addr = pio_addr;
+ p->pio_delay = pio_latency;
+ p->pio_size = pio_size;
+ p->platform = platform;
+ p->system = system;
+ return new IsaFake(p);
+}
+
+REGISTER_SIM_OBJECT("IsaFake", IsaFake)
diff --git a/src/dev/isa_fake.hh b/src/dev/isa_fake.hh
new file mode 100644
index 000000000..65d44f6a5
--- /dev/null
+++ b/src/dev/isa_fake.hh
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * Declaration of a fake device.
+ */
+
+#ifndef __ISA_FAKE_HH__
+#define __ISA_FAKE_HH__
+
+#include "dev/tsunami.hh"
+#include "base/range.hh"
+#include "dev/io_device.hh"
+
+/**
+ * IsaFake is a device that returns -1 on all reads and
+ * accepts all writes. It is meant to be placed at an address range
+ * so that an mcheck doesn't occur when an os probes a piece of hw
+ * that doesn't exist (e.g. UARTs1-3).
+ */
+class IsaFake : public BasicPioDevice
+{
+ public:
+ struct Params : public BasicPioDevice::Params
+ {
+ Addr pio_size;
+ };
+ protected:
+ const Params *params() const { return (const Params*)_params; }
+
+ public:
+ /**
+ * The constructor for Tsunmami Fake just registers itself with the MMU.
+ * @param p params structure
+ */
+ IsaFake(Params *p);
+
+ /**
+ * This read always returns -1.
+ * @param req The memory request.
+ * @param data Where to put the data.
+ */
+ virtual Tick read(Packet *pkt);
+
+ /**
+ * All writes are simply ignored.
+ * @param req The memory request.
+ * @param data the data to not write.
+ */
+ virtual Tick write(Packet *pkt);
+};
+
+#endif // __TSUNAMI_FAKE_HH__
diff --git a/src/dev/ns_gige.cc b/src/dev/ns_gige.cc
new file mode 100644
index 000000000..5e27db58d
--- /dev/null
+++ b/src/dev/ns_gige.cc
@@ -0,0 +1,2914 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * Device module for modelling the National Semiconductor
+ * DP83820 ethernet controller. Does not support priority queueing
+ */
+#include <deque>
+#include <string>
+
+#include "arch/alpha/ev5.hh"
+#include "base/inet.hh"
+#include "cpu/exec_context.hh"
+#include "dev/etherlink.hh"
+#include "dev/ns_gige.hh"
+#include "dev/pciconfigall.hh"
+#include "mem/packet.hh"
+#include "sim/builder.hh"
+#include "sim/debug.hh"
+#include "sim/host.hh"
+#include "sim/stats.hh"
+#include "sim/system.hh"
+
+const char *NsRxStateStrings[] =
+{
+ "rxIdle",
+ "rxDescRefr",
+ "rxDescRead",
+ "rxFifoBlock",
+ "rxFragWrite",
+ "rxDescWrite",
+ "rxAdvance"
+};
+
+const char *NsTxStateStrings[] =
+{
+ "txIdle",
+ "txDescRefr",
+ "txDescRead",
+ "txFifoBlock",
+ "txFragRead",
+ "txDescWrite",
+ "txAdvance"
+};
+
+const char *NsDmaState[] =
+{
+ "dmaIdle",
+ "dmaReading",
+ "dmaWriting",
+ "dmaReadWaiting",
+ "dmaWriteWaiting"
+};
+
+using namespace std;
+using namespace Net;
+using namespace TheISA;
+
+///////////////////////////////////////////////////////////////////////
+//
+// NSGigE PCI Device
+//
+NSGigE::NSGigE(Params *p)
+ : PciDev(p), ioEnable(false),
+ txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size),
+ txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL),
+ txXferLen(0), rxXferLen(0), clock(p->clock),
+ txState(txIdle), txEnable(false), CTDD(false),
+ txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle),
+ rxEnable(false), CRDD(false), rxPktBytes(0),
+ rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false),
+ eepromState(eepromStart), rxDmaReadEvent(this), rxDmaWriteEvent(this),
+ txDmaReadEvent(this), txDmaWriteEvent(this),
+ dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free),
+ txDelay(p->tx_delay), rxDelay(p->rx_delay),
+ rxKickTick(0), rxKickEvent(this), txKickTick(0), txKickEvent(this),
+ txEvent(this), rxFilterEnable(p->rx_filter), acceptBroadcast(false),
+ acceptMulticast(false), acceptUnicast(false),
+ acceptPerfect(false), acceptArp(false), multicastHashEnable(false),
+ intrTick(0), cpuPendingIntr(false),
+ intrEvent(0), interface(0)
+{
+
+ intrDelay = p->intr_delay;
+ dmaReadDelay = p->dma_read_delay;
+ dmaWriteDelay = p->dma_write_delay;
+ dmaReadFactor = p->dma_read_factor;
+ dmaWriteFactor = p->dma_write_factor;
+
+ regsReset();
+ memcpy(&rom.perfectMatch, p->eaddr.bytes(), ETH_ADDR_LEN);
+
+ memset(&rxDesc32, 0, sizeof(rxDesc32));
+ memset(&txDesc32, 0, sizeof(txDesc32));
+ memset(&rxDesc64, 0, sizeof(rxDesc64));
+ memset(&txDesc64, 0, sizeof(txDesc64));
+}
+
+NSGigE::~NSGigE()
+{}
+
+void
+NSGigE::regStats()
+{
+ txBytes
+ .name(name() + ".txBytes")
+ .desc("Bytes Transmitted")
+ .prereq(txBytes)
+ ;
+
+ rxBytes
+ .name(name() + ".rxBytes")
+ .desc("Bytes Received")
+ .prereq(rxBytes)
+ ;
+
+ txPackets
+ .name(name() + ".txPackets")
+ .desc("Number of Packets Transmitted")
+ .prereq(txBytes)
+ ;
+
+ rxPackets
+ .name(name() + ".rxPackets")
+ .desc("Number of Packets Received")
+ .prereq(rxBytes)
+ ;
+
+ txIpChecksums
+ .name(name() + ".txIpChecksums")
+ .desc("Number of tx IP Checksums done by device")
+ .precision(0)
+ .prereq(txBytes)
+ ;
+
+ rxIpChecksums
+ .name(name() + ".rxIpChecksums")
+ .desc("Number of rx IP Checksums done by device")
+ .precision(0)
+ .prereq(rxBytes)
+ ;
+
+ txTcpChecksums
+ .name(name() + ".txTcpChecksums")
+ .desc("Number of tx TCP Checksums done by device")
+ .precision(0)
+ .prereq(txBytes)
+ ;
+
+ rxTcpChecksums
+ .name(name() + ".rxTcpChecksums")
+ .desc("Number of rx TCP Checksums done by device")
+ .precision(0)
+ .prereq(rxBytes)
+ ;
+
+ txUdpChecksums
+ .name(name() + ".txUdpChecksums")
+ .desc("Number of tx UDP Checksums done by device")
+ .precision(0)
+ .prereq(txBytes)
+ ;
+
+ rxUdpChecksums
+ .name(name() + ".rxUdpChecksums")
+ .desc("Number of rx UDP Checksums done by device")
+ .precision(0)
+ .prereq(rxBytes)
+ ;
+
+ descDmaReads
+ .name(name() + ".descDMAReads")
+ .desc("Number of descriptors the device read w/ DMA")
+ .precision(0)
+ ;
+
+ descDmaWrites
+ .name(name() + ".descDMAWrites")
+ .desc("Number of descriptors the device wrote w/ DMA")
+ .precision(0)
+ ;
+
+ descDmaRdBytes
+ .name(name() + ".descDmaReadBytes")
+ .desc("number of descriptor bytes read w/ DMA")
+ .precision(0)
+ ;
+
+ descDmaWrBytes
+ .name(name() + ".descDmaWriteBytes")
+ .desc("number of descriptor bytes write w/ DMA")
+ .precision(0)
+ ;
+
+ txBandwidth
+ .name(name() + ".txBandwidth")
+ .desc("Transmit Bandwidth (bits/s)")
+ .precision(0)
+ .prereq(txBytes)
+ ;
+
+ rxBandwidth
+ .name(name() + ".rxBandwidth")
+ .desc("Receive Bandwidth (bits/s)")
+ .precision(0)
+ .prereq(rxBytes)
+ ;
+
+ totBandwidth
+ .name(name() + ".totBandwidth")
+ .desc("Total Bandwidth (bits/s)")
+ .precision(0)
+ .prereq(totBytes)
+ ;
+
+ totPackets
+ .name(name() + ".totPackets")
+ .desc("Total Packets")
+ .precision(0)
+ .prereq(totBytes)
+ ;
+
+ totBytes
+ .name(name() + ".totBytes")
+ .desc("Total Bytes")
+ .precision(0)
+ .prereq(totBytes)
+ ;
+
+ totPacketRate
+ .name(name() + ".totPPS")
+ .desc("Total Tranmission Rate (packets/s)")
+ .precision(0)
+ .prereq(totBytes)
+ ;
+
+ txPacketRate
+ .name(name() + ".txPPS")
+ .desc("Packet Tranmission Rate (packets/s)")
+ .precision(0)
+ .prereq(txBytes)
+ ;
+
+ rxPacketRate
+ .name(name() + ".rxPPS")
+ .desc("Packet Reception Rate (packets/s)")
+ .precision(0)
+ .prereq(rxBytes)
+ ;
+
+ postedSwi
+ .name(name() + ".postedSwi")
+ .desc("number of software interrupts posted to CPU")
+ .precision(0)
+ ;
+
+ totalSwi
+ .name(name() + ".totalSwi")
+ .desc("total number of Swi written to ISR")
+ .precision(0)
+ ;
+
+ coalescedSwi
+ .name(name() + ".coalescedSwi")
+ .desc("average number of Swi's coalesced into each post")
+ .precision(0)
+ ;
+
+ postedRxIdle
+ .name(name() + ".postedRxIdle")
+ .desc("number of rxIdle interrupts posted to CPU")
+ .precision(0)
+ ;
+
+ totalRxIdle
+ .name(name() + ".totalRxIdle")
+ .desc("total number of RxIdle written to ISR")
+ .precision(0)
+ ;
+
+ coalescedRxIdle
+ .name(name() + ".coalescedRxIdle")
+ .desc("average number of RxIdle's coalesced into each post")
+ .precision(0)
+ ;
+
+ postedRxOk
+ .name(name() + ".postedRxOk")
+ .desc("number of RxOk interrupts posted to CPU")
+ .precision(0)
+ ;
+
+ totalRxOk
+ .name(name() + ".totalRxOk")
+ .desc("total number of RxOk written to ISR")
+ .precision(0)
+ ;
+
+ coalescedRxOk
+ .name(name() + ".coalescedRxOk")
+ .desc("average number of RxOk's coalesced into each post")
+ .precision(0)
+ ;
+
+ postedRxDesc
+ .name(name() + ".postedRxDesc")
+ .desc("number of RxDesc interrupts posted to CPU")
+ .precision(0)
+ ;
+
+ totalRxDesc
+ .name(name() + ".totalRxDesc")
+ .desc("total number of RxDesc written to ISR")
+ .precision(0)
+ ;
+
+ coalescedRxDesc
+ .name(name() + ".coalescedRxDesc")
+ .desc("average number of RxDesc's coalesced into each post")
+ .precision(0)
+ ;
+
+ postedTxOk
+ .name(name() + ".postedTxOk")
+ .desc("number of TxOk interrupts posted to CPU")
+ .precision(0)
+ ;
+
+ totalTxOk
+ .name(name() + ".totalTxOk")
+ .desc("total number of TxOk written to ISR")
+ .precision(0)
+ ;
+
+ coalescedTxOk
+ .name(name() + ".coalescedTxOk")
+ .desc("average number of TxOk's coalesced into each post")
+ .precision(0)
+ ;
+
+ postedTxIdle
+ .name(name() + ".postedTxIdle")
+ .desc("number of TxIdle interrupts posted to CPU")
+ .precision(0)
+ ;
+
+ totalTxIdle
+ .name(name() + ".totalTxIdle")
+ .desc("total number of TxIdle written to ISR")
+ .precision(0)
+ ;
+
+ coalescedTxIdle
+ .name(name() + ".coalescedTxIdle")
+ .desc("average number of TxIdle's coalesced into each post")
+ .precision(0)
+ ;
+
+ postedTxDesc
+ .name(name() + ".postedTxDesc")
+ .desc("number of TxDesc interrupts posted to CPU")
+ .precision(0)
+ ;
+
+ totalTxDesc
+ .name(name() + ".totalTxDesc")
+ .desc("total number of TxDesc written to ISR")
+ .precision(0)
+ ;
+
+ coalescedTxDesc
+ .name(name() + ".coalescedTxDesc")
+ .desc("average number of TxDesc's coalesced into each post")
+ .precision(0)
+ ;
+
+ postedRxOrn
+ .name(name() + ".postedRxOrn")
+ .desc("number of RxOrn posted to CPU")
+ .precision(0)
+ ;
+
+ totalRxOrn
+ .name(name() + ".totalRxOrn")
+ .desc("total number of RxOrn written to ISR")
+ .precision(0)
+ ;
+
+ coalescedRxOrn
+ .name(name() + ".coalescedRxOrn")
+ .desc("average number of RxOrn's coalesced into each post")
+ .precision(0)
+ ;
+
+ coalescedTotal
+ .name(name() + ".coalescedTotal")
+ .desc("average number of interrupts coalesced into each post")
+ .precision(0)
+ ;
+
+ postedInterrupts
+ .name(name() + ".postedInterrupts")
+ .desc("number of posts to CPU")
+ .precision(0)
+ ;
+
+ droppedPackets
+ .name(name() + ".droppedPackets")
+ .desc("number of packets dropped")
+ .precision(0)
+ ;
+
+ coalescedSwi = totalSwi / postedInterrupts;
+ coalescedRxIdle = totalRxIdle / postedInterrupts;
+ coalescedRxOk = totalRxOk / postedInterrupts;
+ coalescedRxDesc = totalRxDesc / postedInterrupts;
+ coalescedTxOk = totalTxOk / postedInterrupts;
+ coalescedTxIdle = totalTxIdle / postedInterrupts;
+ coalescedTxDesc = totalTxDesc / postedInterrupts;
+ coalescedRxOrn = totalRxOrn / postedInterrupts;
+
+ coalescedTotal = (totalSwi + totalRxIdle + totalRxOk + totalRxDesc +
+ totalTxOk + totalTxIdle + totalTxDesc +
+ totalRxOrn) / postedInterrupts;
+
+ txBandwidth = txBytes * Stats::constant(8) / simSeconds;
+ rxBandwidth = rxBytes * Stats::constant(8) / simSeconds;
+ totBandwidth = txBandwidth + rxBandwidth;
+ totBytes = txBytes + rxBytes;
+ totPackets = txPackets + rxPackets;
+
+ txPacketRate = txPackets / simSeconds;
+ rxPacketRate = rxPackets / simSeconds;
+}
+
+
+/**
+ * This is to write to the PCI general configuration registers
+ */
+void
+NSGigE::writeConfig(int offset, const uint16_t data)
+{
+ if (offset < PCI_DEVICE_SPECIFIC)
+ PciDev::writeConfig(offset, data);
+ else
+ panic("Device specific PCI config space not implemented!\n");
+
+ switch (offset) {
+ // seems to work fine without all these PCI settings, but i
+ // put in the IO to double check, an assertion will fail if we
+ // need to properly implement it
+ case PCI_COMMAND:
+ if (config.data[offset] & PCI_CMD_IOSE)
+ ioEnable = true;
+ else
+ ioEnable = false;
+ break;
+ }
+}
+
+/**
+ * This reads the device registers, which are detailed in the NS83820
+ * spec sheet
+ */
+Tick
+NSGigE::read(Packet *pkt)
+{
+ assert(ioEnable);
+
+ pkt->time += pioDelay;
+ pkt->allocate();
+
+ //The mask is to give you only the offset into the device register file
+ Addr daddr = pkt->addr & 0xfff;
+ DPRINTF(EthernetPIO, "read da=%#x pa=%#x size=%d\n",
+ daddr, pkt->addr, pkt->size);
+
+
+ // there are some reserved registers, you can see ns_gige_reg.h and
+ // the spec sheet for details
+ if (daddr > LAST && daddr <= RESERVED) {
+ panic("Accessing reserved register");
+ } else if (daddr > RESERVED && daddr <= 0x3FC) {
+ if (pkt->size == sizeof(uint8_t))
+ readConfig(daddr & 0xff, pkt->getPtr<uint8_t>());
+ if (pkt->size == sizeof(uint16_t))
+ readConfig(daddr & 0xff, pkt->getPtr<uint16_t>());
+ if (pkt->size == sizeof(uint32_t))
+ readConfig(daddr & 0xff, pkt->getPtr<uint32_t>());
+ pkt->result = Success;
+ return pioDelay;
+ } else if (daddr >= MIB_START && daddr <= MIB_END) {
+ // don't implement all the MIB's. hopefully the kernel
+ // doesn't actually DEPEND upon their values
+ // MIB are just hardware stats keepers
+ pkt->set<uint32_t>(0);
+ pkt->result = Success;
+ return pioDelay;
+ } else if (daddr > 0x3FC)
+ panic("Something is messed up!\n");
+
+ assert(pkt->size == sizeof(uint32_t));
+ uint32_t &reg = *pkt->getPtr<uint32_t>();
+ uint16_t rfaddr;
+
+ switch (daddr) {
+ case CR:
+ reg = regs.command;
+ //these are supposed to be cleared on a read
+ reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
+ break;
+
+ case CFGR:
+ reg = regs.config;
+ break;
+
+ case MEAR:
+ reg = regs.mear;
+ break;
+
+ case PTSCR:
+ reg = regs.ptscr;
+ break;
+
+ case ISR:
+ reg = regs.isr;
+ devIntrClear(ISR_ALL);
+ break;
+
+ case IMR:
+ reg = regs.imr;
+ break;
+
+ case IER:
+ reg = regs.ier;
+ break;
+
+ case IHR:
+ reg = regs.ihr;
+ break;
+
+ case TXDP:
+ reg = regs.txdp;
+ break;
+
+ case TXDP_HI:
+ reg = regs.txdp_hi;
+ break;
+
+ case TX_CFG:
+ reg = regs.txcfg;
+ break;
+
+ case GPIOR:
+ reg = regs.gpior;
+ break;
+
+ case RXDP:
+ reg = regs.rxdp;
+ break;
+
+ case RXDP_HI:
+ reg = regs.rxdp_hi;
+ break;
+
+ case RX_CFG:
+ reg = regs.rxcfg;
+ break;
+
+ case PQCR:
+ reg = regs.pqcr;
+ break;
+
+ case WCSR:
+ reg = regs.wcsr;
+ break;
+
+ case PCR:
+ reg = regs.pcr;
+ break;
+
+ // see the spec sheet for how RFCR and RFDR work
+ // basically, you write to RFCR to tell the machine
+ // what you want to do next, then you act upon RFDR,
+ // and the device will be prepared b/c of what you
+ // wrote to RFCR
+ case RFCR:
+ reg = regs.rfcr;
+ break;
+
+ case RFDR:
+ rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR);
+ switch (rfaddr) {
+ // Read from perfect match ROM octets
+ case 0x000:
+ reg = rom.perfectMatch[1];
+ reg = reg << 8;
+ reg += rom.perfectMatch[0];
+ break;
+ case 0x002:
+ reg = rom.perfectMatch[3] << 8;
+ reg += rom.perfectMatch[2];
+ break;
+ case 0x004:
+ reg = rom.perfectMatch[5] << 8;
+ reg += rom.perfectMatch[4];
+ break;
+ default:
+ // Read filter hash table
+ if (rfaddr >= FHASH_ADDR &&
+ rfaddr < FHASH_ADDR + FHASH_SIZE) {
+
+ // Only word-aligned reads supported
+ if (rfaddr % 2)
+ panic("unaligned read from filter hash table!");
+
+ reg = rom.filterHash[rfaddr - FHASH_ADDR + 1] << 8;
+ reg += rom.filterHash[rfaddr - FHASH_ADDR];
+ break;
+ }
+
+ panic("reading RFDR for something other than pattern"
+ " matching or hashing! %#x\n", rfaddr);
+ }
+ break;
+
+ case SRR:
+ reg = regs.srr;
+ break;
+
+ case MIBC:
+ reg = regs.mibc;
+ reg &= ~(MIBC_MIBS | MIBC_ACLR);
+ break;
+
+ case VRCR:
+ reg = regs.vrcr;
+ break;
+
+ case VTCR:
+ reg = regs.vtcr;
+ break;
+
+ case VDR:
+ reg = regs.vdr;
+ break;
+
+ case CCSR:
+ reg = regs.ccsr;
+ break;
+
+ case TBICR:
+ reg = regs.tbicr;
+ break;
+
+ case TBISR:
+ reg = regs.tbisr;
+ break;
+
+ case TANAR:
+ reg = regs.tanar;
+ break;
+
+ case TANLPAR:
+ reg = regs.tanlpar;
+ break;
+
+ case TANER:
+ reg = regs.taner;
+ break;
+
+ case TESR:
+ reg = regs.tesr;
+ break;
+
+ case M5REG:
+ reg = 0;
+ if (params()->rx_thread)
+ reg |= M5REG_RX_THREAD;
+ if (params()->tx_thread)
+ reg |= M5REG_TX_THREAD;
+ if (params()->rss)
+ reg |= M5REG_RSS;
+ break;
+
+ default:
+ panic("reading unimplemented register: addr=%#x", daddr);
+ }
+
+ DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n",
+ daddr, reg, reg);
+
+ pkt->result = Success;
+ return pioDelay;
+}
+
+Tick
+NSGigE::write(Packet *pkt)
+{
+ assert(ioEnable);
+
+ Addr daddr = pkt->addr & 0xfff;
+ DPRINTF(EthernetPIO, "write da=%#x pa=%#x size=%d\n",
+ daddr, pkt->addr, pkt->size);
+
+ pkt->time += pioDelay;
+
+ if (daddr > LAST && daddr <= RESERVED) {
+ panic("Accessing reserved register");
+ } else if (daddr > RESERVED && daddr <= 0x3FC) {
+ if (pkt->size == sizeof(uint8_t))
+ writeConfig(daddr & 0xff, pkt->get<uint8_t>());
+ if (pkt->size == sizeof(uint16_t))
+ writeConfig(daddr & 0xff, pkt->get<uint16_t>());
+ if (pkt->size == sizeof(uint32_t))
+ writeConfig(daddr & 0xff, pkt->get<uint32_t>());
+ pkt->result = Success;
+ return pioDelay;
+ } else if (daddr > 0x3FC)
+ panic("Something is messed up!\n");
+
+ if (pkt->size == sizeof(uint32_t)) {
+ uint32_t reg = pkt->get<uint32_t>();
+ uint16_t rfaddr;
+
+ DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg);
+
+ switch (daddr) {
+ case CR:
+ regs.command = reg;
+ if (reg & CR_TXD) {
+ txEnable = false;
+ } else if (reg & CR_TXE) {
+ txEnable = true;
+
+ // the kernel is enabling the transmit machine
+ if (txState == txIdle)
+ txKick();
+ }
+
+ if (reg & CR_RXD) {
+ rxEnable = false;
+ } else if (reg & CR_RXE) {
+ rxEnable = true;
+
+ if (rxState == rxIdle)
+ rxKick();
+ }
+
+ if (reg & CR_TXR)
+ txReset();
+
+ if (reg & CR_RXR)
+ rxReset();
+
+ if (reg & CR_SWI)
+ devIntrPost(ISR_SWI);
+
+ if (reg & CR_RST) {
+ txReset();
+ rxReset();
+
+ regsReset();
+ }
+ break;
+
+ case CFGR:
+ if (reg & CFGR_LNKSTS ||
+ reg & CFGR_SPDSTS ||
+ reg & CFGR_DUPSTS ||
+ reg & CFGR_RESERVED ||
+ reg & CFGR_T64ADDR ||
+ reg & CFGR_PCI64_DET)
+
+ // First clear all writable bits
+ regs.config &= CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS |
+ CFGR_RESERVED | CFGR_T64ADDR |
+ CFGR_PCI64_DET;
+ // Now set the appropriate writable bits
+ regs.config |= reg & ~(CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS |
+ CFGR_RESERVED | CFGR_T64ADDR |
+ CFGR_PCI64_DET);
+
+// all these #if 0's are because i don't THINK the kernel needs to
+// have these implemented. if there is a problem relating to one of
+// these, you may need to add functionality in.
+ if (reg & CFGR_TBI_EN) ;
+ if (reg & CFGR_MODE_1000) ;
+
+ if (reg & CFGR_AUTO_1000)
+ panic("CFGR_AUTO_1000 not implemented!\n");
+
+ if (reg & CFGR_PINT_DUPSTS ||
+ reg & CFGR_PINT_LNKSTS ||
+ reg & CFGR_PINT_SPDSTS)
+ ;
+
+ if (reg & CFGR_TMRTEST) ;
+ if (reg & CFGR_MRM_DIS) ;
+ if (reg & CFGR_MWI_DIS) ;
+
+ if (reg & CFGR_T64ADDR) ;
+ // panic("CFGR_T64ADDR is read only register!\n");
+
+ if (reg & CFGR_PCI64_DET)
+ panic("CFGR_PCI64_DET is read only register!\n");
+
+ if (reg & CFGR_DATA64_EN) ;
+ if (reg & CFGR_M64ADDR) ;
+ if (reg & CFGR_PHY_RST) ;
+ if (reg & CFGR_PHY_DIS) ;
+
+ if (reg & CFGR_EXTSTS_EN)
+ extstsEnable = true;
+ else
+ extstsEnable = false;
+
+ if (reg & CFGR_REQALG) ;
+ if (reg & CFGR_SB) ;
+ if (reg & CFGR_POW) ;
+ if (reg & CFGR_EXD) ;
+ if (reg & CFGR_PESEL) ;
+ if (reg & CFGR_BROM_DIS) ;
+ if (reg & CFGR_EXT_125) ;
+ if (reg & CFGR_BEM) ;
+ break;
+
+ case MEAR:
+ // Clear writable bits
+ regs.mear &= MEAR_EEDO;
+ // Set appropriate writable bits
+ regs.mear |= reg & ~MEAR_EEDO;
+
+ // FreeBSD uses the EEPROM to read PMATCH (for the MAC address)
+ // even though it could get it through RFDR
+ if (reg & MEAR_EESEL) {
+ // Rising edge of clock
+ if (reg & MEAR_EECLK && !eepromClk)
+ eepromKick();
+ }
+ else {
+ eepromState = eepromStart;
+ regs.mear &= ~MEAR_EEDI;
+ }
+
+ eepromClk = reg & MEAR_EECLK;
+
+ // since phy is completely faked, MEAR_MD* don't matter
+ if (reg & MEAR_MDIO) ;
+ if (reg & MEAR_MDDIR) ;
+ if (reg & MEAR_MDC) ;
+ break;
+
+ case PTSCR:
+ regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY);
+ // these control BISTs for various parts of chip - we
+ // don't care or do just fake that the BIST is done
+ if (reg & PTSCR_RBIST_EN)
+ regs.ptscr |= PTSCR_RBIST_DONE;
+ if (reg & PTSCR_EEBIST_EN)
+ regs.ptscr &= ~PTSCR_EEBIST_EN;
+ if (reg & PTSCR_EELOAD_EN)
+ regs.ptscr &= ~PTSCR_EELOAD_EN;
+ break;
+
+ case ISR: /* writing to the ISR has no effect */
+ panic("ISR is a read only register!\n");
+
+ case IMR:
+ regs.imr = reg;
+ devIntrChangeMask();
+ break;
+
+ case IER:
+ regs.ier = reg;
+ break;
+
+ case IHR:
+ regs.ihr = reg;
+ /* not going to implement real interrupt holdoff */
+ break;
+
+ case TXDP:
+ regs.txdp = (reg & 0xFFFFFFFC);
+ assert(txState == txIdle);
+ CTDD = false;
+ break;
+
+ case TXDP_HI:
+ regs.txdp_hi = reg;
+ break;
+
+ case TX_CFG:
+ regs.txcfg = reg;
+#if 0
+ if (reg & TX_CFG_CSI) ;
+ if (reg & TX_CFG_HBI) ;
+ if (reg & TX_CFG_MLB) ;
+ if (reg & TX_CFG_ATP) ;
+ if (reg & TX_CFG_ECRETRY) {
+ /*
+ * this could easily be implemented, but considering
+ * the network is just a fake pipe, wouldn't make
+ * sense to do this
+ */
+ }
+
+ if (reg & TX_CFG_BRST_DIS) ;
+#endif
+
+#if 0
+ /* we handle our own DMA, ignore the kernel's exhortations */
+ if (reg & TX_CFG_MXDMA) ;
+#endif
+
+ // also, we currently don't care about fill/drain
+ // thresholds though this may change in the future with
+ // more realistic networks or a driver which changes it
+ // according to feedback
+
+ break;
+
+ case GPIOR:
+ // Only write writable bits
+ regs.gpior &= GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN
+ | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN;
+ regs.gpior |= reg & ~(GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN
+ | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN);
+ /* these just control general purpose i/o pins, don't matter */
+ break;
+
+ case RXDP:
+ regs.rxdp = reg;
+ CRDD = false;
+ break;
+
+ case RXDP_HI:
+ regs.rxdp_hi = reg;
+ break;
+
+ case RX_CFG:
+ regs.rxcfg = reg;
+#if 0
+ if (reg & RX_CFG_AEP) ;
+ if (reg & RX_CFG_ARP) ;
+ if (reg & RX_CFG_STRIPCRC) ;
+ if (reg & RX_CFG_RX_RD) ;
+ if (reg & RX_CFG_ALP) ;
+ if (reg & RX_CFG_AIRL) ;
+
+ /* we handle our own DMA, ignore what kernel says about it */
+ if (reg & RX_CFG_MXDMA) ;
+
+ //also, we currently don't care about fill/drain thresholds
+ //though this may change in the future with more realistic
+ //networks or a driver which changes it according to feedback
+ if (reg & (RX_CFG_DRTH | RX_CFG_DRTH0)) ;
+#endif
+ break;
+
+ case PQCR:
+ /* there is no priority queueing used in the linux 2.6 driver */
+ regs.pqcr = reg;
+ break;
+
+ case WCSR:
+ /* not going to implement wake on LAN */
+ regs.wcsr = reg;
+ break;
+
+ case PCR:
+ /* not going to implement pause control */
+ regs.pcr = reg;
+ break;
+
+ case RFCR:
+ regs.rfcr = reg;
+
+ rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
+ acceptBroadcast = (reg & RFCR_AAB) ? true : false;
+ acceptMulticast = (reg & RFCR_AAM) ? true : false;
+ acceptUnicast = (reg & RFCR_AAU) ? true : false;
+ acceptPerfect = (reg & RFCR_APM) ? true : false;
+ acceptArp = (reg & RFCR_AARP) ? true : false;
+ multicastHashEnable = (reg & RFCR_MHEN) ? true : false;
+
+#if 0
+ if (reg & RFCR_APAT)
+ panic("RFCR_APAT not implemented!\n");
+#endif
+ if (reg & RFCR_UHEN)
+ panic("Unicast hash filtering not used by drivers!\n");
+
+ if (reg & RFCR_ULM)
+ panic("RFCR_ULM not implemented!\n");
+
+ break;
+
+ case RFDR:
+ rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR);
+ switch (rfaddr) {
+ case 0x000:
+ rom.perfectMatch[0] = (uint8_t)reg;
+ rom.perfectMatch[1] = (uint8_t)(reg >> 8);
+ break;
+ case 0x002:
+ rom.perfectMatch[2] = (uint8_t)reg;
+ rom.perfectMatch[3] = (uint8_t)(reg >> 8);
+ break;
+ case 0x004:
+ rom.perfectMatch[4] = (uint8_t)reg;
+ rom.perfectMatch[5] = (uint8_t)(reg >> 8);
+ break;
+ default:
+
+ if (rfaddr >= FHASH_ADDR &&
+ rfaddr < FHASH_ADDR + FHASH_SIZE) {
+
+ // Only word-aligned writes supported
+ if (rfaddr % 2)
+ panic("unaligned write to filter hash table!");
+
+ rom.filterHash[rfaddr - FHASH_ADDR] = (uint8_t)reg;
+ rom.filterHash[rfaddr - FHASH_ADDR + 1]
+ = (uint8_t)(reg >> 8);
+ break;
+ }
+ panic("writing RFDR for something other than pattern matching\
+ or hashing! %#x\n", rfaddr);
+ }
+
+ case BRAR:
+ regs.brar = reg;
+ break;
+
+ case BRDR:
+ panic("the driver never uses BRDR, something is wrong!\n");
+
+ case SRR:
+ panic("SRR is read only register!\n");
+
+ case MIBC:
+ panic("the driver never uses MIBC, something is wrong!\n");
+
+ case VRCR:
+ regs.vrcr = reg;
+ break;
+
+ case VTCR:
+ regs.vtcr = reg;
+ break;
+
+ case VDR:
+ panic("the driver never uses VDR, something is wrong!\n");
+
+ case CCSR:
+ /* not going to implement clockrun stuff */
+ regs.ccsr = reg;
+ break;
+
+ case TBICR:
+ regs.tbicr = reg;
+ if (reg & TBICR_MR_LOOPBACK)
+ panic("TBICR_MR_LOOPBACK never used, something wrong!\n");
+
+ if (reg & TBICR_MR_AN_ENABLE) {
+ regs.tanlpar = regs.tanar;
+ regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
+ }
+
+#if 0
+ if (reg & TBICR_MR_RESTART_AN) ;
+#endif
+
+ break;
+
+ case TBISR:
+ panic("TBISR is read only register!\n");
+
+ case TANAR:
+ // Only write the writable bits
+ regs.tanar &= TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED;
+ regs.tanar |= reg & ~(TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED);
+
+ // Pause capability unimplemented
+#if 0
+ if (reg & TANAR_PS2) ;
+ if (reg & TANAR_PS1) ;
+#endif
+
+ break;
+
+ case TANLPAR:
+ panic("this should only be written to by the fake phy!\n");
+
+ case TANER:
+ panic("TANER is read only register!\n");
+
+ case TESR:
+ regs.tesr = reg;
+ break;
+
+ default:
+ panic("invalid register access daddr=%#x", daddr);
+ }
+ } else {
+ panic("Invalid Request Size");
+ }
+ pkt->result = Success;
+ return pioDelay;
+}
+
+void
+NSGigE::devIntrPost(uint32_t interrupts)
+{
+ if (interrupts & ISR_RESERVE)
+ panic("Cannot set a reserved interrupt");
+
+ if (interrupts & ISR_NOIMPL)
+ warn("interrupt not implemented %#x\n", interrupts);
+
+ interrupts &= ISR_IMPL;
+ regs.isr |= interrupts;
+
+ if (interrupts & regs.imr) {
+ if (interrupts & ISR_SWI) {
+ totalSwi++;
+ }
+ if (interrupts & ISR_RXIDLE) {
+ totalRxIdle++;
+ }
+ if (interrupts & ISR_RXOK) {
+ totalRxOk++;
+ }
+ if (interrupts & ISR_RXDESC) {
+ totalRxDesc++;
+ }
+ if (interrupts & ISR_TXOK) {
+ totalTxOk++;
+ }
+ if (interrupts & ISR_TXIDLE) {
+ totalTxIdle++;
+ }
+ if (interrupts & ISR_TXDESC) {
+ totalTxDesc++;
+ }
+ if (interrupts & ISR_RXORN) {
+ totalRxOrn++;
+ }
+ }
+
+ DPRINTF(EthernetIntr,
+ "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n",
+ interrupts, regs.isr, regs.imr);
+
+ if ((regs.isr & regs.imr)) {
+ Tick when = curTick;
+ if ((regs.isr & regs.imr & ISR_NODELAY) == 0)
+ when += intrDelay;
+ cpuIntrPost(when);
+ }
+}
+
+/* writing this interrupt counting stats inside this means that this function
+ is now limited to being used to clear all interrupts upon the kernel
+ reading isr and servicing. just telling you in case you were thinking
+ of expanding use.
+*/
+void
+NSGigE::devIntrClear(uint32_t interrupts)
+{
+ if (interrupts & ISR_RESERVE)
+ panic("Cannot clear a reserved interrupt");
+
+ if (regs.isr & regs.imr & ISR_SWI) {
+ postedSwi++;
+ }
+ if (regs.isr & regs.imr & ISR_RXIDLE) {
+ postedRxIdle++;
+ }
+ if (regs.isr & regs.imr & ISR_RXOK) {
+ postedRxOk++;
+ }
+ if (regs.isr & regs.imr & ISR_RXDESC) {
+ postedRxDesc++;
+ }
+ if (regs.isr & regs.imr & ISR_TXOK) {
+ postedTxOk++;
+ }
+ if (regs.isr & regs.imr & ISR_TXIDLE) {
+ postedTxIdle++;
+ }
+ if (regs.isr & regs.imr & ISR_TXDESC) {
+ postedTxDesc++;
+ }
+ if (regs.isr & regs.imr & ISR_RXORN) {
+ postedRxOrn++;
+ }
+
+ if (regs.isr & regs.imr & ISR_IMPL)
+ postedInterrupts++;
+
+ interrupts &= ~ISR_NOIMPL;
+ regs.isr &= ~interrupts;
+
+ DPRINTF(EthernetIntr,
+ "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n",
+ interrupts, regs.isr, regs.imr);
+
+ if (!(regs.isr & regs.imr))
+ cpuIntrClear();
+}
+
+void
+NSGigE::devIntrChangeMask()
+{
+ DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n",
+ regs.isr, regs.imr, regs.isr & regs.imr);
+
+ if (regs.isr & regs.imr)
+ cpuIntrPost(curTick);
+ else
+ cpuIntrClear();
+}
+
+void
+NSGigE::cpuIntrPost(Tick when)
+{
+ // If the interrupt you want to post is later than an interrupt
+ // already scheduled, just let it post in the coming one and don't
+ // schedule another.
+ // HOWEVER, must be sure that the scheduled intrTick is in the
+ // future (this was formerly the source of a bug)
+ /**
+ * @todo this warning should be removed and the intrTick code should
+ * be fixed.
+ */
+ assert(when >= curTick);
+ assert(intrTick >= curTick || intrTick == 0);
+ if (when > intrTick && intrTick != 0) {
+ DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
+ intrTick);
+ return;
+ }
+
+ intrTick = when;
+ if (intrTick < curTick) {
+ debug_break();
+ intrTick = curTick;
+ }
+
+ DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
+ intrTick);
+
+ if (intrEvent)
+ intrEvent->squash();
+ intrEvent = new IntrEvent(this, true);
+ intrEvent->schedule(intrTick);
+}
+
+void
+NSGigE::cpuInterrupt()
+{
+ assert(intrTick == curTick);
+
+ // Whether or not there's a pending interrupt, we don't care about
+ // it anymore
+ intrEvent = 0;
+ intrTick = 0;
+
+ // Don't send an interrupt if there's already one
+ if (cpuPendingIntr) {
+ DPRINTF(EthernetIntr,
+ "would send an interrupt now, but there's already pending\n");
+ } else {
+ // Send interrupt
+ cpuPendingIntr = true;
+
+ DPRINTF(EthernetIntr, "posting interrupt\n");
+ intrPost();
+ }
+}
+
+void
+NSGigE::cpuIntrClear()
+{
+ if (!cpuPendingIntr)
+ return;
+
+ if (intrEvent) {
+ intrEvent->squash();
+ intrEvent = 0;
+ }
+
+ intrTick = 0;
+
+ cpuPendingIntr = false;
+
+ DPRINTF(EthernetIntr, "clearing interrupt\n");
+ intrClear();
+}
+
+bool
+NSGigE::cpuIntrPending() const
+{ return cpuPendingIntr; }
+
+void
+NSGigE::txReset()
+{
+
+ DPRINTF(Ethernet, "transmit reset\n");
+
+ CTDD = false;
+ txEnable = false;;
+ txFragPtr = 0;
+ assert(txDescCnt == 0);
+ txFifo.clear();
+ txState = txIdle;
+ assert(txDmaState == dmaIdle);
+}
+
+void
+NSGigE::rxReset()
+{
+ DPRINTF(Ethernet, "receive reset\n");
+
+ CRDD = false;
+ assert(rxPktBytes == 0);
+ rxEnable = false;
+ rxFragPtr = 0;
+ assert(rxDescCnt == 0);
+ assert(rxDmaState == dmaIdle);
+ rxFifo.clear();
+ rxState = rxIdle;
+}
+
+void
+NSGigE::regsReset()
+{
+ memset(&regs, 0, sizeof(regs));
+ regs.config = (CFGR_LNKSTS | CFGR_TBI_EN | CFGR_MODE_1000);
+ regs.mear = 0x12;
+ regs.txcfg = 0x120; // set drain threshold to 1024 bytes and
+ // fill threshold to 32 bytes
+ regs.rxcfg = 0x4; // set drain threshold to 16 bytes
+ regs.srr = 0x0103; // set the silicon revision to rev B or 0x103
+ regs.mibc = MIBC_FRZ;
+ regs.vdr = 0x81; // set the vlan tag type to 802.1q
+ regs.tesr = 0xc000; // TBI capable of both full and half duplex
+ regs.brar = 0xffffffff;
+
+ extstsEnable = false;
+ acceptBroadcast = false;
+ acceptMulticast = false;
+ acceptUnicast = false;
+ acceptPerfect = false;
+ acceptArp = false;
+}
+
+bool
+NSGigE::doRxDmaRead()
+{
+ assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
+ rxDmaState = dmaReading;
+
+ if (dmaPending())
+ rxDmaState = dmaReadWaiting;
+ else
+ dmaRead(rxDmaAddr, rxDmaLen, &rxDmaReadEvent, (uint8_t*)rxDmaData);
+
+ return true;
+}
+
+void
+NSGigE::rxDmaReadDone()
+{
+ assert(rxDmaState == dmaReading);
+ rxDmaState = dmaIdle;
+
+ DPRINTF(EthernetDMA, "rx dma read paddr=%#x len=%d\n",
+ rxDmaAddr, rxDmaLen);
+ DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
+
+ // If the transmit state machine has a pending DMA, let it go first
+ if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
+ txKick();
+
+ rxKick();
+}
+
+bool
+NSGigE::doRxDmaWrite()
+{
+ assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
+ rxDmaState = dmaWriting;
+
+ if (dmaPending())
+ rxDmaState = dmaWriteWaiting;
+ else
+ dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaWriteEvent, (uint8_t*)rxDmaData);
+ return true;
+}
+
+void
+NSGigE::rxDmaWriteDone()
+{
+ assert(rxDmaState == dmaWriting);
+ rxDmaState = dmaIdle;
+
+ DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
+ rxDmaAddr, rxDmaLen);
+ DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
+
+ // If the transmit state machine has a pending DMA, let it go first
+ if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
+ txKick();
+
+ rxKick();
+}
+
+void
+NSGigE::rxKick()
+{
+ bool is64bit = (bool)(regs.config & CFGR_M64ADDR);
+
+ DPRINTF(EthernetSM,
+ "receive kick rxState=%s (rxBuf.size=%d) %d-bit\n",
+ NsRxStateStrings[rxState], rxFifo.size(), is64bit ? 64 : 32);
+
+ Addr link, bufptr;
+ uint32_t &cmdsts = is64bit ? rxDesc64.cmdsts : rxDesc32.cmdsts;
+ uint32_t &extsts = is64bit ? rxDesc64.extsts : rxDesc32.extsts;
+
+ next:
+ if (clock) {
+ if (rxKickTick > curTick) {
+ DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n",
+ rxKickTick);
+
+ goto exit;
+ }
+
+ // Go to the next state machine clock tick.
+ rxKickTick = curTick + cycles(1);
+ }
+
+ switch(rxDmaState) {
+ case dmaReadWaiting:
+ if (doRxDmaRead())
+ goto exit;
+ break;
+ case dmaWriteWaiting:
+ if (doRxDmaWrite())
+ goto exit;
+ break;
+ default:
+ break;
+ }
+
+ link = is64bit ? (Addr)rxDesc64.link : (Addr)rxDesc32.link;
+ bufptr = is64bit ? (Addr)rxDesc64.bufptr : (Addr)rxDesc32.bufptr;
+
+ // see state machine from spec for details
+ // the way this works is, if you finish work on one state and can
+ // go directly to another, you do that through jumping to the
+ // label "next". however, if you have intermediate work, like DMA
+ // so that you can't go to the next state yet, you go to exit and
+ // exit the loop. however, when the DMA is done it will trigger
+ // an event and come back to this loop.
+ switch (rxState) {
+ case rxIdle:
+ if (!rxEnable) {
+ DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n");
+ goto exit;
+ }
+
+ if (CRDD) {
+ rxState = rxDescRefr;
+
+ rxDmaAddr = regs.rxdp & 0x3fffffff;
+ rxDmaData =
+ is64bit ? (void *)&rxDesc64.link : (void *)&rxDesc32.link;
+ rxDmaLen = is64bit ? sizeof(rxDesc64.link) : sizeof(rxDesc32.link);
+ rxDmaFree = dmaDescFree;
+
+ descDmaReads++;
+ descDmaRdBytes += rxDmaLen;
+
+ if (doRxDmaRead())
+ goto exit;
+ } else {
+ rxState = rxDescRead;
+
+ rxDmaAddr = regs.rxdp & 0x3fffffff;
+ rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32;
+ rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32);
+ rxDmaFree = dmaDescFree;
+
+ descDmaReads++;
+ descDmaRdBytes += rxDmaLen;
+
+ if (doRxDmaRead())
+ goto exit;
+ }
+ break;
+
+ case rxDescRefr:
+ if (rxDmaState != dmaIdle)
+ goto exit;
+
+ rxState = rxAdvance;
+ break;
+
+ case rxDescRead:
+ if (rxDmaState != dmaIdle)
+ goto exit;
+
+ DPRINTF(EthernetDesc, "rxDesc: addr=%08x read descriptor\n",
+ regs.rxdp & 0x3fffffff);
+ DPRINTF(EthernetDesc,
+ "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n",
+ link, bufptr, cmdsts, extsts);
+
+ if (cmdsts & CMDSTS_OWN) {
+ devIntrPost(ISR_RXIDLE);
+ rxState = rxIdle;
+ goto exit;
+ } else {
+ rxState = rxFifoBlock;
+ rxFragPtr = bufptr;
+ rxDescCnt = cmdsts & CMDSTS_LEN_MASK;
+ }
+ break;
+
+ case rxFifoBlock:
+ if (!rxPacket) {
+ /**
+ * @todo in reality, we should be able to start processing
+ * the packet as it arrives, and not have to wait for the
+ * full packet ot be in the receive fifo.
+ */
+ if (rxFifo.empty())
+ goto exit;
+
+ DPRINTF(EthernetSM, "****processing receive of new packet****\n");
+
+ // If we don't have a packet, grab a new one from the fifo.
+ rxPacket = rxFifo.front();
+ rxPktBytes = rxPacket->length;
+ rxPacketBufPtr = rxPacket->data;
+
+#if TRACING_ON
+ if (DTRACE(Ethernet)) {
+ IpPtr ip(rxPacket);
+ if (ip) {
+ DPRINTF(Ethernet, "ID is %d\n", ip->id());
+ TcpPtr tcp(ip);
+ if (tcp) {
+ DPRINTF(Ethernet,
+ "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
+ tcp->sport(), tcp->dport(), tcp->seq(),
+ tcp->ack());
+ }
+ }
+ }
+#endif
+
+ // sanity check - i think the driver behaves like this
+ assert(rxDescCnt >= rxPktBytes);
+ rxFifo.pop();
+ }
+
+
+ // dont' need the && rxDescCnt > 0 if driver sanity check
+ // above holds
+ if (rxPktBytes > 0) {
+ rxState = rxFragWrite;
+ // don't need min<>(rxPktBytes,rxDescCnt) if above sanity
+ // check holds
+ rxXferLen = rxPktBytes;
+
+ rxDmaAddr = rxFragPtr & 0x3fffffff;
+ rxDmaData = rxPacketBufPtr;
+ rxDmaLen = rxXferLen;
+ rxDmaFree = dmaDataFree;
+
+ if (doRxDmaWrite())
+ goto exit;
+
+ } else {
+ rxState = rxDescWrite;
+
+ //if (rxPktBytes == 0) { /* packet is done */
+ assert(rxPktBytes == 0);
+ DPRINTF(EthernetSM, "done with receiving packet\n");
+
+ cmdsts |= CMDSTS_OWN;
+ cmdsts &= ~CMDSTS_MORE;
+ cmdsts |= CMDSTS_OK;
+ cmdsts &= 0xffff0000;
+ cmdsts += rxPacket->length; //i.e. set CMDSTS_SIZE
+
+#if 0
+ /*
+ * all the driver uses these are for its own stats keeping
+ * which we don't care about, aren't necessary for
+ * functionality and doing this would just slow us down.
+ * if they end up using this in a later version for
+ * functional purposes, just undef
+ */
+ if (rxFilterEnable) {
+ cmdsts &= ~CMDSTS_DEST_MASK;
+ const EthAddr &dst = rxFifoFront()->dst();
+ if (dst->unicast())
+ cmdsts |= CMDSTS_DEST_SELF;
+ if (dst->multicast())
+ cmdsts |= CMDSTS_DEST_MULTI;
+ if (dst->broadcast())
+ cmdsts |= CMDSTS_DEST_MASK;
+ }
+#endif
+
+ IpPtr ip(rxPacket);
+ if (extstsEnable && ip) {
+ extsts |= EXTSTS_IPPKT;
+ rxIpChecksums++;
+ if (cksum(ip) != 0) {
+ DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
+ extsts |= EXTSTS_IPERR;
+ }
+ TcpPtr tcp(ip);
+ UdpPtr udp(ip);
+ if (tcp) {
+ extsts |= EXTSTS_TCPPKT;
+ rxTcpChecksums++;
+ if (cksum(tcp) != 0) {
+ DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
+ extsts |= EXTSTS_TCPERR;
+
+ }
+ } else if (udp) {
+ extsts |= EXTSTS_UDPPKT;
+ rxUdpChecksums++;
+ if (cksum(udp) != 0) {
+ DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
+ extsts |= EXTSTS_UDPERR;
+ }
+ }
+ }
+ rxPacket = 0;
+
+ /*
+ * the driver seems to always receive into desc buffers
+ * of size 1514, so you never have a pkt that is split
+ * into multiple descriptors on the receive side, so
+ * i don't implement that case, hence the assert above.
+ */
+
+ DPRINTF(EthernetDesc,
+ "rxDesc: addr=%08x writeback cmdsts extsts\n",
+ regs.rxdp & 0x3fffffff);
+ DPRINTF(EthernetDesc,
+ "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n",
+ link, bufptr, cmdsts, extsts);
+
+ rxDmaAddr = regs.rxdp & 0x3fffffff;
+ rxDmaData = &cmdsts;
+ if (is64bit) {
+ rxDmaAddr += offsetof(ns_desc64, cmdsts);
+ rxDmaLen = sizeof(rxDesc64.cmdsts) + sizeof(rxDesc64.extsts);
+ } else {
+ rxDmaAddr += offsetof(ns_desc32, cmdsts);
+ rxDmaLen = sizeof(rxDesc32.cmdsts) + sizeof(rxDesc32.extsts);
+ }
+ rxDmaFree = dmaDescFree;
+
+ descDmaWrites++;
+ descDmaWrBytes += rxDmaLen;
+
+ if (doRxDmaWrite())
+ goto exit;
+ }
+ break;
+
+ case rxFragWrite:
+ if (rxDmaState != dmaIdle)
+ goto exit;
+
+ rxPacketBufPtr += rxXferLen;
+ rxFragPtr += rxXferLen;
+ rxPktBytes -= rxXferLen;
+
+ rxState = rxFifoBlock;
+ break;
+
+ case rxDescWrite:
+ if (rxDmaState != dmaIdle)
+ goto exit;
+
+ assert(cmdsts & CMDSTS_OWN);
+
+ assert(rxPacket == 0);
+ devIntrPost(ISR_RXOK);
+
+ if (cmdsts & CMDSTS_INTR)
+ devIntrPost(ISR_RXDESC);
+
+ if (!rxEnable) {
+ DPRINTF(EthernetSM, "Halting the RX state machine\n");
+ rxState = rxIdle;
+ goto exit;
+ } else
+ rxState = rxAdvance;
+ break;
+
+ case rxAdvance:
+ if (link == 0) {
+ devIntrPost(ISR_RXIDLE);
+ rxState = rxIdle;
+ CRDD = true;
+ goto exit;
+ } else {
+ if (rxDmaState != dmaIdle)
+ goto exit;
+ rxState = rxDescRead;
+ regs.rxdp = link;
+ CRDD = false;
+
+ rxDmaAddr = regs.rxdp & 0x3fffffff;
+ rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32;
+ rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32);
+ rxDmaFree = dmaDescFree;
+
+ if (doRxDmaRead())
+ goto exit;
+ }
+ break;
+
+ default:
+ panic("Invalid rxState!");
+ }
+
+ DPRINTF(EthernetSM, "entering next rxState=%s\n",
+ NsRxStateStrings[rxState]);
+ goto next;
+
+ exit:
+ /**
+ * @todo do we want to schedule a future kick?
+ */
+ DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
+ NsRxStateStrings[rxState]);
+
+ if (clock && !rxKickEvent.scheduled())
+ rxKickEvent.schedule(rxKickTick);
+}
+
+void
+NSGigE::transmit()
+{
+ if (txFifo.empty()) {
+ DPRINTF(Ethernet, "nothing to transmit\n");
+ return;
+ }
+
+ DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n",
+ txFifo.size());
+ if (interface->sendPacket(txFifo.front())) {
+#if TRACING_ON
+ if (DTRACE(Ethernet)) {
+ IpPtr ip(txFifo.front());
+ if (ip) {
+ DPRINTF(Ethernet, "ID is %d\n", ip->id());
+ TcpPtr tcp(ip);
+ if (tcp) {
+ DPRINTF(Ethernet,
+ "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
+ tcp->sport(), tcp->dport(), tcp->seq(),
+ tcp->ack());
+ }
+ }
+ }
+#endif
+
+ DDUMP(EthernetData, txFifo.front()->data, txFifo.front()->length);
+ txBytes += txFifo.front()->length;
+ txPackets++;
+
+ DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n",
+ txFifo.avail());
+ txFifo.pop();
+
+ /*
+ * normally do a writeback of the descriptor here, and ONLY
+ * after that is done, send this interrupt. but since our
+ * stuff never actually fails, just do this interrupt here,
+ * otherwise the code has to stray from this nice format.
+ * besides, it's functionally the same.
+ */
+ devIntrPost(ISR_TXOK);
+ }
+
+ if (!txFifo.empty() && !txEvent.scheduled()) {
+ DPRINTF(Ethernet, "reschedule transmit\n");
+ txEvent.schedule(curTick + retryTime);
+ }
+}
+
+bool
+NSGigE::doTxDmaRead()
+{
+ assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
+ txDmaState = dmaReading;
+
+ if (dmaPending())
+ txDmaState = dmaReadWaiting;
+ else
+ dmaRead(txDmaAddr, txDmaLen, &txDmaReadEvent, (uint8_t*)txDmaData);
+
+ return true;
+}
+
+void
+NSGigE::txDmaReadDone()
+{
+ assert(txDmaState == dmaReading);
+ txDmaState = dmaIdle;
+
+ DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n",
+ txDmaAddr, txDmaLen);
+ DDUMP(EthernetDMA, txDmaData, txDmaLen);
+
+ // If the receive state machine has a pending DMA, let it go first
+ if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
+ rxKick();
+
+ txKick();
+}
+
+bool
+NSGigE::doTxDmaWrite()
+{
+ assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
+ txDmaState = dmaWriting;
+
+ if (dmaPending())
+ txDmaState = dmaWriteWaiting;
+ else
+ dmaWrite(txDmaAddr, txDmaLen, &txDmaWriteEvent, (uint8_t*)txDmaData);
+ return true;
+}
+
+void
+NSGigE::txDmaWriteDone()
+{
+ assert(txDmaState == dmaWriting);
+ txDmaState = dmaIdle;
+
+ DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n",
+ txDmaAddr, txDmaLen);
+ DDUMP(EthernetDMA, txDmaData, txDmaLen);
+
+ // If the receive state machine has a pending DMA, let it go first
+ if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
+ rxKick();
+
+ txKick();
+}
+
+void
+NSGigE::txKick()
+{
+ bool is64bit = (bool)(regs.config & CFGR_M64ADDR);
+
+ DPRINTF(EthernetSM, "transmit kick txState=%s %d-bit\n",
+ NsTxStateStrings[txState], is64bit ? 64 : 32);
+
+ Addr link, bufptr;
+ uint32_t &cmdsts = is64bit ? txDesc64.cmdsts : txDesc32.cmdsts;
+ uint32_t &extsts = is64bit ? txDesc64.extsts : txDesc32.extsts;
+
+ next:
+ if (clock) {
+ if (txKickTick > curTick) {
+ DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n",
+ txKickTick);
+ goto exit;
+ }
+
+ // Go to the next state machine clock tick.
+ txKickTick = curTick + cycles(1);
+ }
+
+ switch(txDmaState) {
+ case dmaReadWaiting:
+ if (doTxDmaRead())
+ goto exit;
+ break;
+ case dmaWriteWaiting:
+ if (doTxDmaWrite())
+ goto exit;
+ break;
+ default:
+ break;
+ }
+
+ link = is64bit ? (Addr)txDesc64.link : (Addr)txDesc32.link;
+ bufptr = is64bit ? (Addr)txDesc64.bufptr : (Addr)txDesc32.bufptr;
+ switch (txState) {
+ case txIdle:
+ if (!txEnable) {
+ DPRINTF(EthernetSM, "Transmit disabled. Nothing to do.\n");
+ goto exit;
+ }
+
+ if (CTDD) {
+ txState = txDescRefr;
+
+ txDmaAddr = regs.txdp & 0x3fffffff;
+ txDmaData =
+ is64bit ? (void *)&txDesc64.link : (void *)&txDesc32.link;
+ txDmaLen = is64bit ? sizeof(txDesc64.link) : sizeof(txDesc32.link);
+ txDmaFree = dmaDescFree;
+
+ descDmaReads++;
+ descDmaRdBytes += txDmaLen;
+
+ if (doTxDmaRead())
+ goto exit;
+
+ } else {
+ txState = txDescRead;
+
+ txDmaAddr = regs.txdp & 0x3fffffff;
+ txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32;
+ txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32);
+ txDmaFree = dmaDescFree;
+
+ descDmaReads++;
+ descDmaRdBytes += txDmaLen;
+
+ if (doTxDmaRead())
+ goto exit;
+ }
+ break;
+
+ case txDescRefr:
+ if (txDmaState != dmaIdle)
+ goto exit;
+
+ txState = txAdvance;
+ break;
+
+ case txDescRead:
+ if (txDmaState != dmaIdle)
+ goto exit;
+
+ DPRINTF(EthernetDesc, "txDesc: addr=%08x read descriptor\n",
+ regs.txdp & 0x3fffffff);
+ DPRINTF(EthernetDesc,
+ "txDesc: link=%#x bufptr=%#x cmdsts=%#08x extsts=%#08x\n",
+ link, bufptr, cmdsts, extsts);
+
+ if (cmdsts & CMDSTS_OWN) {
+ txState = txFifoBlock;
+ txFragPtr = bufptr;
+ txDescCnt = cmdsts & CMDSTS_LEN_MASK;
+ } else {
+ devIntrPost(ISR_TXIDLE);
+ txState = txIdle;
+ goto exit;
+ }
+ break;
+
+ case txFifoBlock:
+ if (!txPacket) {
+ DPRINTF(EthernetSM, "****starting the tx of a new packet****\n");
+ txPacket = new EthPacketData(16384);
+ txPacketBufPtr = txPacket->data;
+ }
+
+ if (txDescCnt == 0) {
+ DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n");
+ if (cmdsts & CMDSTS_MORE) {
+ DPRINTF(EthernetSM, "there are more descriptors to come\n");
+ txState = txDescWrite;
+
+ cmdsts &= ~CMDSTS_OWN;
+
+ txDmaAddr = regs.txdp & 0x3fffffff;
+ txDmaData = &cmdsts;
+ if (is64bit) {
+ txDmaAddr += offsetof(ns_desc64, cmdsts);
+ txDmaLen = sizeof(txDesc64.cmdsts);
+ } else {
+ txDmaAddr += offsetof(ns_desc32, cmdsts);
+ txDmaLen = sizeof(txDesc32.cmdsts);
+ }
+ txDmaFree = dmaDescFree;
+
+ if (doTxDmaWrite())
+ goto exit;
+
+ } else { /* this packet is totally done */
+ DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n");
+ /* deal with the the packet that just finished */
+ if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) {
+ IpPtr ip(txPacket);
+ if (extsts & EXTSTS_UDPPKT) {
+ UdpPtr udp(ip);
+ udp->sum(0);
+ udp->sum(cksum(udp));
+ txUdpChecksums++;
+ } else if (extsts & EXTSTS_TCPPKT) {
+ TcpPtr tcp(ip);
+ tcp->sum(0);
+ tcp->sum(cksum(tcp));
+ txTcpChecksums++;
+ }
+ if (extsts & EXTSTS_IPPKT) {
+ ip->sum(0);
+ ip->sum(cksum(ip));
+ txIpChecksums++;
+ }
+ }
+
+ txPacket->length = txPacketBufPtr - txPacket->data;
+ // this is just because the receive can't handle a
+ // packet bigger want to make sure
+ if (txPacket->length > 1514)
+ panic("transmit packet too large, %s > 1514\n",
+ txPacket->length);
+
+#ifndef NDEBUG
+ bool success =
+#endif
+ txFifo.push(txPacket);
+ assert(success);
+
+ /*
+ * this following section is not tqo spec, but
+ * functionally shouldn't be any different. normally,
+ * the chip will wait til the transmit has occurred
+ * before writing back the descriptor because it has
+ * to wait to see that it was successfully transmitted
+ * to decide whether to set CMDSTS_OK or not.
+ * however, in the simulator since it is always
+ * successfully transmitted, and writing it exactly to
+ * spec would complicate the code, we just do it here
+ */
+
+ cmdsts &= ~CMDSTS_OWN;
+ cmdsts |= CMDSTS_OK;
+
+ DPRINTF(EthernetDesc,
+ "txDesc writeback: cmdsts=%08x extsts=%08x\n",
+ cmdsts, extsts);
+
+ txDmaFree = dmaDescFree;
+ txDmaAddr = regs.txdp & 0x3fffffff;
+ txDmaData = &cmdsts;
+ if (is64bit) {
+ txDmaAddr += offsetof(ns_desc64, cmdsts);
+ txDmaLen =
+ sizeof(txDesc64.cmdsts) + sizeof(txDesc64.extsts);
+ } else {
+ txDmaAddr += offsetof(ns_desc32, cmdsts);
+ txDmaLen =
+ sizeof(txDesc32.cmdsts) + sizeof(txDesc32.extsts);
+ }
+
+ descDmaWrites++;
+ descDmaWrBytes += txDmaLen;
+
+ transmit();
+ txPacket = 0;
+
+ if (!txEnable) {
+ DPRINTF(EthernetSM, "halting TX state machine\n");
+ txState = txIdle;
+ goto exit;
+ } else
+ txState = txAdvance;
+
+ if (doTxDmaWrite())
+ goto exit;
+ }
+ } else {
+ DPRINTF(EthernetSM, "this descriptor isn't done yet\n");
+ if (!txFifo.full()) {
+ txState = txFragRead;
+
+ /*
+ * The number of bytes transferred is either whatever
+ * is left in the descriptor (txDescCnt), or if there
+ * is not enough room in the fifo, just whatever room
+ * is left in the fifo
+ */
+ txXferLen = min<uint32_t>(txDescCnt, txFifo.avail());
+
+ txDmaAddr = txFragPtr & 0x3fffffff;
+ txDmaData = txPacketBufPtr;
+ txDmaLen = txXferLen;
+ txDmaFree = dmaDataFree;
+
+ if (doTxDmaRead())
+ goto exit;
+ } else {
+ txState = txFifoBlock;
+ transmit();
+
+ goto exit;
+ }
+
+ }
+ break;
+
+ case txFragRead:
+ if (txDmaState != dmaIdle)
+ goto exit;
+
+ txPacketBufPtr += txXferLen;
+ txFragPtr += txXferLen;
+ txDescCnt -= txXferLen;
+ txFifo.reserve(txXferLen);
+
+ txState = txFifoBlock;
+ break;
+
+ case txDescWrite:
+ if (txDmaState != dmaIdle)
+ goto exit;
+
+ if (cmdsts & CMDSTS_INTR)
+ devIntrPost(ISR_TXDESC);
+
+ if (!txEnable) {
+ DPRINTF(EthernetSM, "halting TX state machine\n");
+ txState = txIdle;
+ goto exit;
+ } else
+ txState = txAdvance;
+ break;
+
+ case txAdvance:
+ if (link == 0) {
+ devIntrPost(ISR_TXIDLE);
+ txState = txIdle;
+ goto exit;
+ } else {
+ if (txDmaState != dmaIdle)
+ goto exit;
+ txState = txDescRead;
+ regs.txdp = link;
+ CTDD = false;
+
+ txDmaAddr = link & 0x3fffffff;
+ txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32;
+ txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32);
+ txDmaFree = dmaDescFree;
+
+ if (doTxDmaRead())
+ goto exit;
+ }
+ break;
+
+ default:
+ panic("invalid state");
+ }
+
+ DPRINTF(EthernetSM, "entering next txState=%s\n",
+ NsTxStateStrings[txState]);
+ goto next;
+
+ exit:
+ /**
+ * @todo do we want to schedule a future kick?
+ */
+ DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
+ NsTxStateStrings[txState]);
+
+ if (clock && !txKickEvent.scheduled())
+ txKickEvent.schedule(txKickTick);
+}
+
+/**
+ * Advance the EEPROM state machine
+ * Called on rising edge of EEPROM clock bit in MEAR
+ */
+void
+NSGigE::eepromKick()
+{
+ switch (eepromState) {
+
+ case eepromStart:
+
+ // Wait for start bit
+ if (regs.mear & MEAR_EEDI) {
+ // Set up to get 2 opcode bits
+ eepromState = eepromGetOpcode;
+ eepromBitsToRx = 2;
+ eepromOpcode = 0;
+ }
+ break;
+
+ case eepromGetOpcode:
+ eepromOpcode <<= 1;
+ eepromOpcode += (regs.mear & MEAR_EEDI) ? 1 : 0;
+ --eepromBitsToRx;
+
+ // Done getting opcode
+ if (eepromBitsToRx == 0) {
+ if (eepromOpcode != EEPROM_READ)
+ panic("only EEPROM reads are implemented!");
+
+ // Set up to get address
+ eepromState = eepromGetAddress;
+ eepromBitsToRx = 6;
+ eepromAddress = 0;
+ }
+ break;
+
+ case eepromGetAddress:
+ eepromAddress <<= 1;
+ eepromAddress += (regs.mear & MEAR_EEDI) ? 1 : 0;
+ --eepromBitsToRx;
+
+ // Done getting address
+ if (eepromBitsToRx == 0) {
+
+ if (eepromAddress >= EEPROM_SIZE)
+ panic("EEPROM read access out of range!");
+
+ switch (eepromAddress) {
+
+ case EEPROM_PMATCH2_ADDR:
+ eepromData = rom.perfectMatch[5];
+ eepromData <<= 8;
+ eepromData += rom.perfectMatch[4];
+ break;
+
+ case EEPROM_PMATCH1_ADDR:
+ eepromData = rom.perfectMatch[3];
+ eepromData <<= 8;
+ eepromData += rom.perfectMatch[2];
+ break;
+
+ case EEPROM_PMATCH0_ADDR:
+ eepromData = rom.perfectMatch[1];
+ eepromData <<= 8;
+ eepromData += rom.perfectMatch[0];
+ break;
+
+ default:
+ panic("FreeBSD driver only uses EEPROM to read PMATCH!");
+ }
+ // Set up to read data
+ eepromState = eepromRead;
+ eepromBitsToRx = 16;
+
+ // Clear data in bit
+ regs.mear &= ~MEAR_EEDI;
+ }
+ break;
+
+ case eepromRead:
+ // Clear Data Out bit
+ regs.mear &= ~MEAR_EEDO;
+ // Set bit to value of current EEPROM bit
+ regs.mear |= (eepromData & 0x8000) ? MEAR_EEDO : 0x0;
+
+ eepromData <<= 1;
+ --eepromBitsToRx;
+
+ // All done
+ if (eepromBitsToRx == 0) {
+ eepromState = eepromStart;
+ }
+ break;
+
+ default:
+ panic("invalid EEPROM state");
+ }
+
+}
+
+void
+NSGigE::transferDone()
+{
+ if (txFifo.empty()) {
+ DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
+ return;
+ }
+
+ DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
+
+ if (txEvent.scheduled())
+ txEvent.reschedule(curTick + cycles(1));
+ else
+ txEvent.schedule(curTick + cycles(1));
+}
+
+bool
+NSGigE::rxFilter(const EthPacketPtr &packet)
+{
+ EthPtr eth = packet;
+ bool drop = true;
+ string type;
+
+ const EthAddr &dst = eth->dst();
+ if (dst.unicast()) {
+ // If we're accepting all unicast addresses
+ if (acceptUnicast)
+ drop = false;
+
+ // If we make a perfect match
+ if (acceptPerfect && dst == rom.perfectMatch)
+ drop = false;
+
+ if (acceptArp && eth->type() == ETH_TYPE_ARP)
+ drop = false;
+
+ } else if (dst.broadcast()) {
+ // if we're accepting broadcasts
+ if (acceptBroadcast)
+ drop = false;
+
+ } else if (dst.multicast()) {
+ // if we're accepting all multicasts
+ if (acceptMulticast)
+ drop = false;
+
+ // Multicast hashing faked - all packets accepted
+ if (multicastHashEnable)
+ drop = false;
+ }
+
+ if (drop) {
+ DPRINTF(Ethernet, "rxFilter drop\n");
+ DDUMP(EthernetData, packet->data, packet->length);
+ }
+
+ return drop;
+}
+
+bool
+NSGigE::recvPacket(EthPacketPtr packet)
+{
+ rxBytes += packet->length;
+ rxPackets++;
+
+ DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n",
+ rxFifo.avail());
+
+ if (!rxEnable) {
+ DPRINTF(Ethernet, "receive disabled...packet dropped\n");
+ return true;
+ }
+
+ if (!rxFilterEnable) {
+ DPRINTF(Ethernet,
+ "receive packet filtering disabled . . . packet dropped\n");
+ return true;
+ }
+
+ if (rxFilter(packet)) {
+ DPRINTF(Ethernet, "packet filtered...dropped\n");
+ return true;
+ }
+
+ if (rxFifo.avail() < packet->length) {
+#if TRACING_ON
+ IpPtr ip(packet);
+ TcpPtr tcp(ip);
+ if (ip) {
+ DPRINTF(Ethernet,
+ "packet won't fit in receive buffer...pkt ID %d dropped\n",
+ ip->id());
+ if (tcp) {
+ DPRINTF(Ethernet, "Seq=%d\n", tcp->seq());
+ }
+ }
+#endif
+ droppedPackets++;
+ devIntrPost(ISR_RXORN);
+ return false;
+ }
+
+ rxFifo.push(packet);
+
+ rxKick();
+ return true;
+}
+
+//=====================================================================
+//
+//
+void
+NSGigE::serialize(ostream &os)
+{
+ // Serialize the PciDev base class
+ PciDev::serialize(os);
+
+ /*
+ * Finalize any DMA events now.
+ */
+ // @todo will mem system save pending dma?
+
+ /*
+ * Serialize the device registers
+ */
+ SERIALIZE_SCALAR(regs.command);
+ SERIALIZE_SCALAR(regs.config);
+ SERIALIZE_SCALAR(regs.mear);
+ SERIALIZE_SCALAR(regs.ptscr);
+ SERIALIZE_SCALAR(regs.isr);
+ SERIALIZE_SCALAR(regs.imr);
+ SERIALIZE_SCALAR(regs.ier);
+ SERIALIZE_SCALAR(regs.ihr);
+ SERIALIZE_SCALAR(regs.txdp);
+ SERIALIZE_SCALAR(regs.txdp_hi);
+ SERIALIZE_SCALAR(regs.txcfg);
+ SERIALIZE_SCALAR(regs.gpior);
+ SERIALIZE_SCALAR(regs.rxdp);
+ SERIALIZE_SCALAR(regs.rxdp_hi);
+ SERIALIZE_SCALAR(regs.rxcfg);
+ SERIALIZE_SCALAR(regs.pqcr);
+ SERIALIZE_SCALAR(regs.wcsr);
+ SERIALIZE_SCALAR(regs.pcr);
+ SERIALIZE_SCALAR(regs.rfcr);
+ SERIALIZE_SCALAR(regs.rfdr);
+ SERIALIZE_SCALAR(regs.brar);
+ SERIALIZE_SCALAR(regs.brdr);
+ SERIALIZE_SCALAR(regs.srr);
+ SERIALIZE_SCALAR(regs.mibc);
+ SERIALIZE_SCALAR(regs.vrcr);
+ SERIALIZE_SCALAR(regs.vtcr);
+ SERIALIZE_SCALAR(regs.vdr);
+ SERIALIZE_SCALAR(regs.ccsr);
+ SERIALIZE_SCALAR(regs.tbicr);
+ SERIALIZE_SCALAR(regs.tbisr);
+ SERIALIZE_SCALAR(regs.tanar);
+ SERIALIZE_SCALAR(regs.tanlpar);
+ SERIALIZE_SCALAR(regs.taner);
+ SERIALIZE_SCALAR(regs.tesr);
+
+ SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
+ SERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE);
+
+ SERIALIZE_SCALAR(ioEnable);
+
+ /*
+ * Serialize the data Fifos
+ */
+ rxFifo.serialize("rxFifo", os);
+ txFifo.serialize("txFifo", os);
+
+ /*
+ * Serialize the various helper variables
+ */
+ bool txPacketExists = txPacket;
+ SERIALIZE_SCALAR(txPacketExists);
+ if (txPacketExists) {
+ txPacket->length = txPacketBufPtr - txPacket->data;
+ txPacket->serialize("txPacket", os);
+ uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data);
+ SERIALIZE_SCALAR(txPktBufPtr);
+ }
+
+ bool rxPacketExists = rxPacket;
+ SERIALIZE_SCALAR(rxPacketExists);
+ if (rxPacketExists) {
+ rxPacket->serialize("rxPacket", os);
+ uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data);
+ SERIALIZE_SCALAR(rxPktBufPtr);
+ }
+
+ SERIALIZE_SCALAR(txXferLen);
+ SERIALIZE_SCALAR(rxXferLen);
+
+ /*
+ * Serialize Cached Descriptors
+ */
+ SERIALIZE_SCALAR(rxDesc64.link);
+ SERIALIZE_SCALAR(rxDesc64.bufptr);
+ SERIALIZE_SCALAR(rxDesc64.cmdsts);
+ SERIALIZE_SCALAR(rxDesc64.extsts);
+ SERIALIZE_SCALAR(txDesc64.link);
+ SERIALIZE_SCALAR(txDesc64.bufptr);
+ SERIALIZE_SCALAR(txDesc64.cmdsts);
+ SERIALIZE_SCALAR(txDesc64.extsts);
+ SERIALIZE_SCALAR(rxDesc32.link);
+ SERIALIZE_SCALAR(rxDesc32.bufptr);
+ SERIALIZE_SCALAR(rxDesc32.cmdsts);
+ SERIALIZE_SCALAR(rxDesc32.extsts);
+ SERIALIZE_SCALAR(txDesc32.link);
+ SERIALIZE_SCALAR(txDesc32.bufptr);
+ SERIALIZE_SCALAR(txDesc32.cmdsts);
+ SERIALIZE_SCALAR(txDesc32.extsts);
+ SERIALIZE_SCALAR(extstsEnable);
+
+ /*
+ * Serialize tx state machine
+ */
+ int txState = this->txState;
+ SERIALIZE_SCALAR(txState);
+ SERIALIZE_SCALAR(txEnable);
+ SERIALIZE_SCALAR(CTDD);
+ SERIALIZE_SCALAR(txFragPtr);
+ SERIALIZE_SCALAR(txDescCnt);
+ int txDmaState = this->txDmaState;
+ SERIALIZE_SCALAR(txDmaState);
+ SERIALIZE_SCALAR(txKickTick);
+
+ /*
+ * Serialize rx state machine
+ */
+ int rxState = this->rxState;
+ SERIALIZE_SCALAR(rxState);
+ SERIALIZE_SCALAR(rxEnable);
+ SERIALIZE_SCALAR(CRDD);
+ SERIALIZE_SCALAR(rxPktBytes);
+ SERIALIZE_SCALAR(rxFragPtr);
+ SERIALIZE_SCALAR(rxDescCnt);
+ int rxDmaState = this->rxDmaState;
+ SERIALIZE_SCALAR(rxDmaState);
+ SERIALIZE_SCALAR(rxKickTick);
+
+ /*
+ * Serialize EEPROM state machine
+ */
+ int eepromState = this->eepromState;
+ SERIALIZE_SCALAR(eepromState);
+ SERIALIZE_SCALAR(eepromClk);
+ SERIALIZE_SCALAR(eepromBitsToRx);
+ SERIALIZE_SCALAR(eepromOpcode);
+ SERIALIZE_SCALAR(eepromAddress);
+ SERIALIZE_SCALAR(eepromData);
+
+ /*
+ * If there's a pending transmit, store the time so we can
+ * reschedule it later
+ */
+ Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0;
+ SERIALIZE_SCALAR(transmitTick);
+
+ /*
+ * receive address filter settings
+ */
+ SERIALIZE_SCALAR(rxFilterEnable);
+ SERIALIZE_SCALAR(acceptBroadcast);
+ SERIALIZE_SCALAR(acceptMulticast);
+ SERIALIZE_SCALAR(acceptUnicast);
+ SERIALIZE_SCALAR(acceptPerfect);
+ SERIALIZE_SCALAR(acceptArp);
+ SERIALIZE_SCALAR(multicastHashEnable);
+
+ /*
+ * Keep track of pending interrupt status.
+ */
+ SERIALIZE_SCALAR(intrTick);
+ SERIALIZE_SCALAR(cpuPendingIntr);
+ Tick intrEventTick = 0;
+ if (intrEvent)
+ intrEventTick = intrEvent->when();
+ SERIALIZE_SCALAR(intrEventTick);
+
+}
+
+void
+NSGigE::unserialize(Checkpoint *cp, const std::string &section)
+{
+ // Unserialize the PciDev base class
+ PciDev::unserialize(cp, section);
+
+ UNSERIALIZE_SCALAR(regs.command);
+ UNSERIALIZE_SCALAR(regs.config);
+ UNSERIALIZE_SCALAR(regs.mear);
+ UNSERIALIZE_SCALAR(regs.ptscr);
+ UNSERIALIZE_SCALAR(regs.isr);
+ UNSERIALIZE_SCALAR(regs.imr);
+ UNSERIALIZE_SCALAR(regs.ier);
+ UNSERIALIZE_SCALAR(regs.ihr);
+ UNSERIALIZE_SCALAR(regs.txdp);
+ UNSERIALIZE_SCALAR(regs.txdp_hi);
+ UNSERIALIZE_SCALAR(regs.txcfg);
+ UNSERIALIZE_SCALAR(regs.gpior);
+ UNSERIALIZE_SCALAR(regs.rxdp);
+ UNSERIALIZE_SCALAR(regs.rxdp_hi);
+ UNSERIALIZE_SCALAR(regs.rxcfg);
+ UNSERIALIZE_SCALAR(regs.pqcr);
+ UNSERIALIZE_SCALAR(regs.wcsr);
+ UNSERIALIZE_SCALAR(regs.pcr);
+ UNSERIALIZE_SCALAR(regs.rfcr);
+ UNSERIALIZE_SCALAR(regs.rfdr);
+ UNSERIALIZE_SCALAR(regs.brar);
+ UNSERIALIZE_SCALAR(regs.brdr);
+ UNSERIALIZE_SCALAR(regs.srr);
+ UNSERIALIZE_SCALAR(regs.mibc);
+ UNSERIALIZE_SCALAR(regs.vrcr);
+ UNSERIALIZE_SCALAR(regs.vtcr);
+ UNSERIALIZE_SCALAR(regs.vdr);
+ UNSERIALIZE_SCALAR(regs.ccsr);
+ UNSERIALIZE_SCALAR(regs.tbicr);
+ UNSERIALIZE_SCALAR(regs.tbisr);
+ UNSERIALIZE_SCALAR(regs.tanar);
+ UNSERIALIZE_SCALAR(regs.tanlpar);
+ UNSERIALIZE_SCALAR(regs.taner);
+ UNSERIALIZE_SCALAR(regs.tesr);
+
+ UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
+ UNSERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE);
+
+ UNSERIALIZE_SCALAR(ioEnable);
+
+ /*
+ * unserialize the data fifos
+ */
+ rxFifo.unserialize("rxFifo", cp, section);
+ txFifo.unserialize("txFifo", cp, section);
+
+ /*
+ * unserialize the various helper variables
+ */
+ bool txPacketExists;
+ UNSERIALIZE_SCALAR(txPacketExists);
+ if (txPacketExists) {
+ txPacket = new EthPacketData(16384);
+ txPacket->unserialize("txPacket", cp, section);
+ uint32_t txPktBufPtr;
+ UNSERIALIZE_SCALAR(txPktBufPtr);
+ txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr;
+ } else
+ txPacket = 0;
+
+ bool rxPacketExists;
+ UNSERIALIZE_SCALAR(rxPacketExists);
+ rxPacket = 0;
+ if (rxPacketExists) {
+ rxPacket = new EthPacketData(16384);
+ rxPacket->unserialize("rxPacket", cp, section);
+ uint32_t rxPktBufPtr;
+ UNSERIALIZE_SCALAR(rxPktBufPtr);
+ rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr;
+ } else
+ rxPacket = 0;
+
+ UNSERIALIZE_SCALAR(txXferLen);
+ UNSERIALIZE_SCALAR(rxXferLen);
+
+ /*
+ * Unserialize Cached Descriptors
+ */
+ UNSERIALIZE_SCALAR(rxDesc64.link);
+ UNSERIALIZE_SCALAR(rxDesc64.bufptr);
+ UNSERIALIZE_SCALAR(rxDesc64.cmdsts);
+ UNSERIALIZE_SCALAR(rxDesc64.extsts);
+ UNSERIALIZE_SCALAR(txDesc64.link);
+ UNSERIALIZE_SCALAR(txDesc64.bufptr);
+ UNSERIALIZE_SCALAR(txDesc64.cmdsts);
+ UNSERIALIZE_SCALAR(txDesc64.extsts);
+ UNSERIALIZE_SCALAR(rxDesc32.link);
+ UNSERIALIZE_SCALAR(rxDesc32.bufptr);
+ UNSERIALIZE_SCALAR(rxDesc32.cmdsts);
+ UNSERIALIZE_SCALAR(rxDesc32.extsts);
+ UNSERIALIZE_SCALAR(txDesc32.link);
+ UNSERIALIZE_SCALAR(txDesc32.bufptr);
+ UNSERIALIZE_SCALAR(txDesc32.cmdsts);
+ UNSERIALIZE_SCALAR(txDesc32.extsts);
+ UNSERIALIZE_SCALAR(extstsEnable);
+
+ /*
+ * unserialize tx state machine
+ */
+ int txState;
+ UNSERIALIZE_SCALAR(txState);
+ this->txState = (TxState) txState;
+ UNSERIALIZE_SCALAR(txEnable);
+ UNSERIALIZE_SCALAR(CTDD);
+ UNSERIALIZE_SCALAR(txFragPtr);
+ UNSERIALIZE_SCALAR(txDescCnt);
+ int txDmaState;
+ UNSERIALIZE_SCALAR(txDmaState);
+ this->txDmaState = (DmaState) txDmaState;
+ UNSERIALIZE_SCALAR(txKickTick);
+ if (txKickTick)
+ txKickEvent.schedule(txKickTick);
+
+ /*
+ * unserialize rx state machine
+ */
+ int rxState;
+ UNSERIALIZE_SCALAR(rxState);
+ this->rxState = (RxState) rxState;
+ UNSERIALIZE_SCALAR(rxEnable);
+ UNSERIALIZE_SCALAR(CRDD);
+ UNSERIALIZE_SCALAR(rxPktBytes);
+ UNSERIALIZE_SCALAR(rxFragPtr);
+ UNSERIALIZE_SCALAR(rxDescCnt);
+ int rxDmaState;
+ UNSERIALIZE_SCALAR(rxDmaState);
+ this->rxDmaState = (DmaState) rxDmaState;
+ UNSERIALIZE_SCALAR(rxKickTick);
+ if (rxKickTick)
+ rxKickEvent.schedule(rxKickTick);
+
+ /*
+ * Unserialize EEPROM state machine
+ */
+ int eepromState;
+ UNSERIALIZE_SCALAR(eepromState);
+ this->eepromState = (EEPROMState) eepromState;
+ UNSERIALIZE_SCALAR(eepromClk);
+ UNSERIALIZE_SCALAR(eepromBitsToRx);
+ UNSERIALIZE_SCALAR(eepromOpcode);
+ UNSERIALIZE_SCALAR(eepromAddress);
+ UNSERIALIZE_SCALAR(eepromData);
+
+ /*
+ * If there's a pending transmit, reschedule it now
+ */
+ Tick transmitTick;
+ UNSERIALIZE_SCALAR(transmitTick);
+ if (transmitTick)
+ txEvent.schedule(curTick + transmitTick);
+
+ /*
+ * unserialize receive address filter settings
+ */
+ UNSERIALIZE_SCALAR(rxFilterEnable);
+ UNSERIALIZE_SCALAR(acceptBroadcast);
+ UNSERIALIZE_SCALAR(acceptMulticast);
+ UNSERIALIZE_SCALAR(acceptUnicast);
+ UNSERIALIZE_SCALAR(acceptPerfect);
+ UNSERIALIZE_SCALAR(acceptArp);
+ UNSERIALIZE_SCALAR(multicastHashEnable);
+
+ /*
+ * Keep track of pending interrupt status.
+ */
+ UNSERIALIZE_SCALAR(intrTick);
+ UNSERIALIZE_SCALAR(cpuPendingIntr);
+ Tick intrEventTick;
+ UNSERIALIZE_SCALAR(intrEventTick);
+ if (intrEventTick) {
+ intrEvent = new IntrEvent(this, true);
+ intrEvent->schedule(intrEventTick);
+ }
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
+
+ SimObjectParam<EtherInt *> peer;
+ SimObjectParam<NSGigE *> device;
+
+END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
+
+ INIT_PARAM_DFLT(peer, "peer interface", NULL),
+ INIT_PARAM(device, "Ethernet device of this interface")
+
+END_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
+
+CREATE_SIM_OBJECT(NSGigEInt)
+{
+ NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device);
+
+ EtherInt *p = (EtherInt *)peer;
+ if (p) {
+ dev_int->setPeer(p);
+ p->setPeer(dev_int);
+ }
+
+ return dev_int;
+}
+
+REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt)
+
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
+
+ SimObjectParam<System *> system;
+ SimObjectParam<Platform *> platform;
+ SimObjectParam<PciConfigAll *> configspace;
+ SimObjectParam<PciConfigData *> configdata;
+ Param<uint32_t> pci_bus;
+ Param<uint32_t> pci_dev;
+ Param<uint32_t> pci_func;
+ Param<Tick> pio_latency;
+
+ Param<Tick> clock;
+ Param<bool> dma_desc_free;
+ Param<bool> dma_data_free;
+ Param<Tick> dma_read_delay;
+ Param<Tick> dma_write_delay;
+ Param<Tick> dma_read_factor;
+ Param<Tick> dma_write_factor;
+ Param<bool> dma_no_allocate;
+ Param<Tick> intr_delay;
+
+ Param<Tick> rx_delay;
+ Param<Tick> tx_delay;
+ Param<uint32_t> rx_fifo_size;
+ Param<uint32_t> tx_fifo_size;
+
+ Param<bool> rx_filter;
+ Param<string> hardware_address;
+ Param<bool> rx_thread;
+ Param<bool> tx_thread;
+ Param<bool> rss;
+
+END_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE)
+
+ INIT_PARAM(system, "System pointer"),
+ INIT_PARAM(platform, "Platform pointer"),
+ INIT_PARAM(configspace, "PCI Configspace"),
+ INIT_PARAM(configdata, "PCI Config data"),
+ INIT_PARAM(pci_bus, "PCI bus ID"),
+ INIT_PARAM(pci_dev, "PCI device number"),
+ INIT_PARAM(pci_func, "PCI function code"),
+ INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
+ INIT_PARAM(clock, "State machine cycle time"),
+
+ INIT_PARAM(dma_desc_free, "DMA of Descriptors is free"),
+ INIT_PARAM(dma_data_free, "DMA of Data is free"),
+ INIT_PARAM(dma_read_delay, "fixed delay for dma reads"),
+ INIT_PARAM(dma_write_delay, "fixed delay for dma writes"),
+ INIT_PARAM(dma_read_factor, "multiplier for dma reads"),
+ INIT_PARAM(dma_write_factor, "multiplier for dma writes"),
+ INIT_PARAM(dma_no_allocate, "Should DMA reads allocate cache lines"),
+ INIT_PARAM(intr_delay, "Interrupt Delay in microseconds"),
+
+ INIT_PARAM(rx_delay, "Receive Delay"),
+ INIT_PARAM(tx_delay, "Transmit Delay"),
+ INIT_PARAM(rx_fifo_size, "max size in bytes of rxFifo"),
+ INIT_PARAM(tx_fifo_size, "max size in bytes of txFifo"),
+
+ INIT_PARAM(rx_filter, "Enable Receive Filter"),
+ INIT_PARAM(hardware_address, "Ethernet Hardware Address"),
+ INIT_PARAM(rx_thread, ""),
+ INIT_PARAM(tx_thread, ""),
+ INIT_PARAM(rss, "")
+
+END_INIT_SIM_OBJECT_PARAMS(NSGigE)
+
+
+CREATE_SIM_OBJECT(NSGigE)
+{
+ NSGigE::Params *params = new NSGigE::Params;
+
+ params->name = getInstanceName();
+ params->platform = platform;
+ params->system = system;
+ params->configSpace = configspace;
+ params->configData = configdata;
+ params->busNum = pci_bus;
+ params->deviceNum = pci_dev;
+ params->functionNum = pci_func;
+ params->pio_delay = pio_latency;
+
+ params->clock = clock;
+ params->dma_desc_free = dma_desc_free;
+ params->dma_data_free = dma_data_free;
+ params->dma_read_delay = dma_read_delay;
+ params->dma_write_delay = dma_write_delay;
+ params->dma_read_factor = dma_read_factor;
+ params->dma_write_factor = dma_write_factor;
+ params->dma_no_allocate = dma_no_allocate;
+ params->pio_delay = pio_latency;
+ params->intr_delay = intr_delay;
+
+ params->rx_delay = rx_delay;
+ params->tx_delay = tx_delay;
+ params->rx_fifo_size = rx_fifo_size;
+ params->tx_fifo_size = tx_fifo_size;
+
+ params->rx_filter = rx_filter;
+ params->eaddr = hardware_address;
+ params->rx_thread = rx_thread;
+ params->tx_thread = tx_thread;
+ params->rss = rss;
+
+ return new NSGigE(params);
+}
+
+REGISTER_SIM_OBJECT("NSGigE", NSGigE)
diff --git a/src/dev/ns_gige.hh b/src/dev/ns_gige.hh
new file mode 100644
index 000000000..51520fd00
--- /dev/null
+++ b/src/dev/ns_gige.hh
@@ -0,0 +1,463 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * Device module for modelling the National Semiconductor
+ * DP83820 ethernet controller
+ */
+
+#ifndef __DEV_NS_GIGE_HH__
+#define __DEV_NS_GIGE_HH__
+
+#include "base/inet.hh"
+#include "base/statistics.hh"
+#include "dev/etherint.hh"
+#include "dev/etherpkt.hh"
+#include "dev/io_device.hh"
+#include "dev/ns_gige_reg.h"
+#include "dev/pcidev.hh"
+#include "dev/pktfifo.hh"
+#include "sim/eventq.hh"
+
+// Hash filtering constants
+const uint16_t FHASH_ADDR = 0x100;
+const uint16_t FHASH_SIZE = 0x100;
+
+// EEPROM constants
+const uint8_t EEPROM_READ = 0x2;
+const uint8_t EEPROM_SIZE = 64; // Size in words of NSC93C46 EEPROM
+const uint8_t EEPROM_PMATCH2_ADDR = 0xA; // EEPROM Address of PMATCH word 2
+const uint8_t EEPROM_PMATCH1_ADDR = 0xB; // EEPROM Address of PMATCH word 1
+const uint8_t EEPROM_PMATCH0_ADDR = 0xC; // EEPROM Address of PMATCH word 0
+
+/**
+ * Ethernet device registers
+ */
+struct dp_regs {
+ uint32_t command;
+ uint32_t config;
+ uint32_t mear;
+ uint32_t ptscr;
+ uint32_t isr;
+ uint32_t imr;
+ uint32_t ier;
+ uint32_t ihr;
+ uint32_t txdp;
+ uint32_t txdp_hi;
+ uint32_t txcfg;
+ uint32_t gpior;
+ uint32_t rxdp;
+ uint32_t rxdp_hi;
+ uint32_t rxcfg;
+ uint32_t pqcr;
+ uint32_t wcsr;
+ uint32_t pcr;
+ uint32_t rfcr;
+ uint32_t rfdr;
+ uint32_t brar;
+ uint32_t brdr;
+ uint32_t srr;
+ uint32_t mibc;
+ uint32_t vrcr;
+ uint32_t vtcr;
+ uint32_t vdr;
+ uint32_t ccsr;
+ uint32_t tbicr;
+ uint32_t tbisr;
+ uint32_t tanar;
+ uint32_t tanlpar;
+ uint32_t taner;
+ uint32_t tesr;
+};
+
+struct dp_rom {
+ /**
+ * for perfect match memory.
+ * the linux driver doesn't use any other ROM
+ */
+ uint8_t perfectMatch[ETH_ADDR_LEN];
+
+ /**
+ * for hash table memory.
+ * used by the freebsd driver
+ */
+ uint8_t filterHash[FHASH_SIZE];
+};
+
+class NSGigEInt;
+class Packet;
+class PciConfigAll;
+
+/**
+ * NS DP83820 Ethernet device model
+ */
+class NSGigE : public PciDev
+{
+ public:
+ /** Transmit State Machine states */
+ enum TxState
+ {
+ txIdle,
+ txDescRefr,
+ txDescRead,
+ txFifoBlock,
+ txFragRead,
+ txDescWrite,
+ txAdvance
+ };
+
+ /** Receive State Machine States */
+ enum RxState
+ {
+ rxIdle,
+ rxDescRefr,
+ rxDescRead,
+ rxFifoBlock,
+ rxFragWrite,
+ rxDescWrite,
+ rxAdvance
+ };
+
+ enum DmaState
+ {
+ dmaIdle,
+ dmaReading,
+ dmaWriting,
+ dmaReadWaiting,
+ dmaWriteWaiting
+ };
+
+ /** EEPROM State Machine States */
+ enum EEPROMState
+ {
+ eepromStart,
+ eepromGetOpcode,
+ eepromGetAddress,
+ eepromRead
+ };
+
+ protected:
+ /** device register file */
+ dp_regs regs;
+ dp_rom rom;
+
+ /** pci settings */
+ bool ioEnable;
+#if 0
+ bool memEnable;
+ bool bmEnable;
+#endif
+
+ /*** BASIC STRUCTURES FOR TX/RX ***/
+ /* Data FIFOs */
+ PacketFifo txFifo;
+ PacketFifo rxFifo;
+
+ /** various helper vars */
+ EthPacketPtr txPacket;
+ EthPacketPtr rxPacket;
+ uint8_t *txPacketBufPtr;
+ uint8_t *rxPacketBufPtr;
+ uint32_t txXferLen;
+ uint32_t rxXferLen;
+ bool rxDmaFree;
+ bool txDmaFree;
+
+ /** DescCaches */
+ ns_desc32 txDesc32;
+ ns_desc32 rxDesc32;
+ ns_desc64 txDesc64;
+ ns_desc64 rxDesc64;
+
+ /* state machine cycle time */
+ Tick clock;
+ inline Tick cycles(int numCycles) const { return numCycles * clock; }
+
+ /* tx State Machine */
+ TxState txState;
+ bool txEnable;
+
+ /** Current Transmit Descriptor Done */
+ bool CTDD;
+ /** halt the tx state machine after next packet */
+ bool txHalt;
+ /** ptr to the next byte in the current fragment */
+ Addr txFragPtr;
+ /** count of bytes remaining in the current descriptor */
+ uint32_t txDescCnt;
+ DmaState txDmaState;
+
+ /** rx State Machine */
+ RxState rxState;
+ bool rxEnable;
+
+ /** Current Receive Descriptor Done */
+ bool CRDD;
+ /** num of bytes in the current packet being drained from rxDataFifo */
+ uint32_t rxPktBytes;
+ /** halt the rx state machine after current packet */
+ bool rxHalt;
+ /** ptr to the next byte in current fragment */
+ Addr rxFragPtr;
+ /** count of bytes remaining in the current descriptor */
+ uint32_t rxDescCnt;
+ DmaState rxDmaState;
+
+ bool extstsEnable;
+
+ /** EEPROM State Machine */
+ EEPROMState eepromState;
+ bool eepromClk;
+ uint8_t eepromBitsToRx;
+ uint8_t eepromOpcode;
+ uint8_t eepromAddress;
+ uint16_t eepromData;
+
+ protected:
+ Tick dmaReadDelay;
+ Tick dmaWriteDelay;
+
+ Tick dmaReadFactor;
+ Tick dmaWriteFactor;
+
+ void *rxDmaData;
+ Addr rxDmaAddr;
+ int rxDmaLen;
+ bool doRxDmaRead();
+ bool doRxDmaWrite();
+
+ void *txDmaData;
+ Addr txDmaAddr;
+ int txDmaLen;
+ bool doTxDmaRead();
+ bool doTxDmaWrite();
+
+ void rxDmaReadDone();
+ friend class EventWrapper<NSGigE, &NSGigE::rxDmaReadDone>;
+ EventWrapper<NSGigE, &NSGigE::rxDmaReadDone> rxDmaReadEvent;
+
+ void rxDmaWriteDone();
+ friend class EventWrapper<NSGigE, &NSGigE::rxDmaWriteDone>;
+ EventWrapper<NSGigE, &NSGigE::rxDmaWriteDone> rxDmaWriteEvent;
+
+ void txDmaReadDone();
+ friend class EventWrapper<NSGigE, &NSGigE::txDmaReadDone>;
+ EventWrapper<NSGigE, &NSGigE::txDmaReadDone> txDmaReadEvent;
+
+ void txDmaWriteDone();
+ friend class EventWrapper<NSGigE, &NSGigE::txDmaWriteDone>;
+ EventWrapper<NSGigE, &NSGigE::txDmaWriteDone> txDmaWriteEvent;
+
+ bool dmaDescFree;
+ bool dmaDataFree;
+
+ protected:
+ Tick txDelay;
+ Tick rxDelay;
+
+ void txReset();
+ void rxReset();
+ void regsReset();
+
+ void rxKick();
+ Tick rxKickTick;
+ typedef EventWrapper<NSGigE, &NSGigE::rxKick> RxKickEvent;
+ friend void RxKickEvent::process();
+ RxKickEvent rxKickEvent;
+
+ void txKick();
+ Tick txKickTick;
+ typedef EventWrapper<NSGigE, &NSGigE::txKick> TxKickEvent;
+ friend void TxKickEvent::process();
+ TxKickEvent txKickEvent;
+
+ void eepromKick();
+
+ /**
+ * Retransmit event
+ */
+ void transmit();
+ void txEventTransmit()
+ {
+ transmit();
+ if (txState == txFifoBlock)
+ txKick();
+ }
+ typedef EventWrapper<NSGigE, &NSGigE::txEventTransmit> TxEvent;
+ friend void TxEvent::process();
+ TxEvent txEvent;
+
+ void txDump() const;
+ void rxDump() const;
+
+ /**
+ * receive address filter
+ */
+ bool rxFilterEnable;
+ bool rxFilter(const EthPacketPtr &packet);
+ bool acceptBroadcast;
+ bool acceptMulticast;
+ bool acceptUnicast;
+ bool acceptPerfect;
+ bool acceptArp;
+ bool multicastHashEnable;
+
+ /**
+ * Interrupt management
+ */
+ void devIntrPost(uint32_t interrupts);
+ void devIntrClear(uint32_t interrupts);
+ void devIntrChangeMask();
+
+ Tick intrDelay;
+ Tick intrTick;
+ bool cpuPendingIntr;
+ void cpuIntrPost(Tick when);
+ void cpuInterrupt();
+ void cpuIntrClear();
+
+ typedef EventWrapper<NSGigE, &NSGigE::cpuInterrupt> IntrEvent;
+ friend void IntrEvent::process();
+ IntrEvent *intrEvent;
+ NSGigEInt *interface;
+
+ public:
+ struct Params : public PciDev::Params
+ {
+ Tick clock;
+ Tick intr_delay;
+ Tick tx_delay;
+ Tick rx_delay;
+ bool dma_desc_free;
+ bool dma_data_free;
+ Tick dma_read_delay;
+ Tick dma_write_delay;
+ Tick dma_read_factor;
+ Tick dma_write_factor;
+ bool rx_filter;
+ Net::EthAddr eaddr;
+ uint32_t tx_fifo_size;
+ uint32_t rx_fifo_size;
+ bool rx_thread;
+ bool tx_thread;
+ bool rss;
+ bool dma_no_allocate;
+ };
+
+ NSGigE(Params *params);
+ ~NSGigE();
+ const Params *params() const { return (const Params *)_params; }
+
+ virtual void writeConfig(int offset, const uint16_t data);
+
+ virtual Tick read(Packet *pkt);
+ virtual Tick write(Packet *pkt);
+
+ bool cpuIntrPending() const;
+ void cpuIntrAck() { cpuIntrClear(); }
+
+ bool recvPacket(EthPacketPtr packet);
+ void transferDone();
+
+ void setInterface(NSGigEInt *i) { assert(!interface); interface = i; }
+
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+
+ public:
+ void regStats();
+
+ private:
+ Stats::Scalar<> txBytes;
+ Stats::Scalar<> rxBytes;
+ Stats::Scalar<> txPackets;
+ Stats::Scalar<> rxPackets;
+ Stats::Scalar<> txIpChecksums;
+ Stats::Scalar<> rxIpChecksums;
+ Stats::Scalar<> txTcpChecksums;
+ Stats::Scalar<> rxTcpChecksums;
+ Stats::Scalar<> txUdpChecksums;
+ Stats::Scalar<> rxUdpChecksums;
+ Stats::Scalar<> descDmaReads;
+ Stats::Scalar<> descDmaWrites;
+ Stats::Scalar<> descDmaRdBytes;
+ Stats::Scalar<> descDmaWrBytes;
+ Stats::Formula totBandwidth;
+ Stats::Formula totPackets;
+ Stats::Formula totBytes;
+ Stats::Formula totPacketRate;
+ Stats::Formula txBandwidth;
+ Stats::Formula rxBandwidth;
+ Stats::Formula txPacketRate;
+ Stats::Formula rxPacketRate;
+ Stats::Scalar<> postedSwi;
+ Stats::Formula coalescedSwi;
+ Stats::Scalar<> totalSwi;
+ Stats::Scalar<> postedRxIdle;
+ Stats::Formula coalescedRxIdle;
+ Stats::Scalar<> totalRxIdle;
+ Stats::Scalar<> postedRxOk;
+ Stats::Formula coalescedRxOk;
+ Stats::Scalar<> totalRxOk;
+ Stats::Scalar<> postedRxDesc;
+ Stats::Formula coalescedRxDesc;
+ Stats::Scalar<> totalRxDesc;
+ Stats::Scalar<> postedTxOk;
+ Stats::Formula coalescedTxOk;
+ Stats::Scalar<> totalTxOk;
+ Stats::Scalar<> postedTxIdle;
+ Stats::Formula coalescedTxIdle;
+ Stats::Scalar<> totalTxIdle;
+ Stats::Scalar<> postedTxDesc;
+ Stats::Formula coalescedTxDesc;
+ Stats::Scalar<> totalTxDesc;
+ Stats::Scalar<> postedRxOrn;
+ Stats::Formula coalescedRxOrn;
+ Stats::Scalar<> totalRxOrn;
+ Stats::Formula coalescedTotal;
+ Stats::Scalar<> postedInterrupts;
+ Stats::Scalar<> droppedPackets;
+};
+
+/*
+ * Ethernet Interface for an Ethernet Device
+ */
+class NSGigEInt : public EtherInt
+{
+ private:
+ NSGigE *dev;
+
+ public:
+ NSGigEInt(const std::string &name, NSGigE *d)
+ : EtherInt(name), dev(d) { dev->setInterface(this); }
+
+ virtual bool recvPacket(EthPacketPtr pkt) { return dev->recvPacket(pkt); }
+ virtual void sendDone() { dev->transferDone(); }
+};
+
+#endif // __DEV_NS_GIGE_HH__
diff --git a/src/dev/ns_gige_reg.h b/src/dev/ns_gige_reg.h
new file mode 100644
index 000000000..5f6fa2cc5
--- /dev/null
+++ b/src/dev/ns_gige_reg.h
@@ -0,0 +1,351 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * Ethernet device register definitions for the National
+ * Semiconductor DP83820 Ethernet controller
+ */
+
+#ifndef __DEV_NS_GIGE_REG_H__
+#define __DEV_NS_GIGE_REG_H__
+
+/* Device Register Address Map */
+#define CR 0x00
+#define CFGR 0x04
+#define MEAR 0x08
+#define PTSCR 0x0c
+#define ISR 0x10
+#define IMR 0x14
+#define IER 0x18
+#define IHR 0x1c
+#define TXDP 0x20
+#define TXDP_HI 0x24
+#define TX_CFG 0x28
+#define GPIOR 0x2c
+#define RXDP 0x30
+#define RXDP_HI 0x34
+#define RX_CFG 0x38
+#define PQCR 0x3c
+#define WCSR 0x40
+#define PCR 0x44
+#define RFCR 0x48
+#define RFDR 0x4c
+#define BRAR 0x50
+#define BRDR 0x54
+#define SRR 0x58
+#define MIBC 0x5c
+#define MIB_START 0x60
+#define MIB_END 0x88
+#define VRCR 0xbc
+#define VTCR 0xc0
+#define VDR 0xc4
+#define CCSR 0xcc
+#define TBICR 0xe0
+#define TBISR 0xe4
+#define TANAR 0xe8
+#define TANLPAR 0xec
+#define TANER 0xf0
+#define TESR 0xf4
+#define M5REG 0xf8
+#define LAST 0xf8
+#define RESERVED 0xfc
+
+/* Chip Command Register */
+#define CR_TXE 0x00000001
+#define CR_TXD 0x00000002
+#define CR_RXE 0x00000004
+#define CR_RXD 0x00000008
+#define CR_TXR 0x00000010
+#define CR_RXR 0x00000020
+#define CR_SWI 0x00000080
+#define CR_RST 0x00000100
+
+/* configuration register */
+#define CFGR_LNKSTS 0x80000000
+#define CFGR_SPDSTS 0x60000000
+#define CFGR_SPDSTS1 0x40000000
+#define CFGR_SPDSTS0 0x20000000
+#define CFGR_DUPSTS 0x10000000
+#define CFGR_TBI_EN 0x01000000
+#define CFGR_RESERVED 0x0e000000
+#define CFGR_MODE_1000 0x00400000
+#define CFGR_AUTO_1000 0x00200000
+#define CFGR_PINT_CTL 0x001c0000
+#define CFGR_PINT_DUPSTS 0x00100000
+#define CFGR_PINT_LNKSTS 0x00080000
+#define CFGR_PINT_SPDSTS 0x00040000
+#define CFGR_TMRTEST 0x00020000
+#define CFGR_MRM_DIS 0x00010000
+#define CFGR_MWI_DIS 0x00008000
+#define CFGR_T64ADDR 0x00004000
+#define CFGR_PCI64_DET 0x00002000
+#define CFGR_DATA64_EN 0x00001000
+#define CFGR_M64ADDR 0x00000800
+#define CFGR_PHY_RST 0x00000400
+#define CFGR_PHY_DIS 0x00000200
+#define CFGR_EXTSTS_EN 0x00000100
+#define CFGR_REQALG 0x00000080
+#define CFGR_SB 0x00000040
+#define CFGR_POW 0x00000020
+#define CFGR_EXD 0x00000010
+#define CFGR_PESEL 0x00000008
+#define CFGR_BROM_DIS 0x00000004
+#define CFGR_EXT_125 0x00000002
+#define CFGR_BEM 0x00000001
+
+/* EEPROM access register */
+#define MEAR_EEDI 0x00000001
+#define MEAR_EEDO 0x00000002
+#define MEAR_EECLK 0x00000004
+#define MEAR_EESEL 0x00000008
+#define MEAR_MDIO 0x00000010
+#define MEAR_MDDIR 0x00000020
+#define MEAR_MDC 0x00000040
+
+/* PCI test control register */
+#define PTSCR_EEBIST_FAIL 0x00000001
+#define PTSCR_EEBIST_EN 0x00000002
+#define PTSCR_EELOAD_EN 0x00000004
+#define PTSCR_RBIST_FAIL 0x000001b8
+#define PTSCR_RBIST_DONE 0x00000200
+#define PTSCR_RBIST_EN 0x00000400
+#define PTSCR_RBIST_RST 0x00002000
+#define PTSCR_RBIST_RDONLY 0x000003f9
+
+/* interrupt status register */
+#define ISR_RESERVE 0x80000000
+#define ISR_TXDESC3 0x40000000
+#define ISR_TXDESC2 0x20000000
+#define ISR_TXDESC1 0x10000000
+#define ISR_TXDESC0 0x08000000
+#define ISR_RXDESC3 0x04000000
+#define ISR_RXDESC2 0x02000000
+#define ISR_RXDESC1 0x01000000
+#define ISR_RXDESC0 0x00800000
+#define ISR_TXRCMP 0x00400000
+#define ISR_RXRCMP 0x00200000
+#define ISR_DPERR 0x00100000
+#define ISR_SSERR 0x00080000
+#define ISR_RMABT 0x00040000
+#define ISR_RTABT 0x00020000
+#define ISR_RXSOVR 0x00010000
+#define ISR_HIBINT 0x00008000
+#define ISR_PHY 0x00004000
+#define ISR_PME 0x00002000
+#define ISR_SWI 0x00001000
+#define ISR_MIB 0x00000800
+#define ISR_TXURN 0x00000400
+#define ISR_TXIDLE 0x00000200
+#define ISR_TXERR 0x00000100
+#define ISR_TXDESC 0x00000080
+#define ISR_TXOK 0x00000040
+#define ISR_RXORN 0x00000020
+#define ISR_RXIDLE 0x00000010
+#define ISR_RXEARLY 0x00000008
+#define ISR_RXERR 0x00000004
+#define ISR_RXDESC 0x00000002
+#define ISR_RXOK 0x00000001
+#define ISR_ALL 0x7FFFFFFF
+#define ISR_DELAY (ISR_TXIDLE|ISR_TXDESC|ISR_TXOK| \
+ ISR_RXIDLE|ISR_RXDESC|ISR_RXOK)
+#define ISR_NODELAY (ISR_ALL & ~ISR_DELAY)
+#define ISR_IMPL (ISR_SWI|ISR_TXIDLE|ISR_TXDESC|ISR_TXOK|ISR_RXORN| \
+ ISR_RXIDLE|ISR_RXDESC|ISR_RXOK)
+#define ISR_NOIMPL (ISR_ALL & ~ISR_IMPL)
+
+/* transmit configuration register */
+#define TX_CFG_CSI 0x80000000
+#define TX_CFG_HBI 0x40000000
+#define TX_CFG_MLB 0x20000000
+#define TX_CFG_ATP 0x10000000
+#define TX_CFG_ECRETRY 0x00800000
+#define TX_CFG_BRST_DIS 0x00080000
+#define TX_CFG_MXDMA1024 0x00000000
+#define TX_CFG_MXDMA512 0x00700000
+#define TX_CFG_MXDMA256 0x00600000
+#define TX_CFG_MXDMA128 0x00500000
+#define TX_CFG_MXDMA64 0x00400000
+#define TX_CFG_MXDMA32 0x00300000
+#define TX_CFG_MXDMA16 0x00200000
+#define TX_CFG_MXDMA8 0x00100000
+#define TX_CFG_MXDMA 0x00700000
+
+#define TX_CFG_FLTH_MASK 0x0000ff00
+#define TX_CFG_DRTH_MASK 0x000000ff
+
+/*general purpose I/O control register */
+#define GPIOR_UNUSED 0xffff8000
+#define GPIOR_GP5_IN 0x00004000
+#define GPIOR_GP4_IN 0x00002000
+#define GPIOR_GP3_IN 0x00001000
+#define GPIOR_GP2_IN 0x00000800
+#define GPIOR_GP1_IN 0x00000400
+#define GPIOR_GP5_OE 0x00000200
+#define GPIOR_GP4_OE 0x00000100
+#define GPIOR_GP3_OE 0x00000080
+#define GPIOR_GP2_OE 0x00000040
+#define GPIOR_GP1_OE 0x00000020
+#define GPIOR_GP5_OUT 0x00000010
+#define GPIOR_GP4_OUT 0x00000008
+#define GPIOR_GP3_OUT 0x00000004
+#define GPIOR_GP2_OUT 0x00000002
+#define GPIOR_GP1_OUT 0x00000001
+
+/* receive configuration register */
+#define RX_CFG_AEP 0x80000000
+#define RX_CFG_ARP 0x40000000
+#define RX_CFG_STRIPCRC 0x20000000
+#define RX_CFG_RX_FD 0x10000000
+#define RX_CFG_ALP 0x08000000
+#define RX_CFG_AIRL 0x04000000
+#define RX_CFG_MXDMA512 0x00700000
+#define RX_CFG_MXDMA 0x00700000
+#define RX_CFG_DRTH 0x0000003e
+#define RX_CFG_DRTH0 0x00000002
+
+/* pause control status register */
+#define PCR_PSEN (1 << 31)
+#define PCR_PS_MCAST (1 << 30)
+#define PCR_PS_DA (1 << 29)
+#define PCR_STHI_8 (3 << 23)
+#define PCR_STLO_4 (1 << 23)
+#define PCR_FFHI_8K (3 << 21)
+#define PCR_FFLO_4K (1 << 21)
+#define PCR_PAUSE_CNT 0xFFFE
+
+/*receive filter/match control register */
+#define RFCR_RFEN 0x80000000
+#define RFCR_AAB 0x40000000
+#define RFCR_AAM 0x20000000
+#define RFCR_AAU 0x10000000
+#define RFCR_APM 0x08000000
+#define RFCR_APAT 0x07800000
+#define RFCR_APAT3 0x04000000
+#define RFCR_APAT2 0x02000000
+#define RFCR_APAT1 0x01000000
+#define RFCR_APAT0 0x00800000
+#define RFCR_AARP 0x00400000
+#define RFCR_MHEN 0x00200000
+#define RFCR_UHEN 0x00100000
+#define RFCR_ULM 0x00080000
+#define RFCR_RFADDR 0x000003ff
+
+/* receive filter/match data register */
+#define RFDR_BMASK 0x00030000
+#define RFDR_RFDATA0 0x000000ff
+#define RFDR_RFDATA1 0x0000ff00
+
+/* management information base control register */
+#define MIBC_MIBS 0x00000008
+#define MIBC_ACLR 0x00000004
+#define MIBC_FRZ 0x00000002
+#define MIBC_WRN 0x00000001
+
+/* VLAN/IP receive control register */
+#define VRCR_RUDPE 0x00000080
+#define VRCR_RTCPE 0x00000040
+#define VRCR_RIPE 0x00000020
+#define VRCR_IPEN 0x00000010
+#define VRCR_DUTF 0x00000008
+#define VRCR_DVTF 0x00000004
+#define VRCR_VTREN 0x00000002
+#define VRCR_VTDEN 0x00000001
+
+/* VLAN/IP transmit control register */
+#define VTCR_PPCHK 0x00000008
+#define VTCR_GCHK 0x00000004
+#define VTCR_VPPTI 0x00000002
+#define VTCR_VGTI 0x00000001
+
+/* Clockrun Control/Status Register */
+#define CCSR_CLKRUN_EN 0x00000001
+
+/* TBI control register */
+#define TBICR_MR_LOOPBACK 0x00004000
+#define TBICR_MR_AN_ENABLE 0x00001000
+#define TBICR_MR_RESTART_AN 0x00000200
+
+/* TBI status register */
+#define TBISR_MR_LINK_STATUS 0x00000020
+#define TBISR_MR_AN_COMPLETE 0x00000004
+
+/* TBI auto-negotiation advertisement register */
+#define TANAR_NP 0x00008000
+#define TANAR_RF2 0x00002000
+#define TANAR_RF1 0x00001000
+#define TANAR_PS2 0x00000100
+#define TANAR_PS1 0x00000080
+#define TANAR_HALF_DUP 0x00000040
+#define TANAR_FULL_DUP 0x00000020
+#define TANAR_UNUSED 0x00000E1F
+
+/* M5 control register */
+#define M5REG_RESERVED 0xfffffffc
+#define M5REG_RSS 0x00000004
+#define M5REG_RX_THREAD 0x00000002
+#define M5REG_TX_THREAD 0x00000001
+
+struct ns_desc32 {
+ uint32_t link; /* link field to next descriptor in linked list */
+ uint32_t bufptr; /* pointer to the first fragment or buffer */
+ uint32_t cmdsts; /* command/status field */
+ uint32_t extsts; /* extended status field for VLAN and IP info */
+};
+
+struct ns_desc64 {
+ uint64_t link; /* link field to next descriptor in linked list */
+ uint64_t bufptr; /* pointer to the first fragment or buffer */
+ uint32_t cmdsts; /* command/status field */
+ uint32_t extsts; /* extended status field for VLAN and IP info */
+};
+
+/* cmdsts flags for descriptors */
+#define CMDSTS_OWN 0x80000000
+#define CMDSTS_MORE 0x40000000
+#define CMDSTS_INTR 0x20000000
+#define CMDSTS_ERR 0x10000000
+#define CMDSTS_OK 0x08000000
+#define CMDSTS_LEN_MASK 0x0000ffff
+
+#define CMDSTS_DEST_MASK 0x01800000
+#define CMDSTS_DEST_SELF 0x00800000
+#define CMDSTS_DEST_MULTI 0x01000000
+
+/* extended flags for descriptors */
+#define EXTSTS_UDPERR 0x00400000
+#define EXTSTS_UDPPKT 0x00200000
+#define EXTSTS_TCPERR 0x00100000
+#define EXTSTS_TCPPKT 0x00080000
+#define EXTSTS_IPERR 0x00040000
+#define EXTSTS_IPPKT 0x00020000
+
+
+/* speed status */
+#define SPDSTS_POLARITY (CFGR_SPDSTS1 | CFGR_SPDSTS0 | CFGR_DUPSTS | (lnksts ? CFGR_LNKSTS : 0))
+
+#endif /* __DEV_NS_GIGE_REG_H__ */
diff --git a/src/dev/pciconfigall.cc b/src/dev/pciconfigall.cc
new file mode 100644
index 000000000..f278a67cf
--- /dev/null
+++ b/src/dev/pciconfigall.cc
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* @file
+ * PCI Configspace implementation
+ */
+
+#include <deque>
+#include <string>
+#include <vector>
+#include <bitset>
+
+#include "base/trace.hh"
+#include "dev/pciconfigall.hh"
+#include "dev/pcidev.hh"
+#include "dev/pcireg.h"
+#include "dev/platform.hh"
+#include "mem/packet.hh"
+#include "sim/builder.hh"
+#include "sim/system.hh"
+
+using namespace std;
+
+PciConfigAll::PciConfigAll(Params *p)
+ : BasicPioDevice(p)
+{
+ pioSize = 0xffffff;
+
+ // Set backpointer for pci config. Really the config stuff should be able to
+ // automagically do this
+ p->platform->pciconfig = this;
+
+ // Make all the pointers to devices null
+ for(int x=0; x < MAX_PCI_DEV; x++)
+ for(int y=0; y < MAX_PCI_FUNC; y++)
+ devices[x][y] = NULL;
+}
+
+// If two interrupts share the same line largely bad things will happen.
+// Since we don't track how many times an interrupt was set and correspondingly
+// cleared two devices on the same interrupt line and assert and deassert each
+// others interrupt "line". Interrupts will not work correctly.
+void
+PciConfigAll::startup()
+{
+ bitset<256> intLines;
+ PciDev *tempDev;
+ uint8_t intline;
+
+ for (int x = 0; x < MAX_PCI_DEV; x++) {
+ for (int y = 0; y < MAX_PCI_FUNC; y++) {
+ if (devices[x][y] != NULL) {
+ tempDev = devices[x][y];
+ intline = tempDev->interruptLine();
+ if (intLines.test(intline))
+ warn("Interrupt line %#X is used multiple times"
+ "(You probably want to fix this).\n", (uint32_t)intline);
+ else
+ intLines.set(intline);
+ } // devices != NULL
+ } // PCI_FUNC
+ } // PCI_DEV
+
+}
+
+Tick
+PciConfigAll::read(Packet *pkt)
+{
+ assert(pkt->result == Unknown);
+ assert(pkt->addr >= pioAddr && pkt->addr < pioAddr + pioSize);
+
+ Addr daddr = pkt->addr - pioAddr;
+ int device = (daddr >> 11) & 0x1F;
+ int func = (daddr >> 8) & 0x7;
+ int reg = daddr & 0xFF;
+
+ pkt->time += pioDelay;
+ pkt->allocate();
+
+ DPRINTF(PciConfigAll, "read va=%#x da=%#x size=%d\n", pkt->addr, daddr,
+ pkt->size);
+
+ switch (pkt->size) {
+ case sizeof(uint32_t):
+ if (devices[device][func] == NULL)
+ pkt->set<uint32_t>(0xFFFFFFFF);
+ else
+ devices[device][func]->readConfig(reg, pkt->getPtr<uint32_t>());
+ break;
+ case sizeof(uint16_t):
+ if (devices[device][func] == NULL)
+ pkt->set<uint16_t>(0xFFFF);
+ else
+ devices[device][func]->readConfig(reg, pkt->getPtr<uint16_t>());
+ break;
+ case sizeof(uint8_t):
+ if (devices[device][func] == NULL)
+ pkt->set<uint8_t>(0xFF);
+ else
+ devices[device][func]->readConfig(reg, pkt->getPtr<uint8_t>());
+ break;
+ default:
+ panic("invalid access size(?) for PCI configspace!\n");
+ }
+ pkt->result = Success;
+ return pioDelay;
+}
+
+Tick
+PciConfigAll::write(Packet *pkt)
+{
+ pkt->time += pioDelay;
+
+ assert(pkt->result == Unknown);
+ assert(pkt->addr >= pioAddr && pkt->addr < pioAddr + pioSize);
+ assert(pkt->size == sizeof(uint8_t) || pkt->size == sizeof(uint16_t) ||
+ pkt->size == sizeof(uint32_t));
+ Addr daddr = pkt->addr - pioAddr;
+
+ int device = (daddr >> 11) & 0x1F;
+ int func = (daddr >> 8) & 0x7;
+ int reg = daddr & 0xFF;
+
+ if (devices[device][func] == NULL)
+ panic("Attempting to write to config space on non-existant device\n");
+
+ DPRINTF(PciConfigAll, "write - va=%#x size=%d data=%#x\n",
+ pkt->addr, pkt->size, pkt->get<uint32_t>());
+
+ switch (pkt->size) {
+ case sizeof(uint8_t):
+ devices[device][func]->writeConfig(reg, pkt->get<uint8_t>());
+ break;
+ case sizeof(uint16_t):
+ devices[device][func]->writeConfig(reg, pkt->get<uint16_t>());
+ break;
+ case sizeof(uint32_t):
+ devices[device][func]->writeConfig(reg, pkt->get<uint32_t>());
+ break;
+ default:
+ panic("invalid pci config write size\n");
+ }
+ pkt->result = Success;
+ return pioDelay;
+}
+
+void
+PciConfigAll::serialize(std::ostream &os)
+{
+ /*
+ * There is no state associated with this object that requires
+ * serialization. The only real state are the device pointers
+ * which are all setup by the constructor of the PciDev class
+ */
+}
+
+void
+PciConfigAll::unserialize(Checkpoint *cp, const std::string &section)
+{
+ /*
+ * There is no state associated with this object that requires
+ * serialization. The only real state are the device pointers
+ * which are all setup by the constructor of the PciDev class
+ */
+}
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(PciConfigAll)
+
+ Param<Addr> pio_addr;
+ Param<Tick> pio_latency;
+ SimObjectParam<Platform *> platform;
+ SimObjectParam<System *> system;
+
+END_DECLARE_SIM_OBJECT_PARAMS(PciConfigAll)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(PciConfigAll)
+
+ INIT_PARAM(pio_addr, "Device Address"),
+ INIT_PARAM(pio_latency, "Programmed IO latency"),
+ INIT_PARAM(platform, "platform"),
+ INIT_PARAM(system, "system object")
+
+END_INIT_SIM_OBJECT_PARAMS(PciConfigAll)
+
+CREATE_SIM_OBJECT(PciConfigAll)
+{
+ BasicPioDevice::Params *p = new BasicPioDevice::Params;
+ p->pio_addr = pio_addr;
+ p->pio_delay = pio_latency;
+ p->platform = platform;
+ p->system = system;
+ return new PciConfigAll(p);
+}
+
+REGISTER_SIM_OBJECT("PciConfigAll", PciConfigAll)
+
+#endif // DOXYGEN_SHOULD_SKIP_THIS
diff --git a/src/dev/pciconfigall.hh b/src/dev/pciconfigall.hh
new file mode 100644
index 000000000..df4eae448
--- /dev/null
+++ b/src/dev/pciconfigall.hh
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * @file
+ * PCI Config space implementation.
+ */
+
+#ifndef __PCICONFIGALL_HH__
+#define __PCICONFIGALL_HH__
+
+#include "dev/pcireg.h"
+#include "base/range.hh"
+#include "dev/io_device.hh"
+
+
+static const uint32_t MAX_PCI_DEV = 32;
+static const uint32_t MAX_PCI_FUNC = 8;
+
+class PciDev;
+
+/**
+ * PCI Config Space
+ * All of PCI config space needs to return -1 on Tsunami, except
+ * the devices that exist. This device maps the entire bus config
+ * space and passes the requests on to TsunamiPCIDev devices as
+ * appropriate.
+ */
+class PciConfigAll : public BasicPioDevice
+{
+ private:
+ /**
+ * Pointers to all the devices that are registered with this
+ * particular config space.
+ */
+ PciDev* devices[MAX_PCI_DEV][MAX_PCI_FUNC];
+
+ public:
+ /**
+ * Constructor for PCIConfigAll
+ * @param p parameters structure
+ */
+ PciConfigAll(Params *p);
+
+ /**
+ * Check if a device exists.
+ * @param pcidev PCI device to check
+ * @param pcifunc PCI function to check
+ * @return true if device exists, false otherwise
+ */
+ bool deviceExists(uint32_t pcidev, uint32_t pcifunc)
+ { return devices[pcidev][pcifunc] != NULL ? true : false; }
+
+ /**
+ * Registers a device with the config space object.
+ * @param pcidev PCI device to register
+ * @param pcifunc PCI function to register
+ * @param device device to register
+ */
+ void registerDevice(uint8_t pcidev, uint8_t pcifunc, PciDev *device)
+ { devices[pcidev][pcifunc] = device; }
+
+ /**
+ * Read something in PCI config space. If the device does not exist
+ * -1 is returned, if the device does exist its PciDev::ReadConfig (or the
+ * virtual function that overrides) it is called.
+ * @param pkt Contains the address of the field to read.
+ * @return Amount of time to do the read
+ */
+ virtual Tick read(Packet *pkt);
+
+ /**
+ * Write to PCI config spcae. If the device does not exit the simulator
+ * panics. If it does it is passed on the PciDev::WriteConfig (or the virtual
+ * function that overrides it).
+ * @param req Contains the address to write to.
+ * @param data The data to write.
+ * @return The fault condition of the access.
+ */
+
+ virtual Tick write(Packet *pkt);
+
+ /**
+ * Start up function to check if more than one person is using an interrupt line
+ * and print a warning if such a case exists
+ */
+ virtual void startup();
+
+ /**
+ * Serialize this object to the given output stream.
+ * @param os The stream to serialize to.
+ */
+ virtual void serialize(std::ostream &os);
+
+ /**
+ * Reconstruct the state of this object from a checkpoint.
+ * @param cp The checkpoint use.
+ * @param section The section name of this object
+ */
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+};
+
+#endif // __PCICONFIGALL_HH__
diff --git a/src/dev/pcidev.cc b/src/dev/pcidev.cc
new file mode 100644
index 000000000..76392ccfe
--- /dev/null
+++ b/src/dev/pcidev.cc
@@ -0,0 +1,386 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* @file
+ * A single PCI device configuration space entry.
+ */
+
+#include <list>
+#include <string>
+#include <vector>
+
+#include "base/inifile.hh"
+#include "base/misc.hh"
+#include "base/str.hh" // for to_number
+#include "base/trace.hh"
+#include "dev/pciconfigall.hh"
+#include "dev/pcidev.hh"
+#include "dev/tsunamireg.h"
+#include "mem/packet.hh"
+#include "sim/builder.hh"
+#include "sim/byteswap.hh"
+#include "sim/param.hh"
+#include "sim/root.hh"
+
+using namespace std;
+
+PciDev::PciDev(Params *p)
+ : DmaDevice(p), plat(p->platform), configData(p->configData),
+ pioDelay(p->pio_delay)
+{
+ // copy the config data from the PciConfigData object
+ if (configData) {
+ memcpy(config.data, configData->config.data, sizeof(config.data));
+ memcpy(BARSize, configData->BARSize, sizeof(BARSize));
+ memcpy(BARAddrs, configData->BARAddrs, sizeof(BARAddrs));
+ } else
+ panic("NULL pointer to configuration data");
+
+ // Setup pointer in config space to point to this entry
+ if (p->configSpace->deviceExists(p->deviceNum, p->functionNum))
+ panic("Two PCI devices occuping same dev: %#x func: %#x",
+ p->deviceNum, p->functionNum);
+ else
+ p->configSpace->registerDevice(p->deviceNum, p->functionNum, this);
+}
+
+void
+PciDev::readConfig(int offset, uint8_t *data)
+{
+ if (offset >= PCI_DEVICE_SPECIFIC)
+ panic("Device specific PCI config space not implemented!\n");
+
+ *data = config.data[offset];
+
+ DPRINTF(PCIDEV,
+ "read device: %#x function: %#x register: %#x 1 bytes: data: %#x\n",
+ params()->deviceNum, params()->functionNum, offset, *data);
+}
+
+void
+PciDev::addressRanges(AddrRangeList &range_list)
+{
+ int x = 0;
+ range_list.clear();
+ for (x = 0; x < 6; x++)
+ if (BARAddrs[x] != 0)
+ range_list.push_back(RangeSize(BARAddrs[x],BARSize[x]));
+}
+
+void
+PciDev::readConfig(int offset, uint16_t *data)
+{
+ if (offset >= PCI_DEVICE_SPECIFIC)
+ panic("Device specific PCI config space not implemented!\n");
+
+ *data = *(uint16_t*)&config.data[offset];
+
+ DPRINTF(PCIDEV,
+ "read device: %#x function: %#x register: %#x 2 bytes: data: %#x\n",
+ params()->deviceNum, params()->functionNum, offset, *data);
+}
+
+void
+PciDev::readConfig(int offset, uint32_t *data)
+{
+ if (offset >= PCI_DEVICE_SPECIFIC)
+ panic("Device specific PCI config space not implemented!\n");
+
+ *data = *(uint32_t*)&config.data[offset];
+
+ DPRINTF(PCIDEV,
+ "read device: %#x function: %#x register: %#x 4 bytes: data: %#x\n",
+ params()->deviceNum, params()->functionNum, offset, *data);
+}
+
+
+void
+PciDev::writeConfig(int offset, const uint8_t data)
+{
+ if (offset >= PCI_DEVICE_SPECIFIC)
+ panic("Device specific PCI config space not implemented!\n");
+
+ DPRINTF(PCIDEV,
+ "write device: %#x function: %#x reg: %#x size: 1 data: %#x\n",
+ params()->deviceNum, params()->functionNum, offset, data);
+
+ switch (offset) {
+ case PCI0_INTERRUPT_LINE:
+ config.interruptLine = data;
+ case PCI_CACHE_LINE_SIZE:
+ config.cacheLineSize = data;
+ case PCI_LATENCY_TIMER:
+ config.latencyTimer = data;
+ break;
+ /* Do nothing for these read-only registers */
+ case PCI0_INTERRUPT_PIN:
+ case PCI0_MINIMUM_GRANT:
+ case PCI0_MAXIMUM_LATENCY:
+ case PCI_CLASS_CODE:
+ case PCI_REVISION_ID:
+ break;
+ default:
+ panic("writing to a read only register");
+ }
+}
+
+void
+PciDev::writeConfig(int offset, const uint16_t data)
+{
+ if (offset >= PCI_DEVICE_SPECIFIC)
+ panic("Device specific PCI config space not implemented!\n");
+
+ DPRINTF(PCIDEV,
+ "write device: %#x function: %#x reg: %#x size: 2 data: %#x\n",
+ params()->deviceNum, params()->functionNum, offset, data);
+
+ switch (offset) {
+ case PCI_COMMAND:
+ config.command = data;
+ case PCI_STATUS:
+ config.status = data;
+ case PCI_CACHE_LINE_SIZE:
+ config.cacheLineSize = data;
+ break;
+ default:
+ panic("writing to a read only register");
+ }
+}
+
+
+void
+PciDev::writeConfig(int offset, const uint32_t data)
+{
+ if (offset >= PCI_DEVICE_SPECIFIC)
+ panic("Device specific PCI config space not implemented!\n");
+
+ DPRINTF(PCIDEV,
+ "write device: %#x function: %#x reg: %#x size: 4 data: %#x\n",
+ params()->deviceNum, params()->functionNum, offset, data);
+
+ switch (offset) {
+ case PCI0_BASE_ADDR0:
+ case PCI0_BASE_ADDR1:
+ case PCI0_BASE_ADDR2:
+ case PCI0_BASE_ADDR3:
+ case PCI0_BASE_ADDR4:
+ case PCI0_BASE_ADDR5:
+
+ uint32_t barnum, bar_mask;
+ Addr base_addr, base_size, space_base;
+
+ barnum = BAR_NUMBER(offset);
+
+ if (BAR_IO_SPACE(letoh(config.baseAddr[barnum]))) {
+ bar_mask = BAR_IO_MASK;
+ space_base = TSUNAMI_PCI0_IO;
+ } else {
+ bar_mask = BAR_MEM_MASK;
+ space_base = TSUNAMI_PCI0_MEMORY;
+ }
+
+ // Writing 0xffffffff to a BAR tells the card to set the
+ // value of the bar to size of memory it needs
+ if (letoh(data) == 0xffffffff) {
+ // This is I/O Space, bottom two bits are read only
+
+ config.baseAddr[barnum] = letoh(
+ (~(BARSize[barnum] - 1) & ~bar_mask) |
+ (letoh(config.baseAddr[barnum]) & bar_mask));
+ } else {
+ config.baseAddr[barnum] = letoh(
+ (letoh(data) & ~bar_mask) |
+ (letoh(config.baseAddr[barnum]) & bar_mask));
+
+ if (letoh(config.baseAddr[barnum]) & ~bar_mask) {
+ base_addr = (letoh(data) & ~bar_mask) + space_base;
+ base_size = BARSize[barnum];
+ BARAddrs[barnum] = base_addr;
+
+ pioPort->sendStatusChange(Port::RangeChange);
+ }
+ }
+ break;
+
+ case PCI0_ROM_BASE_ADDR:
+ if (letoh(data) == 0xfffffffe)
+ config.expansionROM = htole((uint32_t)0xffffffff);
+ else
+ config.expansionROM = data;
+ break;
+
+ case PCI_COMMAND:
+ // This could also clear some of the error bits in the Status
+ // register. However they should never get set, so lets ignore
+ // it for now
+ config.command = data;
+ break;
+
+ default:
+ DPRINTF(PCIDEV, "Writing to a read only register");
+ }
+}
+
+void
+PciDev::serialize(ostream &os)
+{
+ SERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0]));
+ SERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0]));
+ SERIALIZE_ARRAY(config.data, sizeof(config.data) / sizeof(config.data[0]));
+}
+
+void
+PciDev::unserialize(Checkpoint *cp, const std::string &section)
+{
+ UNSERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0]));
+ UNSERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0]));
+ UNSERIALIZE_ARRAY(config.data,
+ sizeof(config.data) / sizeof(config.data[0]));
+}
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(PciConfigData)
+
+ Param<uint16_t> VendorID;
+ Param<uint16_t> DeviceID;
+ Param<uint16_t> Command;
+ Param<uint16_t> Status;
+ Param<uint8_t> Revision;
+ Param<uint8_t> ProgIF;
+ Param<uint8_t> SubClassCode;
+ Param<uint8_t> ClassCode;
+ Param<uint8_t> CacheLineSize;
+ Param<uint8_t> LatencyTimer;
+ Param<uint8_t> HeaderType;
+ Param<uint8_t> BIST;
+ Param<uint32_t> BAR0;
+ Param<uint32_t> BAR1;
+ Param<uint32_t> BAR2;
+ Param<uint32_t> BAR3;
+ Param<uint32_t> BAR4;
+ Param<uint32_t> BAR5;
+ Param<uint32_t> CardbusCIS;
+ Param<uint16_t> SubsystemVendorID;
+ Param<uint16_t> SubsystemID;
+ Param<uint32_t> ExpansionROM;
+ Param<uint8_t> InterruptLine;
+ Param<uint8_t> InterruptPin;
+ Param<uint8_t> MinimumGrant;
+ Param<uint8_t> MaximumLatency;
+ Param<uint32_t> BAR0Size;
+ Param<uint32_t> BAR1Size;
+ Param<uint32_t> BAR2Size;
+ Param<uint32_t> BAR3Size;
+ Param<uint32_t> BAR4Size;
+ Param<uint32_t> BAR5Size;
+
+END_DECLARE_SIM_OBJECT_PARAMS(PciConfigData)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(PciConfigData)
+
+ INIT_PARAM(VendorID, "Vendor ID"),
+ INIT_PARAM(DeviceID, "Device ID"),
+ INIT_PARAM_DFLT(Command, "Command Register", 0x00),
+ INIT_PARAM_DFLT(Status, "Status Register", 0x00),
+ INIT_PARAM_DFLT(Revision, "Device Revision", 0x00),
+ INIT_PARAM_DFLT(ProgIF, "Programming Interface", 0x00),
+ INIT_PARAM(SubClassCode, "Sub-Class Code"),
+ INIT_PARAM(ClassCode, "Class Code"),
+ INIT_PARAM_DFLT(CacheLineSize, "System Cacheline Size", 0x00),
+ INIT_PARAM_DFLT(LatencyTimer, "PCI Latency Timer", 0x00),
+ INIT_PARAM_DFLT(HeaderType, "PCI Header Type", 0x00),
+ INIT_PARAM_DFLT(BIST, "Built In Self Test", 0x00),
+ INIT_PARAM_DFLT(BAR0, "Base Address Register 0", 0x00),
+ INIT_PARAM_DFLT(BAR1, "Base Address Register 1", 0x00),
+ INIT_PARAM_DFLT(BAR2, "Base Address Register 2", 0x00),
+ INIT_PARAM_DFLT(BAR3, "Base Address Register 3", 0x00),
+ INIT_PARAM_DFLT(BAR4, "Base Address Register 4", 0x00),
+ INIT_PARAM_DFLT(BAR5, "Base Address Register 5", 0x00),
+ INIT_PARAM_DFLT(CardbusCIS, "Cardbus Card Information Structure", 0x00),
+ INIT_PARAM_DFLT(SubsystemVendorID, "Subsystem Vendor ID", 0x00),
+ INIT_PARAM_DFLT(SubsystemID, "Subsystem ID", 0x00),
+ INIT_PARAM_DFLT(ExpansionROM, "Expansion ROM Base Address Register", 0x00),
+ INIT_PARAM(InterruptLine, "Interrupt Line Register"),
+ INIT_PARAM(InterruptPin, "Interrupt Pin Register"),
+ INIT_PARAM_DFLT(MinimumGrant, "Minimum Grant", 0x00),
+ INIT_PARAM_DFLT(MaximumLatency, "Maximum Latency", 0x00),
+ INIT_PARAM_DFLT(BAR0Size, "Base Address Register 0 Size", 0x00),
+ INIT_PARAM_DFLT(BAR1Size, "Base Address Register 1 Size", 0x00),
+ INIT_PARAM_DFLT(BAR2Size, "Base Address Register 2 Size", 0x00),
+ INIT_PARAM_DFLT(BAR3Size, "Base Address Register 3 Size", 0x00),
+ INIT_PARAM_DFLT(BAR4Size, "Base Address Register 4 Size", 0x00),
+ INIT_PARAM_DFLT(BAR5Size, "Base Address Register 5 Size", 0x00)
+
+END_INIT_SIM_OBJECT_PARAMS(PciConfigData)
+
+CREATE_SIM_OBJECT(PciConfigData)
+{
+ PciConfigData *data = new PciConfigData(getInstanceName());
+
+ data->config.vendor = htole(VendorID);
+ data->config.device = htole(DeviceID);
+ data->config.command = htole(Command);
+ data->config.status = htole(Status);
+ data->config.revision = htole(Revision);
+ data->config.progIF = htole(ProgIF);
+ data->config.subClassCode = htole(SubClassCode);
+ data->config.classCode = htole(ClassCode);
+ data->config.cacheLineSize = htole(CacheLineSize);
+ data->config.latencyTimer = htole(LatencyTimer);
+ data->config.headerType = htole(HeaderType);
+ data->config.bist = htole(BIST);
+
+ data->config.baseAddr0 = htole(BAR0);
+ data->config.baseAddr1 = htole(BAR1);
+ data->config.baseAddr2 = htole(BAR2);
+ data->config.baseAddr3 = htole(BAR3);
+ data->config.baseAddr4 = htole(BAR4);
+ data->config.baseAddr5 = htole(BAR5);
+ data->config.cardbusCIS = htole(CardbusCIS);
+ data->config.subsystemVendorID = htole(SubsystemVendorID);
+ data->config.subsystemID = htole(SubsystemVendorID);
+ data->config.expansionROM = htole(ExpansionROM);
+ data->config.interruptLine = htole(InterruptLine);
+ data->config.interruptPin = htole(InterruptPin);
+ data->config.minimumGrant = htole(MinimumGrant);
+ data->config.maximumLatency = htole(MaximumLatency);
+
+ data->BARSize[0] = BAR0Size;
+ data->BARSize[1] = BAR1Size;
+ data->BARSize[2] = BAR2Size;
+ data->BARSize[3] = BAR3Size;
+ data->BARSize[4] = BAR4Size;
+ data->BARSize[5] = BAR5Size;
+
+ return data;
+}
+
+REGISTER_SIM_OBJECT("PciConfigData", PciConfigData)
+
+#endif // DOXYGEN_SHOULD_SKIP_THIS
diff --git a/src/dev/pcidev.hh b/src/dev/pcidev.hh
new file mode 100644
index 000000000..fc4773908
--- /dev/null
+++ b/src/dev/pcidev.hh
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* @file
+ * Interface for devices using PCI configuration
+ */
+
+#ifndef __DEV_PCIDEV_HH__
+#define __DEV_PCIDEV_HH__
+
+#include "dev/io_device.hh"
+#include "dev/pcireg.h"
+#include "dev/platform.hh"
+
+#define BAR_IO_MASK 0x3
+#define BAR_MEM_MASK 0xF
+#define BAR_IO_SPACE_BIT 0x1
+#define BAR_IO_SPACE(x) ((x) & BAR_IO_SPACE_BIT)
+#define BAR_NUMBER(x) (((x) - PCI0_BASE_ADDR0) >> 0x2);
+
+class PciConfigAll;
+
+
+/**
+ * This class encapulates the first 64 bytes of a singles PCI
+ * devices config space that in configured by the configuration file.
+ */
+class PciConfigData : public SimObject
+{
+ public:
+ /**
+ * Constructor to initialize the devices config space to 0.
+ */
+ PciConfigData(const std::string &name)
+ : SimObject(name)
+ {
+ memset(config.data, 0, sizeof(config.data));
+ memset(BARAddrs, 0, sizeof(BARAddrs));
+ memset(BARSize, 0, sizeof(BARSize));
+ }
+
+ /** The first 64 bytes */
+ PCIConfig config;
+
+ /** The size of the BARs */
+ uint32_t BARSize[6];
+
+ /** The addresses of the BARs */
+ Addr BARAddrs[6];
+};
+
+/**
+ * PCI device, base implemnation is only config space.
+ * Each device is connected to a PCIConfigSpace device
+ * which returns -1 for everything but the pcidevs that
+ * register with it. This object registers with the PCIConfig space
+ * object.
+ */
+class PciDev : public DmaDevice
+{
+ public:
+ struct Params : public ::PioDevice::Params
+ {
+ /**
+ * A pointer to the configspace all object that calls us when
+ * a read comes to this particular device/function.
+ */
+ PciConfigAll *configSpace;
+
+ /**
+ * A pointer to the object that contains the first 64 bytes of
+ * config space
+ */
+ PciConfigData *configData;
+
+ /** The bus number we are on */
+ uint32_t busNum;
+
+ /** The device number we have */
+ uint32_t deviceNum;
+
+ /** The function number */
+ uint32_t functionNum;
+
+ /** The latency for pio accesses. */
+ Tick pio_delay;
+ };
+
+ public:
+ const Params *params() const { return (const Params *)_params; }
+
+ protected:
+ /** The current config space. Unlike the PciConfigData this is
+ * updated during simulation while continues to reflect what was
+ * in the config file.
+ */
+ PCIConfig config;
+
+ /** The size of the BARs */
+ uint32_t BARSize[6];
+
+ /** The current address mapping of the BARs */
+ Addr BARAddrs[6];
+
+ bool
+ isBAR(Addr addr, int bar) const
+ {
+ assert(bar >= 0 && bar < 6);
+ return BARAddrs[bar] <= addr && addr < BARAddrs[bar] + BARSize[bar];
+ }
+
+ int
+ getBAR(Addr addr)
+ {
+ for (int i = 0; i <= 5; ++i)
+ if (isBAR(addr, i))
+ return i;
+
+ return -1;
+ }
+
+ bool
+ getBAR(Addr paddr, Addr &daddr, int &bar)
+ {
+ int b = getBAR(paddr);
+ if (b < 0)
+ return false;
+
+ daddr = paddr - BARAddrs[b];
+ bar = b;
+ return true;
+ }
+
+ protected:
+ Platform *plat;
+ PciConfigData *configData;
+ Tick pioDelay;
+
+ public:
+ Addr pciToDma(Addr pciAddr) const
+ { return plat->pciToDma(pciAddr); }
+
+ void
+ intrPost()
+ { plat->postPciInt(configData->config.interruptLine); }
+
+ void
+ intrClear()
+ { plat->clearPciInt(configData->config.interruptLine); }
+
+ uint8_t
+ interruptLine()
+ { return configData->config.interruptLine; }
+
+ /** return the address ranges that this device responds to.
+ * @params range_list range list to populate with ranges
+ */
+ void addressRanges(AddrRangeList &range_list);
+
+ /**
+ * Constructor for PCI Dev. This function copies data from the
+ * config file object PCIConfigData and registers the device with
+ * a PciConfigAll object.
+ */
+ PciDev(Params *params);
+
+ /**
+ * Write to the PCI config space data that is stored locally. This may be
+ * overridden by the device but at some point it will eventually call this
+ * for normal operations that it does not need to override.
+ * @param offset the offset into config space
+ * @param size the size of the write
+ * @param data the data to write
+ */
+ virtual void writeConfig(int offset, const uint8_t data);
+ virtual void writeConfig(int offset, const uint16_t data);
+ virtual void writeConfig(int offset, const uint32_t data);
+
+
+ /**
+ * Read from the PCI config space data that is stored locally. This may be
+ * overridden by the device but at some point it will eventually call this
+ * for normal operations that it does not need to override.
+ * @param offset the offset into config space
+ * @param size the size of the read
+ * @param data pointer to the location where the read value should be stored
+ */
+ virtual void readConfig(int offset, uint8_t *data);
+ virtual void readConfig(int offset, uint16_t *data);
+ virtual void readConfig(int offset, uint32_t *data);
+
+ /**
+ * Serialize this object to the given output stream.
+ * @param os The stream to serialize to.
+ */
+ virtual void serialize(std::ostream &os);
+
+ /**
+ * Reconstruct the state of this object from a checkpoint.
+ * @param cp The checkpoint use.
+ * @param section The section name of this object
+ */
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+};
+#endif // __DEV_PCIDEV_HH__
diff --git a/src/dev/pcireg.h b/src/dev/pcireg.h
new file mode 100644
index 000000000..9d2737c20
--- /dev/null
+++ b/src/dev/pcireg.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* @file
+ * Device register definitions for a device's PCI config space
+ */
+
+#ifndef __PCIREG_H__
+#define __PCIREG_H__
+
+#include <sys/types.h>
+
+union PCIConfig {
+ uint8_t data[64];
+
+ struct {
+ uint16_t vendor;
+ uint16_t device;
+ uint16_t command;
+ uint16_t status;
+ uint8_t revision;
+ uint8_t progIF;
+ uint8_t subClassCode;
+ uint8_t classCode;
+ uint8_t cacheLineSize;
+ uint8_t latencyTimer;
+ uint8_t headerType;
+ uint8_t bist;
+ union {
+ uint32_t baseAddr[6];
+
+ struct {
+ uint32_t baseAddr0;
+ uint32_t baseAddr1;
+ uint32_t baseAddr2;
+ uint32_t baseAddr3;
+ uint32_t baseAddr4;
+ uint32_t baseAddr5;
+ };
+ };
+ uint32_t cardbusCIS;
+ uint16_t subsystemVendorID;
+ uint16_t subsystemID;
+ uint32_t expansionROM;
+ uint32_t reserved0;
+ uint32_t reserved1;
+ uint8_t interruptLine;
+ uint8_t interruptPin;
+ uint8_t minimumGrant;
+ uint8_t maximumLatency;
+ };
+};
+
+// Common PCI offsets
+#define PCI_VENDOR_ID 0x00 // Vendor ID ro
+#define PCI_DEVICE_ID 0x02 // Device ID ro
+#define PCI_COMMAND 0x04 // Command rw
+#define PCI_STATUS 0x06 // Status rw
+#define PCI_REVISION_ID 0x08 // Revision ID ro
+#define PCI_CLASS_CODE 0x09 // Class Code ro
+#define PCI_SUB_CLASS_CODE 0x0A // Sub Class Code ro
+#define PCI_BASE_CLASS_CODE 0x0B // Base Class Code ro
+#define PCI_CACHE_LINE_SIZE 0x0C // Cache Line Size ro+
+#define PCI_LATENCY_TIMER 0x0D // Latency Timer ro+
+#define PCI_HEADER_TYPE 0x0E // Header Type ro
+#define PCI_BIST 0x0F // Built in self test rw
+
+// some pci command reg bitfields
+#define PCI_CMD_BME 0x04 // Bus master function enable
+#define PCI_CMD_MSE 0x02 // Memory Space Access enable
+#define PCI_CMD_IOSE 0x01 // I/O space enable
+
+// Type 0 PCI offsets
+#define PCI0_BASE_ADDR0 0x10 // Base Address 0 rw
+#define PCI0_BASE_ADDR1 0x14 // Base Address 1 rw
+#define PCI0_BASE_ADDR2 0x18 // Base Address 2 rw
+#define PCI0_BASE_ADDR3 0x1C // Base Address 3 rw
+#define PCI0_BASE_ADDR4 0x20 // Base Address 4 rw
+#define PCI0_BASE_ADDR5 0x24 // Base Address 5 rw
+#define PCI0_CIS 0x28 // CardBus CIS Pointer ro
+#define PCI0_SUB_VENDOR_ID 0x2C // Sub-Vendor ID ro
+#define PCI0_SUB_SYSTEM_ID 0x2E // Sub-System ID ro
+#define PCI0_ROM_BASE_ADDR 0x30 // Expansion ROM Base Address rw
+#define PCI0_RESERVED0 0x34
+#define PCI0_RESERVED1 0x38
+#define PCI0_INTERRUPT_LINE 0x3C // Interrupt Line rw
+#define PCI0_INTERRUPT_PIN 0x3D // Interrupt Pin ro
+#define PCI0_MINIMUM_GRANT 0x3E // Maximum Grant ro
+#define PCI0_MAXIMUM_LATENCY 0x3F // Maximum Latency ro
+
+// Type 1 PCI offsets
+#define PCI1_BASE_ADDR0 0x10 // Base Address 0 rw
+#define PCI1_BASE_ADDR1 0x14 // Base Address 1 rw
+#define PCI1_PRI_BUS_NUM 0x18 // Primary Bus Number rw
+#define PCI1_SEC_BUS_NUM 0x19 // Secondary Bus Number rw
+#define PCI1_SUB_BUS_NUM 0x1A // Subordinate Bus Number rw
+#define PCI1_SEC_LAT_TIMER 0x1B // Secondary Latency Timer ro+
+#define PCI1_IO_BASE 0x1C // I/O Base rw
+#define PCI1_IO_LIMIT 0x1D // I/O Limit rw
+#define PCI1_SECONDARY_STATUS 0x1E // Secondary Status rw
+#define PCI1_MEM_BASE 0x20 // Memory Base rw
+#define PCI1_MEM_LIMIT 0x22 // Memory Limit rw
+#define PCI1_PRF_MEM_BASE 0x24 // Prefetchable Memory Base rw
+#define PCI1_PRF_MEM_LIMIT 0x26 // Prefetchable Memory Limit rw
+#define PCI1_PRF_BASE_UPPER 0x28 // Prefetchable Base Upper 32 rw
+#define PCI1_PRF_LIMIT_UPPER 0x2C // Prefetchable Limit Upper 32 rw
+#define PCI1_IO_BASE_UPPER 0x30 // I/O Base Upper 16 bits rw
+#define PCI1_IO_LIMIT_UPPER 0x32 // I/O Limit Upper 16 bits rw
+#define PCI1_RESERVED 0x34 // Reserved ro
+#define PCI1_ROM_BASE_ADDR 0x38 // Expansion ROM Base Address rw
+#define PCI1_INTR_LINE 0x3C // Interrupt Line rw
+#define PCI1_INTR_PIN 0x3D // Interrupt Pin ro
+#define PCI1_BRIDGE_CTRL 0x3E // Bridge Control rw
+
+// Device specific offsets
+#define PCI_DEVICE_SPECIFIC 0x40 // 192 bytes
+
+// Some Vendor IDs
+#define PCI_VENDOR_DEC 0x1011
+#define PCI_VENDOR_NCR 0x101A
+#define PCI_VENDOR_QLOGIC 0x1077
+#define PCI_VENDOR_SIMOS 0x1291
+
+// Some Product IDs
+#define PCI_PRODUCT_DEC_PZA 0x0008
+#define PCI_PRODUCT_NCR_810 0x0001
+#define PCI_PRODUCT_QLOGIC_ISP1020 0x1020
+#define PCI_PRODUCT_SIMOS_SIMOS 0x1291
+#define PCI_PRODUCT_SIMOS_ETHER 0x1292
+
+#endif // __PCIREG_H__
diff --git a/src/dev/pitreg.h b/src/dev/pitreg.h
new file mode 100644
index 000000000..5fe1cf03f
--- /dev/null
+++ b/src/dev/pitreg.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* @file
+ * Device register definitions for a device's PCI config space
+ */
+
+#ifndef __PITREG_H__
+#define __PITREG_H__
+
+#include <sys/types.h>
+
+// Control Word Format
+
+#define PIT_SEL_SHFT 0x6
+#define PIT_RW_SHFT 0x4
+#define PIT_MODE_SHFT 0x1
+#define PIT_BCD_SHFT 0x0
+
+#define PIT_SEL_MASK 0x3
+#define PIT_RW_MASK 0x3
+#define PIT_MODE_MASK 0x7
+#define PIT_BCD_MASK 0x1
+
+#define GET_CTRL_FIELD(x, s, m) (((x) >> s) & m)
+#define GET_CTRL_SEL(x) GET_CTRL_FIELD(x, PIT_SEL_SHFT, PIT_SEL_MASK)
+#define GET_CTRL_RW(x) GET_CTRL_FIELD(x, PIT_RW_SHFT, PIT_RW_MASK)
+#define GET_CTRL_MODE(x) GET_CTRL_FIELD(x, PIT_MODE_SHFT, PIT_MODE_MASK)
+#define GET_CTRL_BCD(x) GET_CTRL_FIELD(x, PIT_BCD_SHFT, PIT_BCD_MASK)
+
+#define PIT_READ_BACK 0x3
+
+#define PIT_RW_LATCH_COMMAND 0x0
+#define PIT_RW_LSB_ONLY 0x1
+#define PIT_RW_MSB_ONLY 0x2
+#define PIT_RW_16BIT 0x3
+
+#define PIT_MODE_INTTC 0x0
+#define PIT_MODE_ONESHOT 0x1
+#define PIT_MODE_RATEGEN 0x2
+#define PIT_MODE_SQWAVE 0x3
+#define PIT_MODE_SWSTROBE 0x4
+#define PIT_MODE_HWSTROBE 0x5
+
+#define PIT_BCD_FALSE 0x0
+#define PIT_BCD_TRUE 0x1
+
+#endif // __PITREG_H__
diff --git a/src/dev/pktfifo.cc b/src/dev/pktfifo.cc
new file mode 100644
index 000000000..922a66912
--- /dev/null
+++ b/src/dev/pktfifo.cc
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "base/misc.hh"
+#include "dev/pktfifo.hh"
+
+using namespace std;
+
+bool
+PacketFifo::copyout(void *dest, int offset, int len)
+{
+ char *data = (char *)dest;
+ if (offset + len >= size())
+ return false;
+
+ list<EthPacketPtr>::iterator p = fifo.begin();
+ list<EthPacketPtr>::iterator end = fifo.end();
+ while (len > 0) {
+ while (offset >= (*p)->length) {
+ offset -= (*p)->length;
+ ++p;
+ }
+
+ if (p == end)
+ panic("invalid fifo");
+
+ int size = min((*p)->length - offset, len);
+ memcpy(data, (*p)->data, size);
+ offset = 0;
+ len -= size;
+ data += size;
+ ++p;
+ }
+
+ return true;
+}
+
+
+void
+PacketFifo::serialize(const string &base, ostream &os)
+{
+ paramOut(os, base + ".size", _size);
+ paramOut(os, base + ".maxsize", _maxsize);
+ paramOut(os, base + ".reserved", _reserved);
+ paramOut(os, base + ".packets", fifo.size());
+
+ int i = 0;
+ list<EthPacketPtr>::iterator p = fifo.begin();
+ list<EthPacketPtr>::iterator end = fifo.end();
+ while (p != end) {
+ (*p)->serialize(csprintf("%s.packet%d", base, i), os);
+ ++p;
+ ++i;
+ }
+}
+
+void
+PacketFifo::unserialize(const string &base, Checkpoint *cp,
+ const string &section)
+{
+ paramIn(cp, section, base + ".size", _size);
+// paramIn(cp, section, base + ".maxsize", _maxsize);
+ paramIn(cp, section, base + ".reserved", _reserved);
+ int fifosize;
+ paramIn(cp, section, base + ".packets", fifosize);
+
+ fifo.clear();
+
+ for (int i = 0; i < fifosize; ++i) {
+ EthPacketPtr p = new EthPacketData(16384);
+ p->unserialize(csprintf("%s.packet%d", base, i), cp, section);
+ fifo.push_back(p);
+ }
+}
diff --git a/src/dev/pktfifo.hh b/src/dev/pktfifo.hh
new file mode 100644
index 000000000..336da22d8
--- /dev/null
+++ b/src/dev/pktfifo.hh
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __DEV_PKTFIFO_HH__
+#define __DEV_PKTFIFO_HH__
+
+#include <iosfwd>
+#include <list>
+#include <string>
+
+#include "dev/etherpkt.hh"
+#include "sim/serialize.hh"
+
+class Checkpoint;
+class PacketFifo
+{
+ public:
+ typedef std::list<EthPacketPtr> fifo_list;
+ typedef fifo_list::iterator iterator;
+
+ protected:
+ std::list<EthPacketPtr> fifo;
+ int _maxsize;
+ int _size;
+ int _reserved;
+
+ public:
+ explicit PacketFifo(int max) : _maxsize(max), _size(0), _reserved(0) {}
+ virtual ~PacketFifo() {}
+
+ int packets() const { return fifo.size(); }
+ int maxsize() const { return _maxsize; }
+ int size() const { return _size; }
+ int reserved() const { return _reserved; }
+ int avail() const { return _maxsize - _size - _reserved; }
+ bool empty() const { return size() <= 0; }
+ bool full() const { return avail() <= 0; }
+
+ int reserve(int len = 0)
+ {
+ _reserved += len;
+ assert(avail() >= 0);
+ return _reserved;
+ }
+
+ iterator begin() { return fifo.begin(); }
+ iterator end() { return fifo.end(); }
+
+ EthPacketPtr front() { return fifo.front(); }
+
+ bool push(EthPacketPtr ptr)
+ {
+ assert(ptr->length);
+ assert(_reserved <= ptr->length);
+ assert(ptr->slack == 0);
+ if (avail() < ptr->length - _reserved)
+ return false;
+
+ _size += ptr->length;
+ fifo.push_back(ptr);
+ _reserved = 0;
+ return true;
+ }
+
+ void pop()
+ {
+ if (empty())
+ return;
+
+ EthPacketPtr &packet = fifo.front();
+ _size -= packet->length;
+ _size -= packet->slack;
+ packet->slack = 0;
+ packet = NULL;
+ fifo.pop_front();
+ }
+
+ void clear()
+ {
+ for (iterator i = begin(); i != end(); ++i)
+ (*i)->slack = 0;
+ fifo.clear();
+ _size = 0;
+ _reserved = 0;
+ }
+
+ void remove(iterator i)
+ {
+ EthPacketPtr &packet = *i;
+ if (i != fifo.begin()) {
+ iterator prev = i;
+ --prev;
+ assert(prev != fifo.end());
+ (*prev)->slack += packet->length;
+ } else {
+ _size -= packet->length;
+ _size -= packet->slack;
+ }
+
+ packet->slack = 0;
+ packet = NULL;
+ fifo.erase(i);
+ }
+
+ bool copyout(void *dest, int offset, int len);
+
+ int countPacketsBefore(iterator end)
+ {
+ iterator i = fifo.begin();
+ int count = 0;
+
+ while (i != end) {
+ ++count;
+ ++i;
+ }
+
+ return count;
+ }
+
+ int countPacketsAfter(iterator i)
+ {
+ iterator end = fifo.end();
+ int count = 0;
+
+ while (i != end) {
+ ++count;
+ ++i;
+ }
+
+ return count;
+ }
+
+
+/**
+ * Serialization stuff
+ */
+ public:
+ void serialize(const std::string &base, std::ostream &os);
+ void unserialize(const std::string &base,
+ Checkpoint *cp, const std::string &section);
+};
+
+#endif // __DEV_PKTFIFO_HH__
diff --git a/src/dev/platform.cc b/src/dev/platform.cc
new file mode 100644
index 000000000..9d10e0828
--- /dev/null
+++ b/src/dev/platform.cc
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "dev/platform.hh"
+#include "sim/builder.hh"
+#include "sim/sim_exit.hh"
+
+using namespace std;
+using namespace TheISA;
+
+Platform::Platform(const string &name, IntrControl *intctrl)
+ : SimObject(name), intrctrl(intctrl)
+{
+}
+
+Platform::~Platform()
+{
+}
+
+void
+Platform::postPciInt(int line)
+{
+ panic("No PCI interrupt support in platform.");
+}
+
+void
+Platform::clearPciInt(int line)
+{
+ panic("No PCI interrupt support in platform.");
+}
+
+Addr
+Platform::pciToDma(Addr pciAddr) const
+{
+ panic("No PCI dma support in platform.");
+}
+
+DEFINE_SIM_OBJECT_CLASS_NAME("Platform", Platform)
+
diff --git a/src/dev/platform.hh b/src/dev/platform.hh
new file mode 100644
index 000000000..f149ca2fb
--- /dev/null
+++ b/src/dev/platform.hh
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * Generic interface for platforms
+ */
+
+#ifndef __DEV_PLATFORM_HH__
+#define __DEV_PLATFORM_HH__
+
+#include "sim/sim_object.hh"
+#include "arch/isa_traits.hh"
+
+class PciConfigAll;
+class IntrControl;
+class SimConsole;
+class Uart;
+class System;
+
+class Platform : public SimObject
+{
+ public:
+ /** Pointer to the interrupt controller */
+ IntrControl *intrctrl;
+
+ /** Pointer to the PCI configuration space */
+ PciConfigAll *pciconfig;
+
+ /** Pointer to the UART, set by the uart */
+ Uart *uart;
+
+ /** Pointer to the system for info about the memory system. */
+ System *system;
+
+ public:
+ Platform(const std::string &name, IntrControl *intctrl);
+ virtual ~Platform();
+ virtual void init() { if (pciconfig == NULL) panic("PCI Config not set"); }
+ virtual void postConsoleInt() = 0;
+ virtual void clearConsoleInt() = 0;
+ virtual Tick intrFrequency() = 0;
+ virtual void postPciInt(int line);
+ virtual void clearPciInt(int line);
+ virtual Addr pciToDma(Addr pciAddr) const;
+};
+
+#endif // __DEV_PLATFORM_HH__
diff --git a/src/dev/rtcreg.h b/src/dev/rtcreg.h
new file mode 100644
index 000000000..5025a0e95
--- /dev/null
+++ b/src/dev/rtcreg.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define RTC_SEC 0x00
+#define RTC_SEC_ALRM 0x01
+#define RTC_MIN 0x02
+#define RTC_MIN_ALRM 0x03
+#define RTC_HR 0x04
+#define RTC_HR_ALRM 0x05
+#define RTC_DOW 0x06
+#define RTC_DOM 0x07
+#define RTC_MON 0x08
+#define RTC_YEAR 0x09
+
+#define RTC_STAT_REGA 0x0A
+#define RTCA_1024HZ 0x06 /* 1024Hz periodic interrupt frequency */
+#define RTCA_32768HZ 0x20 /* 22-stage divider, 32.768KHz timebase */
+#define RTCA_UIP 0x80 /* 1 = date and time update in progress */
+
+#define RTC_STAT_REGB 0x0B
+#define RTCB_DST 0x01 /* USA Daylight Savings Time enable */
+#define RTCB_24HR 0x02 /* 0 = 12 hours, 1 = 24 hours */
+#define RTCB_BIN 0x04 /* 0 = BCD, 1 = Binary coded time */
+#define RTCB_SQWE 0x08 /* 1 = output sqare wave at SQW pin */
+#define RTCB_UPDT_IE 0x10 /* 1 = enable update-ended interrupt */
+#define RTCB_ALRM_IE 0x20 /* 1 = enable alarm interrupt */
+#define RTCB_PRDC_IE 0x40 /* 1 = enable periodic clock interrupt */
+#define RTCB_NO_UPDT 0x80 /* stop clock updates */
+
+#define RTC_STAT_REGC 0x0C
+#define RTC_STAT_REGD 0x0D
+
diff --git a/src/dev/simconsole.cc b/src/dev/simconsole.cc
new file mode 100644
index 000000000..c3e4f554a
--- /dev/null
+++ b/src/dev/simconsole.cc
@@ -0,0 +1,414 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* @file
+ * Implements the user interface to a serial console
+ */
+
+#include <sys/ioctl.h>
+#include <sys/termios.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <poll.h>
+#include <unistd.h>
+
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <string>
+
+#include "base/misc.hh"
+#include "base/output.hh"
+#include "base/socket.hh"
+#include "base/trace.hh"
+#include "dev/platform.hh"
+#include "dev/simconsole.hh"
+#include "dev/uart.hh"
+#include "sim/builder.hh"
+
+using namespace std;
+
+////////////////////////////////////////////////////////////////////////
+//
+//
+
+SimConsole::Event::Event(SimConsole *c, int fd, int e)
+ : PollEvent(fd, e), cons(c)
+{
+}
+
+void
+SimConsole::Event::process(int revent)
+{
+ if (revent & POLLIN)
+ cons->data();
+ else if (revent & POLLNVAL)
+ cons->detach();
+}
+
+SimConsole::SimConsole(const string &name, ostream *os, int num)
+ : SimObject(name), event(NULL), number(num), in_fd(-1), out_fd(-1),
+ listener(NULL), txbuf(16384), rxbuf(16384), outfile(os)
+#if TRACING_ON == 1
+ , linebuf(16384)
+#endif
+{
+ if (outfile)
+ outfile->setf(ios::unitbuf);
+}
+
+SimConsole::~SimConsole()
+{
+ close();
+}
+
+void
+SimConsole::close()
+{
+ if (in_fd != -1)
+ ::close(in_fd);
+
+ if (out_fd != in_fd && out_fd != -1)
+ ::close(out_fd);
+}
+
+void
+SimConsole::attach(int in, int out, ConsoleListener *l)
+{
+ in_fd = in;
+ out_fd = out;
+ listener = l;
+
+ event = new Event(this, in, POLLIN);
+ pollQueue.schedule(event);
+
+ stringstream stream;
+ ccprintf(stream, "==== m5 slave console: Console %d ====", number);
+
+ // we need an actual carriage return followed by a newline for the
+ // terminal
+ stream << "\r\n";
+
+ write((const uint8_t *)stream.str().c_str(), stream.str().size());
+
+
+ DPRINTFN("attach console %d\n", number);
+
+ txbuf.readall(out);
+}
+
+void
+SimConsole::detach()
+{
+ close();
+ in_fd = -1;
+ out_fd = -1;
+
+ pollQueue.remove(event);
+
+ if (listener) {
+ listener->add(this);
+ listener = NULL;
+ }
+
+ DPRINTFN("detach console %d\n", number);
+}
+
+void
+SimConsole::data()
+{
+ uint8_t buf[1024];
+ int len;
+
+ len = read(buf, sizeof(buf));
+ if (len) {
+ rxbuf.write((char *)buf, len);
+ // Inform the UART there is data available
+ uart->dataAvailable();
+ }
+}
+
+size_t
+SimConsole::read(uint8_t *buf, size_t len)
+{
+ if (in_fd < 0)
+ panic("Console not properly attached.\n");
+
+ size_t ret;
+ do {
+ ret = ::read(in_fd, buf, len);
+ } while (ret == -1 && errno == EINTR);
+
+
+ if (ret < 0)
+ DPRINTFN("Read failed.\n");
+
+ if (ret <= 0) {
+ detach();
+ return 0;
+ }
+
+ return ret;
+}
+
+// Console output.
+size_t
+SimConsole::write(const uint8_t *buf, size_t len)
+{
+ if (out_fd < 0)
+ panic("Console not properly attached.\n");
+
+ size_t ret;
+ for (;;) {
+ ret = ::write(out_fd, buf, len);
+
+ if (ret >= 0)
+ break;
+
+ if (errno != EINTR)
+ detach();
+ }
+
+ return ret;
+}
+
+#define MORE_PENDING (ULL(1) << 61)
+#define RECEIVE_SUCCESS (ULL(0) << 62)
+#define RECEIVE_NONE (ULL(2) << 62)
+#define RECEIVE_ERROR (ULL(3) << 62)
+
+bool
+SimConsole::in(uint8_t &c)
+{
+ bool empty, ret;
+
+ empty = rxbuf.empty();
+ ret = !empty;
+ if (!empty) {
+ rxbuf.read((char *)&c, 1);
+ empty = rxbuf.empty();
+ }
+
+ DPRINTF(ConsoleVerbose, "in: \'%c\' %#02x more: %d, return: %d\n",
+ isprint(c) ? c : ' ', c, !empty, ret);
+
+ return ret;
+}
+
+uint64_t
+SimConsole::console_in()
+{
+ uint8_t c;
+ uint64_t value;
+
+ if (in(c)) {
+ value = RECEIVE_SUCCESS | c;
+ if (!rxbuf.empty())
+ value |= MORE_PENDING;
+ } else {
+ value = RECEIVE_NONE;
+ }
+
+ DPRINTF(ConsoleVerbose, "console_in: return: %#x\n", value);
+
+ return value;
+}
+
+void
+SimConsole::out(char c)
+{
+#if TRACING_ON == 1
+ if (DTRACE(Console)) {
+ static char last = '\0';
+
+ if (c != '\n' && c != '\r' ||
+ last != '\n' && last != '\r') {
+ if (c == '\n' || c == '\r') {
+ int size = linebuf.size();
+ char *buffer = new char[size + 1];
+ linebuf.read(buffer, size);
+ buffer[size] = '\0';
+ DPRINTF(Console, "%s\n", buffer);
+ delete [] buffer;
+ } else {
+ linebuf.write(c);
+ }
+ }
+
+ last = c;
+ }
+#endif
+
+ txbuf.write(c);
+
+ if (out_fd >= 0)
+ write(c);
+
+ if (outfile)
+ outfile->write(&c, 1);
+
+ DPRINTF(ConsoleVerbose, "out: \'%c\' %#02x\n",
+ isprint(c) ? c : ' ', (int)c);
+
+}
+
+
+void
+SimConsole::serialize(ostream &os)
+{
+}
+
+void
+SimConsole::unserialize(Checkpoint *cp, const std::string &section)
+{
+}
+
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimConsole)
+
+ SimObjectParam<ConsoleListener *> listener;
+ SimObjectParam<IntrControl *> intr_control;
+ Param<string> output;
+ Param<bool> append_name;
+ Param<int> number;
+
+END_DECLARE_SIM_OBJECT_PARAMS(SimConsole)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(SimConsole)
+
+ INIT_PARAM(listener, "console listener"),
+ INIT_PARAM(intr_control, "interrupt controller"),
+ INIT_PARAM(output, "file to dump output to"),
+ INIT_PARAM_DFLT(append_name, "append name() to filename", true),
+ INIT_PARAM_DFLT(number, "console number", 0)
+
+END_INIT_SIM_OBJECT_PARAMS(SimConsole)
+
+CREATE_SIM_OBJECT(SimConsole)
+{
+ string filename = output;
+ ostream *stream = NULL;
+
+ if (!filename.empty()) {
+ if (append_name)
+ filename += "." + getInstanceName();
+ stream = simout.find(filename);
+ }
+
+ SimConsole *console = new SimConsole(getInstanceName(), stream, number);
+ ((ConsoleListener *)listener)->add(console);
+
+ return console;
+}
+
+REGISTER_SIM_OBJECT("SimConsole", SimConsole)
+
+////////////////////////////////////////////////////////////////////////
+//
+//
+
+ConsoleListener::ConsoleListener(const string &name)
+ : SimObject(name), event(NULL)
+{}
+
+ConsoleListener::~ConsoleListener()
+{
+ if (event)
+ delete event;
+}
+
+void
+ConsoleListener::Event::process(int revent)
+{
+ listener->accept();
+}
+
+///////////////////////////////////////////////////////////////////////
+// socket creation and console attach
+//
+
+void
+ConsoleListener::listen(int port)
+{
+ while (!listener.listen(port, true)) {
+ DPRINTF(Console,
+ ": can't bind address console port %d inuse PID %d\n",
+ port, getpid());
+ port++;
+ }
+
+ ccprintf(cerr, "Listening for console connection on port %d\n", port);
+
+ event = new Event(this, listener.getfd(), POLLIN);
+ pollQueue.schedule(event);
+}
+
+void
+ConsoleListener::add(SimConsole *cons)
+{ ConsoleList.push_back(cons);}
+
+void
+ConsoleListener::accept()
+{
+ if (!listener.islistening())
+ panic("%s: cannot accept a connection if not listening!", name());
+
+ int sfd = listener.accept(true);
+ if (sfd != -1) {
+ iter_t i = ConsoleList.begin();
+ iter_t end = ConsoleList.end();
+ if (i == end) {
+ close(sfd);
+ } else {
+ (*i)->attach(sfd, this);
+ i = ConsoleList.erase(i);
+ }
+ }
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(ConsoleListener)
+
+ Param<int> port;
+
+END_DECLARE_SIM_OBJECT_PARAMS(ConsoleListener)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(ConsoleListener)
+
+ INIT_PARAM_DFLT(port, "listen port", 3456)
+
+END_INIT_SIM_OBJECT_PARAMS(ConsoleListener)
+
+CREATE_SIM_OBJECT(ConsoleListener)
+{
+ ConsoleListener *listener = new ConsoleListener(getInstanceName());
+ listener->listen(port);
+
+ return listener;
+}
+
+REGISTER_SIM_OBJECT("ConsoleListener", ConsoleListener)
diff --git a/src/dev/simconsole.hh b/src/dev/simconsole.hh
new file mode 100644
index 000000000..cf0641f9e
--- /dev/null
+++ b/src/dev/simconsole.hh
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* @file
+ * User Console Interface
+ */
+
+#ifndef __CONSOLE_HH__
+#define __CONSOLE_HH__
+
+#include <iostream>
+
+#include "base/circlebuf.hh"
+#include "cpu/intr_control.hh"
+#include "base/pollevent.hh"
+#include "base/socket.hh"
+#include "sim/sim_object.hh"
+
+class ConsoleListener;
+class Uart;
+
+class SimConsole : public SimObject
+{
+ public:
+ Uart *uart;
+
+ protected:
+ class Event : public PollEvent
+ {
+ protected:
+ SimConsole *cons;
+
+ public:
+ Event(SimConsole *c, int fd, int e);
+ void process(int revent);
+ };
+
+ friend class Event;
+ Event *event;
+
+ protected:
+ int number;
+ int in_fd;
+ int out_fd;
+ ConsoleListener *listener;
+
+ public:
+ SimConsole(const std::string &name, std::ostream *os, int num);
+ ~SimConsole();
+
+ protected:
+ CircleBuf txbuf;
+ CircleBuf rxbuf;
+ std::ostream *outfile;
+#if TRACING_ON == 1
+ CircleBuf linebuf;
+#endif
+
+ public:
+ ///////////////////////
+ // Terminal Interface
+
+ void attach(int fd, ConsoleListener *l = NULL) { attach(fd, fd, l); }
+ void attach(int in, int out, ConsoleListener *l = NULL);
+ void detach();
+
+ void data();
+
+ void close();
+ void read(uint8_t &c) { read(&c, 1); }
+ size_t read(uint8_t *buf, size_t len);
+ void write(uint8_t c) { write(&c, 1); }
+ size_t write(const uint8_t *buf, size_t len);
+
+ public:
+ /////////////////
+ // OS interface
+
+ // Get a character from the console.
+ bool in(uint8_t &value);
+
+ // get a character from the console in the console specific format
+ // corresponds to GETC:
+ // retval<63:61>
+ // 000: success: character received
+ // 001: success: character received, more pending
+ // 100: failure: no character ready
+ // 110: failure: character received with error
+ // 111: failure: character received with error, more pending
+ // retval<31:0>
+ // character read from console
+ //
+ // Interrupts are cleared when the buffer is empty.
+ uint64_t console_in();
+
+ // Send a character to the console
+ void out(char c);
+
+ //Ask the console if data is available
+ bool dataAvailable() { return !rxbuf.empty(); }
+
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+};
+
+class ConsoleListener : public SimObject
+{
+ protected:
+ class Event : public PollEvent
+ {
+ protected:
+ ConsoleListener *listener;
+
+ public:
+ Event(ConsoleListener *l, int fd, int e)
+ : PollEvent(fd, e), listener(l) {}
+ void process(int revent);
+ };
+
+ friend class Event;
+ Event *event;
+
+ typedef std::list<SimConsole *> list_t;
+ typedef list_t::iterator iter_t;
+ list_t ConsoleList;
+
+ protected:
+ ListenSocket listener;
+
+ public:
+ ConsoleListener(const std::string &name);
+ ~ConsoleListener();
+
+ void add(SimConsole *cons);
+
+ void accept();
+ void listen(int port);
+};
+
+#endif // __CONSOLE_HH__
diff --git a/src/dev/simple_disk.cc b/src/dev/simple_disk.cc
new file mode 100644
index 000000000..9eee4668c
--- /dev/null
+++ b/src/dev/simple_disk.cc
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* @file
+ * Simple disk interface for the system console
+ */
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <cstring>
+#include <string>
+
+#include "base/misc.hh"
+#include "base/trace.hh"
+#include "dev/disk_image.hh"
+#include "dev/simple_disk.hh"
+#include "mem/port.hh"
+#include "sim/builder.hh"
+#include "sim/system.hh"
+
+using namespace std;
+
+SimpleDisk::SimpleDisk(const string &name, System *sys, DiskImage *img)
+ : SimObject(name), system(sys), image(img)
+{}
+
+SimpleDisk::~SimpleDisk()
+{}
+
+
+void
+SimpleDisk::read(Addr addr, baddr_t block, int count) const
+{
+ uint8_t *data = new uint8_t[SectorSize * count];
+
+ if (count & (SectorSize - 1))
+ panic("Not reading a multiple of a sector (count = %d)", count);
+
+ for (int i = 0, j = 0; i < count; i += SectorSize, j++)
+ image->read(data + i, block + j);
+
+ system->functionalPort.writeBlob(addr, data, count);
+
+ DPRINTF(SimpleDisk, "read block=%#x len=%d\n", (uint64_t)block, count);
+ DDUMP(SimpleDiskData, data, count);
+
+ delete data;
+}
+
+void
+SimpleDisk::write(Addr addr, baddr_t block, int count)
+{
+ panic("unimplemented!\n");
+
+#if 0
+ uint8_t *data = physmem->dma_addr(addr, count);
+ if (!data)
+ panic("dma out of range! write addr=%#x count=%d\n", addr, count);
+
+ image->write(data, block, count);
+#endif
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleDisk)
+
+ SimObjectParam<System *> system;
+ SimObjectParam<DiskImage *> disk;
+
+END_DECLARE_SIM_OBJECT_PARAMS(SimpleDisk)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleDisk)
+
+ INIT_PARAM(system, "System pointer"),
+ INIT_PARAM(disk, "Disk Image")
+
+END_INIT_SIM_OBJECT_PARAMS(SimpleDisk)
+
+CREATE_SIM_OBJECT(SimpleDisk)
+{
+ return new SimpleDisk(getInstanceName(), system, disk);
+}
+
+REGISTER_SIM_OBJECT("SimpleDisk", SimpleDisk)
diff --git a/src/dev/simple_disk.hh b/src/dev/simple_disk.hh
new file mode 100644
index 000000000..19967f208
--- /dev/null
+++ b/src/dev/simple_disk.hh
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* @file
+ * Simple disk interface for the system console
+ */
+
+#ifndef __DEV_SIMPLE_DISK_HH__
+#define __DEV_SIMPLE_DISK_HH__
+
+#include "sim/sim_object.hh"
+#include "arch/isa_traits.hh"
+
+class DiskImage;
+class System;
+
+/*
+ * Trivial interface to a disk image used by the System Console
+ */
+class SimpleDisk : public SimObject
+{
+ public:
+ typedef uint64_t baddr_t;
+
+ protected:
+ System *system;
+ DiskImage *image;
+
+ public:
+ SimpleDisk(const std::string &name, System *sys, DiskImage *img);
+ ~SimpleDisk();
+
+ void read(Addr addr, baddr_t block, int count) const;
+ void write(Addr addr, baddr_t block, int count);
+};
+
+#endif // __DEV_SIMPLE_DISK_HH__
diff --git a/src/dev/sinic.cc b/src/dev/sinic.cc
new file mode 100644
index 000000000..df7e4d167
--- /dev/null
+++ b/src/dev/sinic.cc
@@ -0,0 +1,1756 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <deque>
+#include <limits>
+#include <string>
+
+#include "base/inet.hh"
+#include "cpu/exec_context.hh"
+#include "cpu/intr_control.hh"
+#include "dev/etherlink.hh"
+#include "dev/sinic.hh"
+#include "dev/pciconfigall.hh"
+#include "mem/packet.hh"
+#include "sim/builder.hh"
+#include "sim/debug.hh"
+#include "sim/eventq.hh"
+#include "sim/host.hh"
+#include "sim/stats.hh"
+#include "arch/vtophys.hh"
+
+using namespace Net;
+using namespace TheISA;
+
+namespace Sinic {
+
+const char *RxStateStrings[] =
+{
+ "rxIdle",
+ "rxFifoBlock",
+ "rxBeginCopy",
+ "rxCopy",
+ "rxCopyDone"
+};
+
+const char *TxStateStrings[] =
+{
+ "txIdle",
+ "txFifoBlock",
+ "txBeginCopy",
+ "txCopy",
+ "txCopyDone"
+};
+
+
+///////////////////////////////////////////////////////////////////////
+//
+// Sinic PCI Device
+//
+Base::Base(Params *p)
+ : PciDev(p), rxEnable(false), txEnable(false), clock(p->clock),
+ intrDelay(p->intr_delay), intrTick(0), cpuIntrEnable(false),
+ cpuPendingIntr(false), intrEvent(0), interface(NULL)
+{
+}
+
+Device::Device(Params *p)
+ : Base(p), rxUnique(0), txUnique(0),
+ virtualRegs(p->virtual_count < 1 ? 1 : p->virtual_count),
+ rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size),
+ rxKickTick(0), txKickTick(0),
+ txEvent(this), rxDmaEvent(this), txDmaEvent(this),
+ dmaReadDelay(p->dma_read_delay), dmaReadFactor(p->dma_read_factor),
+ dmaWriteDelay(p->dma_write_delay), dmaWriteFactor(p->dma_write_factor)
+{
+ reset();
+
+}
+
+Device::~Device()
+{}
+
+void
+Device::regStats()
+{
+ rxBytes
+ .name(name() + ".rxBytes")
+ .desc("Bytes Received")
+ .prereq(rxBytes)
+ ;
+
+ rxBandwidth
+ .name(name() + ".rxBandwidth")
+ .desc("Receive Bandwidth (bits/s)")
+ .precision(0)
+ .prereq(rxBytes)
+ ;
+
+ rxPackets
+ .name(name() + ".rxPackets")
+ .desc("Number of Packets Received")
+ .prereq(rxBytes)
+ ;
+
+ rxPacketRate
+ .name(name() + ".rxPPS")
+ .desc("Packet Reception Rate (packets/s)")
+ .precision(0)
+ .prereq(rxBytes)
+ ;
+
+ rxIpPackets
+ .name(name() + ".rxIpPackets")
+ .desc("Number of IP Packets Received")
+ .prereq(rxBytes)
+ ;
+
+ rxTcpPackets
+ .name(name() + ".rxTcpPackets")
+ .desc("Number of Packets Received")
+ .prereq(rxBytes)
+ ;
+
+ rxUdpPackets
+ .name(name() + ".rxUdpPackets")
+ .desc("Number of UDP Packets Received")
+ .prereq(rxBytes)
+ ;
+
+ rxIpChecksums
+ .name(name() + ".rxIpChecksums")
+ .desc("Number of rx IP Checksums done by device")
+ .precision(0)
+ .prereq(rxBytes)
+ ;
+
+ rxTcpChecksums
+ .name(name() + ".rxTcpChecksums")
+ .desc("Number of rx TCP Checksums done by device")
+ .precision(0)
+ .prereq(rxBytes)
+ ;
+
+ rxUdpChecksums
+ .name(name() + ".rxUdpChecksums")
+ .desc("Number of rx UDP Checksums done by device")
+ .precision(0)
+ .prereq(rxBytes)
+ ;
+
+ totBandwidth
+ .name(name() + ".totBandwidth")
+ .desc("Total Bandwidth (bits/s)")
+ .precision(0)
+ .prereq(totBytes)
+ ;
+
+ totPackets
+ .name(name() + ".totPackets")
+ .desc("Total Packets")
+ .precision(0)
+ .prereq(totBytes)
+ ;
+
+ totBytes
+ .name(name() + ".totBytes")
+ .desc("Total Bytes")
+ .precision(0)
+ .prereq(totBytes)
+ ;
+
+ totPacketRate
+ .name(name() + ".totPPS")
+ .desc("Total Tranmission Rate (packets/s)")
+ .precision(0)
+ .prereq(totBytes)
+ ;
+
+ txBytes
+ .name(name() + ".txBytes")
+ .desc("Bytes Transmitted")
+ .prereq(txBytes)
+ ;
+
+ txBandwidth
+ .name(name() + ".txBandwidth")
+ .desc("Transmit Bandwidth (bits/s)")
+ .precision(0)
+ .prereq(txBytes)
+ ;
+
+ txPackets
+ .name(name() + ".txPackets")
+ .desc("Number of Packets Transmitted")
+ .prereq(txBytes)
+ ;
+
+ txPacketRate
+ .name(name() + ".txPPS")
+ .desc("Packet Tranmission Rate (packets/s)")
+ .precision(0)
+ .prereq(txBytes)
+ ;
+
+ txIpPackets
+ .name(name() + ".txIpPackets")
+ .desc("Number of IP Packets Transmitted")
+ .prereq(txBytes)
+ ;
+
+ txTcpPackets
+ .name(name() + ".txTcpPackets")
+ .desc("Number of TCP Packets Transmitted")
+ .prereq(txBytes)
+ ;
+
+ txUdpPackets
+ .name(name() + ".txUdpPackets")
+ .desc("Number of Packets Transmitted")
+ .prereq(txBytes)
+ ;
+
+ txIpChecksums
+ .name(name() + ".txIpChecksums")
+ .desc("Number of tx IP Checksums done by device")
+ .precision(0)
+ .prereq(txBytes)
+ ;
+
+ txTcpChecksums
+ .name(name() + ".txTcpChecksums")
+ .desc("Number of tx TCP Checksums done by device")
+ .precision(0)
+ .prereq(txBytes)
+ ;
+
+ txUdpChecksums
+ .name(name() + ".txUdpChecksums")
+ .desc("Number of tx UDP Checksums done by device")
+ .precision(0)
+ .prereq(txBytes)
+ ;
+
+ txBandwidth = txBytes * Stats::constant(8) / simSeconds;
+ rxBandwidth = rxBytes * Stats::constant(8) / simSeconds;
+ totBandwidth = txBandwidth + rxBandwidth;
+ totBytes = txBytes + rxBytes;
+ totPackets = txPackets + rxPackets;
+ txPacketRate = txPackets / simSeconds;
+ rxPacketRate = rxPackets / simSeconds;
+}
+
+void
+Device::prepareIO(int cpu, int index)
+{
+ int size = virtualRegs.size();
+ if (index > size)
+ panic("Trying to access a vnic that doesn't exist %d > %d\n",
+ index, size);
+}
+
+void
+Device::prepareRead(int cpu, int index)
+{
+ using namespace Regs;
+ prepareIO(cpu, index);
+
+ VirtualReg &vnic = virtualRegs[index];
+
+ // update rx registers
+ uint64_t rxdone = vnic.RxDone;
+ rxdone = set_RxDone_Packets(rxdone, rxFifo.countPacketsAfter(rxFifoPtr));
+ rxdone = set_RxDone_Empty(rxdone, rxFifo.empty());
+ rxdone = set_RxDone_High(rxdone, rxFifo.size() > regs.RxFifoMark);
+ rxdone = set_RxDone_NotHigh(rxdone, rxLow);
+ regs.RxData = vnic.RxData;
+ regs.RxDone = rxdone;
+ regs.RxWait = rxdone;
+
+ // update tx regsiters
+ uint64_t txdone = vnic.TxDone;
+ txdone = set_TxDone_Packets(txdone, txFifo.packets());
+ txdone = set_TxDone_Full(txdone, txFifo.avail() < regs.TxMaxCopy);
+ txdone = set_TxDone_Low(txdone, txFifo.size() < regs.TxFifoMark);
+ regs.TxData = vnic.TxData;
+ regs.TxDone = txdone;
+ regs.TxWait = txdone;
+}
+
+void
+Device::prepareWrite(int cpu, int index)
+{
+ prepareIO(cpu, index);
+}
+
+/**
+ * I/O read of device register
+ */
+Tick
+Device::read(Packet *pkt)
+{
+ assert(config.command & PCI_CMD_MSE);
+ assert(pkt->addr >= BARAddrs[0] && pkt->size < BARSize[0]);
+
+ int cpu = pkt->req->getCpuNum();
+ Addr daddr = pkt->addr - BARAddrs[0];
+ Addr index = daddr >> Regs::VirtualShift;
+ Addr raddr = daddr & Regs::VirtualMask;
+
+ pkt->time += pioDelay;
+ pkt->allocate();
+
+ if (!regValid(raddr))
+ panic("invalid register: cpu=%d vnic=%d da=%#x pa=%#x size=%d",
+ cpu, index, daddr, pkt->addr, pkt->size);
+
+ const Regs::Info &info = regInfo(raddr);
+ if (!info.read)
+ panic("read %s (write only): "
+ "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
+ info.name, cpu, index, daddr, pkt->addr, pkt->size);
+
+ panic("read %s (invalid size): "
+ "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
+ info.name, cpu, index, daddr, pkt->addr, pkt->size);
+
+ prepareRead(cpu, index);
+
+ uint64_t value = 0;
+ if (pkt->size == 4) {
+ uint32_t reg = regData32(raddr);
+ pkt->set(reg);
+ value = reg;
+ }
+
+ if (pkt->size == 8) {
+ uint64_t reg = regData64(raddr);
+ pkt->set(reg);
+ value = reg;
+ }
+
+ DPRINTF(EthernetPIO,
+ "read %s: cpu=%d vnic=%d da=%#x pa=%#x size=%d val=%#x\n",
+ info.name, cpu, index, daddr, pkt->addr, pkt->size, value);
+
+ // reading the interrupt status register has the side effect of
+ // clearing it
+ if (raddr == Regs::IntrStatus)
+ devIntrClear();
+
+ return pioDelay;
+}
+
+/**
+ * IPR read of device register
+
+ Fault
+Device::iprRead(Addr daddr, int cpu, uint64_t &result)
+{
+ if (!regValid(daddr))
+ panic("invalid address: da=%#x", daddr);
+
+ const Regs::Info &info = regInfo(daddr);
+ if (!info.read)
+ panic("reading %s (write only): cpu=%d da=%#x", info.name, cpu, daddr);
+
+ DPRINTF(EthernetPIO, "IPR read %s: cpu=%d da=%#x\n",
+ info.name, cpu, daddr);
+
+ prepareRead(cpu, 0);
+
+ if (info.size == 4)
+ result = regData32(daddr);
+
+ if (info.size == 8)
+ result = regData64(daddr);
+
+ DPRINTF(EthernetPIO, "IPR read %s: cpu=%s da=%#x val=%#x\n",
+ info.name, cpu, result);
+
+ return NoFault;
+}
+*/
+/**
+ * I/O write of device register
+ */
+Tick
+Device::write(Packet *pkt)
+{
+ assert(config.command & PCI_CMD_MSE);
+ assert(pkt->addr >= BARAddrs[0] && pkt->size < BARSize[0]);
+
+ int cpu = pkt->req->getCpuNum();
+ Addr daddr = pkt->addr - BARAddrs[0];
+ Addr index = daddr >> Regs::VirtualShift;
+ Addr raddr = daddr & Regs::VirtualMask;
+
+ pkt->time += pioDelay;
+
+ if (!regValid(raddr))
+ panic("invalid register: cpu=%d, da=%#x pa=%#x size=%d",
+ cpu, daddr, pkt->addr, pkt->size);
+
+ const Regs::Info &info = regInfo(raddr);
+ if (!info.write)
+ panic("write %s (read only): "
+ "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
+ info.name, cpu, index, daddr, pkt->addr, pkt->size);
+
+ if (pkt->size != info.size)
+ panic("write %s (invalid size): "
+ "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
+ info.name, cpu, index, daddr, pkt->addr, pkt->size);
+
+ VirtualReg &vnic = virtualRegs[index];
+
+ DPRINTF(EthernetPIO,
+ "write %s vnic %d: cpu=%d val=%#x da=%#x pa=%#x size=%d\n",
+ info.name, index, cpu, info.size == 4 ? pkt->get<uint32_t>() :
+ pkt->get<uint64_t>(), daddr, pkt->addr, pkt->size);
+
+ prepareWrite(cpu, index);
+
+ switch (raddr) {
+ case Regs::Config:
+ changeConfig(pkt->get<uint32_t>());
+ break;
+
+ case Regs::Command:
+ command(pkt->get<uint32_t>());
+ break;
+
+ case Regs::IntrStatus:
+ devIntrClear(regs.IntrStatus & pkt->get<uint32_t>());
+ break;
+
+ case Regs::IntrMask:
+ devIntrChangeMask(pkt->get<uint32_t>());
+ break;
+
+ case Regs::RxData:
+ if (Regs::get_RxDone_Busy(vnic.RxDone))
+ panic("receive machine busy with another request! rxState=%s",
+ RxStateStrings[rxState]);
+
+ vnic.rxUnique = rxUnique++;
+ vnic.RxDone = Regs::RxDone_Busy;
+ vnic.RxData = pkt->get<uint64_t>();
+
+ if (Regs::get_RxData_Vaddr(pkt->get<uint64_t>())) {
+ panic("vtophys not implemented in newmem");
+/* Addr vaddr = Regs::get_RxData_Addr(reg64);
+ Addr paddr = vtophys(req->xc, vaddr);
+ DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d): "
+ "vaddr=%#x, paddr=%#x\n",
+ index, vnic.rxUnique, vaddr, paddr);
+
+ vnic.RxData = Regs::set_RxData_Addr(vnic.RxData, paddr);*/
+ } else {
+ DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d)\n",
+ index, vnic.rxUnique);
+ }
+
+ if (vnic.rxPacket == rxFifo.end()) {
+ DPRINTF(EthernetPIO, "request new packet...appending to rxList\n");
+ rxList.push_back(index);
+ } else {
+ DPRINTF(EthernetPIO, "packet exists...appending to rxBusy\n");
+ rxBusy.push_back(index);
+ }
+
+ if (rxEnable && (rxState == rxIdle || rxState == rxFifoBlock)) {
+ rxState = rxFifoBlock;
+ rxKick();
+ }
+ break;
+
+ case Regs::TxData:
+ if (Regs::get_TxDone_Busy(vnic.TxDone))
+ panic("transmit machine busy with another request! txState=%s",
+ TxStateStrings[txState]);
+
+ vnic.txUnique = txUnique++;
+ vnic.TxDone = Regs::TxDone_Busy;
+
+ if (Regs::get_TxData_Vaddr(pkt->get<uint64_t>())) {
+ panic("vtophys won't work here in newmem.\n");
+ /*Addr vaddr = Regs::get_TxData_Addr(reg64);
+ Addr paddr = vtophys(req->xc, vaddr);
+ DPRINTF(EthernetPIO, "write TxData vnic %d (rxunique %d): "
+ "vaddr=%#x, paddr=%#x\n",
+ index, vnic.txUnique, vaddr, paddr);
+
+ vnic.TxData = Regs::set_TxData_Addr(vnic.TxData, paddr);*/
+ } else {
+ DPRINTF(EthernetPIO, "write TxData vnic %d (rxunique %d)\n",
+ index, vnic.txUnique);
+ }
+
+ if (txList.empty() || txList.front() != index)
+ txList.push_back(index);
+ if (txEnable && txState == txIdle && txList.front() == index) {
+ txState = txFifoBlock;
+ txKick();
+ }
+ break;
+ }
+
+ return pioDelay;
+}
+
+void
+Device::devIntrPost(uint32_t interrupts)
+{
+ if ((interrupts & Regs::Intr_Res))
+ panic("Cannot set a reserved interrupt");
+
+ regs.IntrStatus |= interrupts;
+
+ DPRINTF(EthernetIntr,
+ "interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n",
+ interrupts, regs.IntrStatus, regs.IntrMask);
+
+ interrupts = regs.IntrStatus & regs.IntrMask;
+
+ // Intr_RxHigh is special, we only signal it if we've emptied the fifo
+ // and then filled it above the high watermark
+ if (rxEmpty)
+ rxEmpty = false;
+ else
+ interrupts &= ~Regs::Intr_RxHigh;
+
+ // Intr_TxLow is special, we only signal it if we've filled up the fifo
+ // and then dropped below the low watermark
+ if (txFull)
+ txFull = false;
+ else
+ interrupts &= ~Regs::Intr_TxLow;
+
+ if (interrupts) {
+ Tick when = curTick;
+ if ((interrupts & Regs::Intr_NoDelay) == 0)
+ when += intrDelay;
+ cpuIntrPost(when);
+ }
+}
+
+void
+Device::devIntrClear(uint32_t interrupts)
+{
+ if ((interrupts & Regs::Intr_Res))
+ panic("Cannot clear a reserved interrupt");
+
+ regs.IntrStatus &= ~interrupts;
+
+ DPRINTF(EthernetIntr,
+ "interrupt cleared from intStatus: intr=%x status=%x mask=%x\n",
+ interrupts, regs.IntrStatus, regs.IntrMask);
+
+ if (!(regs.IntrStatus & regs.IntrMask))
+ cpuIntrClear();
+}
+
+void
+Device::devIntrChangeMask(uint32_t newmask)
+{
+ if (regs.IntrMask == newmask)
+ return;
+
+ regs.IntrMask = newmask;
+
+ DPRINTF(EthernetIntr,
+ "interrupt mask changed: intStatus=%x intMask=%x masked=%x\n",
+ regs.IntrStatus, regs.IntrMask, regs.IntrStatus & regs.IntrMask);
+
+ if (regs.IntrStatus & regs.IntrMask)
+ cpuIntrPost(curTick);
+ else
+ cpuIntrClear();
+}
+
+void
+Base::cpuIntrPost(Tick when)
+{
+ // If the interrupt you want to post is later than an interrupt
+ // already scheduled, just let it post in the coming one and don't
+ // schedule another.
+ // HOWEVER, must be sure that the scheduled intrTick is in the
+ // future (this was formerly the source of a bug)
+ /**
+ * @todo this warning should be removed and the intrTick code should
+ * be fixed.
+ */
+ assert(when >= curTick);
+ assert(intrTick >= curTick || intrTick == 0);
+ if (!cpuIntrEnable) {
+ DPRINTF(EthernetIntr, "interrupts not enabled.\n",
+ intrTick);
+ return;
+ }
+
+ if (when > intrTick && intrTick != 0) {
+ DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
+ intrTick);
+ return;
+ }
+
+ intrTick = when;
+ if (intrTick < curTick) {
+ debug_break();
+ intrTick = curTick;
+ }
+
+ DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
+ intrTick);
+
+ if (intrEvent)
+ intrEvent->squash();
+ intrEvent = new IntrEvent(this, true);
+ intrEvent->schedule(intrTick);
+}
+
+void
+Base::cpuInterrupt()
+{
+ assert(intrTick == curTick);
+
+ // Whether or not there's a pending interrupt, we don't care about
+ // it anymore
+ intrEvent = 0;
+ intrTick = 0;
+
+ // Don't send an interrupt if there's already one
+ if (cpuPendingIntr) {
+ DPRINTF(EthernetIntr,
+ "would send an interrupt now, but there's already pending\n");
+ } else {
+ // Send interrupt
+ cpuPendingIntr = true;
+
+ DPRINTF(EthernetIntr, "posting interrupt\n");
+ intrPost();
+ }
+}
+
+void
+Base::cpuIntrClear()
+{
+ if (!cpuPendingIntr)
+ return;
+
+ if (intrEvent) {
+ intrEvent->squash();
+ intrEvent = 0;
+ }
+
+ intrTick = 0;
+
+ cpuPendingIntr = false;
+
+ DPRINTF(EthernetIntr, "clearing cchip interrupt\n");
+ intrClear();
+}
+
+bool
+Base::cpuIntrPending() const
+{ return cpuPendingIntr; }
+
+void
+Device::changeConfig(uint32_t newconf)
+{
+ uint32_t changed = regs.Config ^ newconf;
+ if (!changed)
+ return;
+
+ regs.Config = newconf;
+
+ if ((changed & Regs::Config_IntEn)) {
+ cpuIntrEnable = regs.Config & Regs::Config_IntEn;
+ if (cpuIntrEnable) {
+ if (regs.IntrStatus & regs.IntrMask)
+ cpuIntrPost(curTick);
+ } else {
+ cpuIntrClear();
+ }
+ }
+
+ if ((changed & Regs::Config_TxEn)) {
+ txEnable = regs.Config & Regs::Config_TxEn;
+ if (txEnable)
+ txKick();
+ }
+
+ if ((changed & Regs::Config_RxEn)) {
+ rxEnable = regs.Config & Regs::Config_RxEn;
+ if (rxEnable)
+ rxKick();
+ }
+}
+
+void
+Device::command(uint32_t command)
+{
+ if (command & Regs::Command_Intr)
+ devIntrPost(Regs::Intr_Soft);
+
+ if (command & Regs::Command_Reset)
+ reset();
+}
+
+void
+Device::reset()
+{
+ using namespace Regs;
+
+ memset(&regs, 0, sizeof(regs));
+
+ regs.Config = 0;
+ if (params()->rx_thread)
+ regs.Config |= Config_RxThread;
+ if (params()->tx_thread)
+ regs.Config |= Config_TxThread;
+ if (params()->rss)
+ regs.Config |= Config_RSS;
+ if (params()->zero_copy)
+ regs.Config |= Config_ZeroCopy;
+ if (params()->delay_copy)
+ regs.Config |= Config_DelayCopy;
+ if (params()->virtual_addr)
+ regs.Config |= Config_Vaddr;
+
+ if (params()->delay_copy && params()->zero_copy)
+ panic("Can't delay copy and zero copy");
+
+ regs.IntrMask = Intr_Soft | Intr_RxHigh | Intr_RxPacket | Intr_TxLow;
+ regs.RxMaxCopy = params()->rx_max_copy;
+ regs.TxMaxCopy = params()->tx_max_copy;
+ regs.RxMaxIntr = params()->rx_max_intr;
+ regs.VirtualCount = params()->virtual_count;
+ regs.RxFifoSize = params()->rx_fifo_size;
+ regs.TxFifoSize = params()->tx_fifo_size;
+ regs.RxFifoMark = params()->rx_fifo_threshold;
+ regs.TxFifoMark = params()->tx_fifo_threshold;
+ regs.HwAddr = params()->eaddr;
+
+ rxList.clear();
+ rxBusy.clear();
+ rxActive = -1;
+ txList.clear();
+
+ rxState = rxIdle;
+ txState = txIdle;
+
+ rxFifo.clear();
+ rxFifoPtr = rxFifo.end();
+ txFifo.clear();
+ rxEmpty = false;
+ rxLow = true;
+ txFull = false;
+
+ int size = virtualRegs.size();
+ virtualRegs.clear();
+ virtualRegs.resize(size);
+ for (int i = 0; i < size; ++i)
+ virtualRegs[i].rxPacket = rxFifo.end();
+}
+
+void
+Device::rxDmaDone()
+{
+ assert(rxState == rxCopy);
+ rxState = rxCopyDone;
+ DPRINTF(EthernetDMA, "end rx dma write paddr=%#x len=%d\n",
+ rxDmaAddr, rxDmaLen);
+ DDUMP(EthernetData, rxDmaData, rxDmaLen);
+
+ // If the transmit state machine has a pending DMA, let it go first
+ if (txState == txBeginCopy)
+ txKick();
+
+ rxKick();
+}
+
+void
+Device::rxKick()
+{
+ VirtualReg *vnic = NULL;
+
+ DPRINTF(EthernetSM, "rxKick: rxState=%s (rxFifo.size=%d)\n",
+ RxStateStrings[rxState], rxFifo.size());
+
+ if (rxKickTick > curTick) {
+ DPRINTF(EthernetSM, "rxKick: exiting, can't run till %d\n",
+ rxKickTick);
+ return;
+ }
+
+ next:
+ if (rxState == rxIdle)
+ goto exit;
+
+ if (rxActive == -1) {
+ if (rxState != rxFifoBlock)
+ panic("no active vnic while in state %s", RxStateStrings[rxState]);
+
+ DPRINTF(EthernetSM, "processing rxState=%s\n",
+ RxStateStrings[rxState]);
+ } else {
+ vnic = &virtualRegs[rxActive];
+ DPRINTF(EthernetSM,
+ "processing rxState=%s for vnic %d (rxunique %d)\n",
+ RxStateStrings[rxState], rxActive, vnic->rxUnique);
+ }
+
+ switch (rxState) {
+ case rxFifoBlock:
+ if (DTRACE(EthernetSM)) {
+ PacketFifo::iterator end = rxFifo.end();
+ int size = virtualRegs.size();
+ for (int i = 0; i < size; ++i) {
+ VirtualReg *vn = &virtualRegs[i];
+ if (vn->rxPacket != end &&
+ !Regs::get_RxDone_Busy(vn->RxDone)) {
+ DPRINTF(EthernetSM,
+ "vnic %d (rxunique %d), has outstanding packet %d\n",
+ i, vn->rxUnique,
+ rxFifo.countPacketsBefore(vn->rxPacket));
+ }
+ }
+ }
+
+ if (!rxBusy.empty()) {
+ rxActive = rxBusy.front();
+ rxBusy.pop_front();
+ vnic = &virtualRegs[rxActive];
+
+ if (vnic->rxPacket == rxFifo.end())
+ panic("continuing vnic without packet\n");
+
+ DPRINTF(EthernetSM,
+ "continue processing for vnic %d (rxunique %d)\n",
+ rxActive, vnic->rxUnique);
+
+ rxState = rxBeginCopy;
+
+ break;
+ }
+
+ if (rxFifoPtr == rxFifo.end()) {
+ DPRINTF(EthernetSM, "receive waiting for data. Nothing to do.\n");
+ goto exit;
+ }
+
+ if (rxList.empty())
+ panic("Not idle, but nothing to do!");
+
+ assert(!rxFifo.empty());
+
+ rxActive = rxList.front();
+ rxList.pop_front();
+ vnic = &virtualRegs[rxActive];
+
+ DPRINTF(EthernetSM,
+ "processing new packet for vnic %d (rxunique %d)\n",
+ rxActive, vnic->rxUnique);
+
+ // Grab a new packet from the fifo.
+ vnic->rxPacket = rxFifoPtr++;
+ vnic->rxPacketOffset = 0;
+ vnic->rxPacketBytes = (*vnic->rxPacket)->length;
+ assert(vnic->rxPacketBytes);
+
+ vnic->rxDoneData = 0;
+ /* scope for variables */ {
+ IpPtr ip(*vnic->rxPacket);
+ if (ip) {
+ DPRINTF(Ethernet, "ID is %d\n", ip->id());
+ vnic->rxDoneData |= Regs::RxDone_IpPacket;
+ rxIpChecksums++;
+ if (cksum(ip) != 0) {
+ DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
+ vnic->rxDoneData |= Regs::RxDone_IpError;
+ }
+ TcpPtr tcp(ip);
+ UdpPtr udp(ip);
+ if (tcp) {
+ DPRINTF(Ethernet,
+ "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
+ tcp->sport(), tcp->dport(), tcp->seq(),
+ tcp->ack());
+ vnic->rxDoneData |= Regs::RxDone_TcpPacket;
+ rxTcpChecksums++;
+ if (cksum(tcp) != 0) {
+ DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
+ vnic->rxDoneData |= Regs::RxDone_TcpError;
+ }
+ } else if (udp) {
+ vnic->rxDoneData |= Regs::RxDone_UdpPacket;
+ rxUdpChecksums++;
+ if (cksum(udp) != 0) {
+ DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
+ vnic->rxDoneData |= Regs::RxDone_UdpError;
+ }
+ }
+ }
+ }
+ rxState = rxBeginCopy;
+ break;
+
+ case rxBeginCopy:
+ if (dmaPending())
+ goto exit;
+
+ rxDmaAddr = params()->platform->pciToDma(
+ Regs::get_RxData_Addr(vnic->RxData));
+ rxDmaLen = std::min<int>(Regs::get_RxData_Len(vnic->RxData),
+ vnic->rxPacketBytes);
+ rxDmaData = (*vnic->rxPacket)->data + vnic->rxPacketOffset;
+ rxState = rxCopy;
+ if (rxDmaAddr == 1LL) {
+ rxState = rxCopyDone;
+ break;
+ }
+
+
+ dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaEvent, rxDmaData);
+ break;
+
+ case rxCopy:
+ DPRINTF(EthernetSM, "receive machine still copying\n");
+ goto exit;
+
+ case rxCopyDone:
+ vnic->RxDone = vnic->rxDoneData;
+ vnic->RxDone |= Regs::RxDone_Complete;
+
+ if (vnic->rxPacketBytes == rxDmaLen) {
+ // Packet is complete. Indicate how many bytes were copied
+ vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, rxDmaLen);
+
+ DPRINTF(EthernetSM,
+ "rxKick: packet complete on vnic %d (rxunique %d)\n",
+ rxActive, vnic->rxUnique);
+ rxFifo.remove(vnic->rxPacket);
+ vnic->rxPacket = rxFifo.end();
+ } else {
+ vnic->rxPacketBytes -= rxDmaLen;
+ vnic->rxPacketOffset += rxDmaLen;
+ vnic->RxDone |= Regs::RxDone_More;
+ vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone,
+ vnic->rxPacketBytes);
+ DPRINTF(EthernetSM,
+ "rxKick: packet not complete on vnic %d (rxunique %d): "
+ "%d bytes left\n",
+ rxActive, vnic->rxUnique, vnic->rxPacketBytes);
+ }
+
+ rxActive = -1;
+ rxState = rxBusy.empty() && rxList.empty() ? rxIdle : rxFifoBlock;
+
+ if (rxFifo.empty()) {
+ devIntrPost(Regs::Intr_RxEmpty);
+ rxEmpty = true;
+ }
+
+ if (rxFifo.size() < params()->rx_fifo_low_mark)
+ rxLow = true;
+
+ if (rxFifo.size() > params()->rx_fifo_threshold)
+ rxLow = false;
+
+ devIntrPost(Regs::Intr_RxDMA);
+ break;
+
+ default:
+ panic("Invalid rxState!");
+ }
+
+ DPRINTF(EthernetSM, "entering next rxState=%s\n",
+ RxStateStrings[rxState]);
+
+ goto next;
+
+ exit:
+ /**
+ * @todo do we want to schedule a future kick?
+ */
+ DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
+ RxStateStrings[rxState]);
+}
+
+void
+Device::txDmaDone()
+{
+ assert(txState == txCopy);
+ txState = txCopyDone;
+ DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n",
+ txDmaAddr, txDmaLen);
+ DDUMP(EthernetData, txDmaData, txDmaLen);
+
+ // If the receive state machine has a pending DMA, let it go first
+ if (rxState == rxBeginCopy)
+ rxKick();
+
+ txKick();
+}
+
+void
+Device::transmit()
+{
+ if (txFifo.empty()) {
+ DPRINTF(Ethernet, "nothing to transmit\n");
+ return;
+ }
+
+ uint32_t interrupts;
+ EthPacketPtr packet = txFifo.front();
+ if (!interface->sendPacket(packet)) {
+ DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n",
+ txFifo.avail());
+ goto reschedule;
+ }
+
+ txFifo.pop();
+#if TRACING_ON
+ if (DTRACE(Ethernet)) {
+ IpPtr ip(packet);
+ if (ip) {
+ DPRINTF(Ethernet, "ID is %d\n", ip->id());
+ TcpPtr tcp(ip);
+ if (tcp) {
+ DPRINTF(Ethernet,
+ "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
+ tcp->sport(), tcp->dport(), tcp->seq(),
+ tcp->ack());
+ }
+ }
+ }
+#endif
+
+ DDUMP(EthernetData, packet->data, packet->length);
+ txBytes += packet->length;
+ txPackets++;
+
+ DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n",
+ txFifo.avail());
+
+ interrupts = Regs::Intr_TxPacket;
+ if (txFifo.size() < regs.TxFifoMark)
+ interrupts |= Regs::Intr_TxLow;
+ devIntrPost(interrupts);
+
+ reschedule:
+ if (!txFifo.empty() && !txEvent.scheduled()) {
+ DPRINTF(Ethernet, "reschedule transmit\n");
+ txEvent.schedule(curTick + retryTime);
+ }
+}
+
+void
+Device::txKick()
+{
+ VirtualReg *vnic;
+ DPRINTF(EthernetSM, "txKick: txState=%s (txFifo.size=%d)\n",
+ TxStateStrings[txState], txFifo.size());
+
+ if (txKickTick > curTick) {
+ DPRINTF(EthernetSM, "txKick: exiting, can't run till %d\n",
+ txKickTick);
+ return;
+ }
+
+ next:
+ if (txState == txIdle)
+ goto exit;
+
+ assert(!txList.empty());
+ vnic = &virtualRegs[txList.front()];
+
+ switch (txState) {
+ case txFifoBlock:
+ assert(Regs::get_TxDone_Busy(vnic->TxDone));
+ if (!txPacket) {
+ // Grab a new packet from the fifo.
+ txPacket = new EthPacketData(16384);
+ txPacketOffset = 0;
+ }
+
+ if (txFifo.avail() - txPacket->length <
+ Regs::get_TxData_Len(vnic->TxData)) {
+ DPRINTF(EthernetSM, "transmit fifo full. Nothing to do.\n");
+ goto exit;
+ }
+
+ txState = txBeginCopy;
+ break;
+
+ case txBeginCopy:
+ if (dmaPending())
+ goto exit;
+
+ txDmaAddr = params()->platform->pciToDma(
+ Regs::get_TxData_Addr(vnic->TxData));
+ txDmaLen = Regs::get_TxData_Len(vnic->TxData);
+ txDmaData = txPacket->data + txPacketOffset;
+ txState = txCopy;
+
+ dmaRead(txDmaAddr, txDmaLen, &txDmaEvent, txDmaData);
+ break;
+
+ case txCopy:
+ DPRINTF(EthernetSM, "transmit machine still copying\n");
+ goto exit;
+
+ case txCopyDone:
+ vnic->TxDone = txDmaLen | Regs::TxDone_Complete;
+ txPacket->length += txDmaLen;
+ if ((vnic->TxData & Regs::TxData_More)) {
+ txPacketOffset += txDmaLen;
+ txState = txIdle;
+ devIntrPost(Regs::Intr_TxDMA);
+ break;
+ }
+
+ assert(txPacket->length <= txFifo.avail());
+ if ((vnic->TxData & Regs::TxData_Checksum)) {
+ IpPtr ip(txPacket);
+ if (ip) {
+ TcpPtr tcp(ip);
+ if (tcp) {
+ tcp->sum(0);
+ tcp->sum(cksum(tcp));
+ txTcpChecksums++;
+ }
+
+ UdpPtr udp(ip);
+ if (udp) {
+ udp->sum(0);
+ udp->sum(cksum(udp));
+ txUdpChecksums++;
+ }
+
+ ip->sum(0);
+ ip->sum(cksum(ip));
+ txIpChecksums++;
+ }
+ }
+
+ txFifo.push(txPacket);
+ if (txFifo.avail() < regs.TxMaxCopy) {
+ devIntrPost(Regs::Intr_TxFull);
+ txFull = true;
+ }
+ txPacket = 0;
+ transmit();
+ txList.pop_front();
+ txState = txList.empty() ? txIdle : txFifoBlock;
+ devIntrPost(Regs::Intr_TxDMA);
+ break;
+
+ default:
+ panic("Invalid txState!");
+ }
+
+ DPRINTF(EthernetSM, "entering next txState=%s\n",
+ TxStateStrings[txState]);
+
+ goto next;
+
+ exit:
+ /**
+ * @todo do we want to schedule a future kick?
+ */
+ DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
+ TxStateStrings[txState]);
+}
+
+void
+Device::transferDone()
+{
+ if (txFifo.empty()) {
+ DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
+ return;
+ }
+
+ DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
+
+ if (txEvent.scheduled())
+ txEvent.reschedule(curTick + cycles(1));
+ else
+ txEvent.schedule(curTick + cycles(1));
+}
+
+bool
+Device::rxFilter(const EthPacketPtr &packet)
+{
+ if (!Regs::get_Config_Filter(regs.Config))
+ return false;
+
+ panic("receive filter not implemented\n");
+ bool drop = true;
+
+#if 0
+ string type;
+
+ EthHdr *eth = packet->eth();
+ if (eth->unicast()) {
+ // If we're accepting all unicast addresses
+ if (acceptUnicast)
+ drop = false;
+
+ // If we make a perfect match
+ if (acceptPerfect && params->eaddr == eth.dst())
+ drop = false;
+
+ if (acceptArp && eth->type() == ETH_TYPE_ARP)
+ drop = false;
+
+ } else if (eth->broadcast()) {
+ // if we're accepting broadcasts
+ if (acceptBroadcast)
+ drop = false;
+
+ } else if (eth->multicast()) {
+ // if we're accepting all multicasts
+ if (acceptMulticast)
+ drop = false;
+
+ }
+
+ if (drop) {
+ DPRINTF(Ethernet, "rxFilter drop\n");
+ DDUMP(EthernetData, packet->data, packet->length);
+ }
+#endif
+ return drop;
+}
+
+bool
+Device::recvPacket(EthPacketPtr packet)
+{
+ rxBytes += packet->length;
+ rxPackets++;
+
+ DPRINTF(Ethernet, "Receiving packet from wire, rxFifo Available is %d\n",
+ rxFifo.avail());
+
+ if (!rxEnable) {
+ DPRINTF(Ethernet, "receive disabled...packet dropped\n");
+ return true;
+ }
+
+ if (rxFilter(packet)) {
+ DPRINTF(Ethernet, "packet filtered...dropped\n");
+ return true;
+ }
+
+ if (rxFifo.size() >= regs.RxFifoMark)
+ devIntrPost(Regs::Intr_RxHigh);
+
+ if (!rxFifo.push(packet)) {
+ DPRINTF(Ethernet,
+ "packet will not fit in receive buffer...packet dropped\n");
+ return false;
+ }
+
+ // If we were at the last element, back up one ot go to the new
+ // last element of the list.
+ if (rxFifoPtr == rxFifo.end())
+ --rxFifoPtr;
+
+ devIntrPost(Regs::Intr_RxPacket);
+ rxKick();
+ return true;
+}
+
+//=====================================================================
+//
+//
+void
+Base::serialize(std::ostream &os)
+{
+ // Serialize the PciDev base class
+ PciDev::serialize(os);
+
+ SERIALIZE_SCALAR(rxEnable);
+ SERIALIZE_SCALAR(txEnable);
+ SERIALIZE_SCALAR(cpuIntrEnable);
+
+ /*
+ * Keep track of pending interrupt status.
+ */
+ SERIALIZE_SCALAR(intrTick);
+ SERIALIZE_SCALAR(cpuPendingIntr);
+ Tick intrEventTick = 0;
+ if (intrEvent)
+ intrEventTick = intrEvent->when();
+ SERIALIZE_SCALAR(intrEventTick);
+}
+
+void
+Base::unserialize(Checkpoint *cp, const std::string &section)
+{
+ // Unserialize the PciDev base class
+ PciDev::unserialize(cp, section);
+
+ UNSERIALIZE_SCALAR(rxEnable);
+ UNSERIALIZE_SCALAR(txEnable);
+ UNSERIALIZE_SCALAR(cpuIntrEnable);
+
+ /*
+ * Keep track of pending interrupt status.
+ */
+ UNSERIALIZE_SCALAR(intrTick);
+ UNSERIALIZE_SCALAR(cpuPendingIntr);
+ Tick intrEventTick;
+ UNSERIALIZE_SCALAR(intrEventTick);
+ if (intrEventTick) {
+ intrEvent = new IntrEvent(this, true);
+ intrEvent->schedule(intrEventTick);
+ }
+}
+
+void
+Device::serialize(std::ostream &os)
+{
+ int count;
+
+ // Serialize the PciDev base class
+ Base::serialize(os);
+
+ if (rxState == rxCopy)
+ panic("can't serialize with an in flight dma request rxState=%s",
+ RxStateStrings[rxState]);
+
+ if (txState == txCopy)
+ panic("can't serialize with an in flight dma request txState=%s",
+ TxStateStrings[txState]);
+
+ /*
+ * Serialize the device registers
+ */
+ SERIALIZE_SCALAR(regs.Config);
+ SERIALIZE_SCALAR(regs.IntrStatus);
+ SERIALIZE_SCALAR(regs.IntrMask);
+ SERIALIZE_SCALAR(regs.RxMaxCopy);
+ SERIALIZE_SCALAR(regs.TxMaxCopy);
+ SERIALIZE_SCALAR(regs.RxMaxIntr);
+ SERIALIZE_SCALAR(regs.VirtualCount);
+ SERIALIZE_SCALAR(regs.RxData);
+ SERIALIZE_SCALAR(regs.RxDone);
+ SERIALIZE_SCALAR(regs.TxData);
+ SERIALIZE_SCALAR(regs.TxDone);
+
+ /*
+ * Serialize the virtual nic state
+ */
+ int virtualRegsSize = virtualRegs.size();
+ SERIALIZE_SCALAR(virtualRegsSize);
+ for (int i = 0; i < virtualRegsSize; ++i) {
+ VirtualReg *vnic = &virtualRegs[i];
+
+ std::string reg = csprintf("vnic%d", i);
+ paramOut(os, reg + ".RxData", vnic->RxData);
+ paramOut(os, reg + ".RxDone", vnic->RxDone);
+ paramOut(os, reg + ".TxData", vnic->TxData);
+ paramOut(os, reg + ".TxDone", vnic->TxDone);
+
+ bool rxPacketExists = vnic->rxPacket != rxFifo.end();
+ paramOut(os, reg + ".rxPacketExists", rxPacketExists);
+ if (rxPacketExists) {
+ int rxPacket = 0;
+ PacketFifo::iterator i = rxFifo.begin();
+ while (i != vnic->rxPacket) {
+ assert(i != rxFifo.end());
+ ++i;
+ ++rxPacket;
+ }
+
+ paramOut(os, reg + ".rxPacket", rxPacket);
+ paramOut(os, reg + ".rxPacketOffset", vnic->rxPacketOffset);
+ paramOut(os, reg + ".rxPacketBytes", vnic->rxPacketBytes);
+ }
+ paramOut(os, reg + ".rxDoneData", vnic->rxDoneData);
+ }
+
+ int rxFifoPtr = rxFifo.countPacketsBefore(this->rxFifoPtr);
+ SERIALIZE_SCALAR(rxFifoPtr);
+
+ SERIALIZE_SCALAR(rxActive);
+
+ VirtualList::iterator i, end;
+ for (count = 0, i = rxList.begin(), end = rxList.end(); i != end; ++i)
+ paramOut(os, csprintf("rxList%d", count++), *i);
+ int rxListSize = count;
+ SERIALIZE_SCALAR(rxListSize);
+
+ for (count = 0, i = rxBusy.begin(), end = rxBusy.end(); i != end; ++i)
+ paramOut(os, csprintf("rxBusy%d", count++), *i);
+ int rxBusySize = count;
+ SERIALIZE_SCALAR(rxBusySize);
+
+ for (count = 0, i = txList.begin(), end = txList.end(); i != end; ++i)
+ paramOut(os, csprintf("txList%d", count++), *i);
+ int txListSize = count;
+ SERIALIZE_SCALAR(txListSize);
+
+ /*
+ * Serialize rx state machine
+ */
+ int rxState = this->rxState;
+ SERIALIZE_SCALAR(rxState);
+ SERIALIZE_SCALAR(rxEmpty);
+ SERIALIZE_SCALAR(rxLow);
+ rxFifo.serialize("rxFifo", os);
+
+ /*
+ * Serialize tx state machine
+ */
+ int txState = this->txState;
+ SERIALIZE_SCALAR(txState);
+ SERIALIZE_SCALAR(txFull);
+ txFifo.serialize("txFifo", os);
+ bool txPacketExists = txPacket;
+ SERIALIZE_SCALAR(txPacketExists);
+ if (txPacketExists) {
+ txPacket->serialize("txPacket", os);
+ SERIALIZE_SCALAR(txPacketOffset);
+ SERIALIZE_SCALAR(txPacketBytes);
+ }
+
+ /*
+ * If there's a pending transmit, store the time so we can
+ * reschedule it later
+ */
+ Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0;
+ SERIALIZE_SCALAR(transmitTick);
+}
+
+void
+Device::unserialize(Checkpoint *cp, const std::string &section)
+{
+ // Unserialize the PciDev base class
+ Base::unserialize(cp, section);
+
+ /*
+ * Unserialize the device registers
+ */
+ UNSERIALIZE_SCALAR(regs.Config);
+ UNSERIALIZE_SCALAR(regs.IntrStatus);
+ UNSERIALIZE_SCALAR(regs.IntrMask);
+ UNSERIALIZE_SCALAR(regs.RxMaxCopy);
+ UNSERIALIZE_SCALAR(regs.TxMaxCopy);
+ UNSERIALIZE_SCALAR(regs.RxMaxIntr);
+ UNSERIALIZE_SCALAR(regs.VirtualCount);
+ UNSERIALIZE_SCALAR(regs.RxData);
+ UNSERIALIZE_SCALAR(regs.RxDone);
+ UNSERIALIZE_SCALAR(regs.TxData);
+ UNSERIALIZE_SCALAR(regs.TxDone);
+
+ UNSERIALIZE_SCALAR(rxActive);
+
+ int rxListSize;
+ UNSERIALIZE_SCALAR(rxListSize);
+ rxList.clear();
+ for (int i = 0; i < rxListSize; ++i) {
+ int value;
+ paramIn(cp, section, csprintf("rxList%d", i), value);
+ rxList.push_back(value);
+ }
+
+ int rxBusySize;
+ UNSERIALIZE_SCALAR(rxBusySize);
+ rxBusy.clear();
+ for (int i = 0; i < rxBusySize; ++i) {
+ int value;
+ paramIn(cp, section, csprintf("rxBusy%d", i), value);
+ rxBusy.push_back(value);
+ }
+
+ int txListSize;
+ UNSERIALIZE_SCALAR(txListSize);
+ txList.clear();
+ for (int i = 0; i < txListSize; ++i) {
+ int value;
+ paramIn(cp, section, csprintf("txList%d", i), value);
+ txList.push_back(value);
+ }
+
+ /*
+ * Unserialize rx state machine
+ */
+ int rxState;
+ UNSERIALIZE_SCALAR(rxState);
+ UNSERIALIZE_SCALAR(rxEmpty);
+ UNSERIALIZE_SCALAR(rxLow);
+ this->rxState = (RxState) rxState;
+ rxFifo.unserialize("rxFifo", cp, section);
+
+ int rxFifoPtr;
+ UNSERIALIZE_SCALAR(rxFifoPtr);
+ this->rxFifoPtr = rxFifo.begin();
+ for (int i = 0; i < rxFifoPtr; ++i)
+ ++this->rxFifoPtr;
+
+ /*
+ * Unserialize tx state machine
+ */
+ int txState;
+ UNSERIALIZE_SCALAR(txState);
+ UNSERIALIZE_SCALAR(txFull);
+ this->txState = (TxState) txState;
+ txFifo.unserialize("txFifo", cp, section);
+ bool txPacketExists;
+ UNSERIALIZE_SCALAR(txPacketExists);
+ txPacket = 0;
+ if (txPacketExists) {
+ txPacket = new EthPacketData(16384);
+ txPacket->unserialize("txPacket", cp, section);
+ UNSERIALIZE_SCALAR(txPacketOffset);
+ UNSERIALIZE_SCALAR(txPacketBytes);
+ }
+
+ /*
+ * unserialize the virtual nic registers/state
+ *
+ * this must be done after the unserialization of the rxFifo
+ * because the packet iterators depend on the fifo being populated
+ */
+ int virtualRegsSize;
+ UNSERIALIZE_SCALAR(virtualRegsSize);
+ virtualRegs.clear();
+ virtualRegs.resize(virtualRegsSize);
+ for (int i = 0; i < virtualRegsSize; ++i) {
+ VirtualReg *vnic = &virtualRegs[i];
+ std::string reg = csprintf("vnic%d", i);
+
+ paramIn(cp, section, reg + ".RxData", vnic->RxData);
+ paramIn(cp, section, reg + ".RxDone", vnic->RxDone);
+ paramIn(cp, section, reg + ".TxData", vnic->TxData);
+ paramIn(cp, section, reg + ".TxDone", vnic->TxDone);
+
+ vnic->rxUnique = rxUnique++;
+ vnic->txUnique = txUnique++;
+
+ bool rxPacketExists;
+ paramIn(cp, section, reg + ".rxPacketExists", rxPacketExists);
+ if (rxPacketExists) {
+ int rxPacket;
+ paramIn(cp, section, reg + ".rxPacket", rxPacket);
+ vnic->rxPacket = rxFifo.begin();
+ while (rxPacket--)
+ ++vnic->rxPacket;
+
+ paramIn(cp, section, reg + ".rxPacketOffset",
+ vnic->rxPacketOffset);
+ paramIn(cp, section, reg + ".rxPacketBytes", vnic->rxPacketBytes);
+ } else {
+ vnic->rxPacket = rxFifo.end();
+ }
+ paramIn(cp, section, reg + ".rxDoneData", vnic->rxDoneData);
+ }
+
+ /*
+ * If there's a pending transmit, reschedule it now
+ */
+ Tick transmitTick;
+ UNSERIALIZE_SCALAR(transmitTick);
+ if (transmitTick)
+ txEvent.schedule(curTick + transmitTick);
+
+ pioPort->sendStatusChange(Port::RangeChange);
+
+}
+
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(Interface)
+
+ SimObjectParam<EtherInt *> peer;
+ SimObjectParam<Device *> device;
+
+END_DECLARE_SIM_OBJECT_PARAMS(Interface)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(Interface)
+
+ INIT_PARAM_DFLT(peer, "peer interface", NULL),
+ INIT_PARAM(device, "Ethernet device of this interface")
+
+END_INIT_SIM_OBJECT_PARAMS(Interface)
+
+CREATE_SIM_OBJECT(Interface)
+{
+ Interface *dev_int = new Interface(getInstanceName(), device);
+
+ EtherInt *p = (EtherInt *)peer;
+ if (p) {
+ dev_int->setPeer(p);
+ p->setPeer(dev_int);
+ }
+
+ return dev_int;
+}
+
+REGISTER_SIM_OBJECT("SinicInt", Interface)
+
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(Device)
+
+
+ SimObjectParam<System *> system;
+ SimObjectParam<Platform *> platform;
+ SimObjectParam<PciConfigAll *> configspace;
+ SimObjectParam<PciConfigData *> configdata;
+ Param<uint32_t> pci_bus;
+ Param<uint32_t> pci_dev;
+ Param<uint32_t> pci_func;
+ Param<Tick> pio_latency;
+ Param<Tick> intr_delay;
+
+ Param<Tick> clock;
+ Param<Tick> dma_read_delay;
+ Param<Tick> dma_read_factor;
+ Param<Tick> dma_write_delay;
+ Param<Tick> dma_write_factor;
+
+ Param<Tick> rx_delay;
+ Param<Tick> tx_delay;
+ Param<uint32_t> rx_max_copy;
+ Param<uint32_t> tx_max_copy;
+ Param<uint32_t> rx_max_intr;
+ Param<uint32_t> rx_fifo_size;
+ Param<uint32_t> tx_fifo_size;
+ Param<uint32_t> rx_fifo_threshold;
+ Param<uint32_t> rx_fifo_low_mark;
+ Param<uint32_t> tx_fifo_high_mark;
+ Param<uint32_t> tx_fifo_threshold;
+
+ Param<bool> rx_filter;
+ Param<std::string> hardware_address;
+ Param<bool> rx_thread;
+ Param<bool> tx_thread;
+ Param<bool> rss;
+ Param<uint32_t> virtual_count;
+ Param<bool> zero_copy;
+ Param<bool> delay_copy;
+ Param<bool> virtual_addr;
+
+END_DECLARE_SIM_OBJECT_PARAMS(Device)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(Device)
+
+
+ INIT_PARAM(system, "System pointer"),
+ INIT_PARAM(platform, "Platform pointer"),
+ INIT_PARAM(configspace, "PCI Configspace"),
+ INIT_PARAM(configdata, "PCI Config data"),
+ INIT_PARAM(pci_bus, "PCI bus ID"),
+ INIT_PARAM(pci_dev, "PCI device number"),
+ INIT_PARAM(pci_func, "PCI function code"),
+ INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
+ INIT_PARAM(intr_delay, "Interrupt Delay"),
+ INIT_PARAM(clock, "State machine cycle time"),
+
+ INIT_PARAM(dma_read_delay, "fixed delay for dma reads"),
+ INIT_PARAM(dma_read_factor, "multiplier for dma reads"),
+ INIT_PARAM(dma_write_delay, "fixed delay for dma writes"),
+ INIT_PARAM(dma_write_factor, "multiplier for dma writes"),
+
+ INIT_PARAM(rx_delay, "Receive Delay"),
+ INIT_PARAM(tx_delay, "Transmit Delay"),
+ INIT_PARAM(rx_max_copy, "rx max copy"),
+ INIT_PARAM(tx_max_copy, "rx max copy"),
+ INIT_PARAM(rx_max_intr, "rx max intr"),
+ INIT_PARAM(rx_fifo_size, "max size in bytes of rxFifo"),
+ INIT_PARAM(tx_fifo_size, "max size in bytes of txFifo"),
+ INIT_PARAM(rx_fifo_threshold, "max size in bytes of rxFifo"),
+ INIT_PARAM(rx_fifo_low_mark, "max size in bytes of rxFifo"),
+ INIT_PARAM(tx_fifo_high_mark, "max size in bytes of txFifo"),
+ INIT_PARAM(tx_fifo_threshold, "max size in bytes of txFifo"),
+
+ INIT_PARAM(rx_filter, "Enable Receive Filter"),
+ INIT_PARAM(hardware_address, "Ethernet Hardware Address"),
+ INIT_PARAM(rx_thread, ""),
+ INIT_PARAM(tx_thread, ""),
+ INIT_PARAM(rss, ""),
+ INIT_PARAM(virtual_count, ""),
+ INIT_PARAM(zero_copy, ""),
+ INIT_PARAM(delay_copy, ""),
+ INIT_PARAM(virtual_addr, "")
+
+END_INIT_SIM_OBJECT_PARAMS(Device)
+
+
+CREATE_SIM_OBJECT(Device)
+{
+ Device::Params *params = new Device::Params;
+ params->name = getInstanceName();
+ params->platform = platform;
+ params->system = system;
+ params->configSpace = configspace;
+ params->configData = configdata;
+ params->busNum = pci_bus;
+ params->deviceNum = pci_dev;
+ params->functionNum = pci_func;
+ params->pio_delay = pio_latency;
+ params->intr_delay = intr_delay;
+ params->clock = clock;
+
+ params->dma_read_delay = dma_read_delay;
+ params->dma_read_factor = dma_read_factor;
+ params->dma_write_delay = dma_write_delay;
+ params->dma_write_factor = dma_write_factor;
+
+ params->tx_delay = tx_delay;
+ params->rx_delay = rx_delay;
+ params->rx_max_copy = rx_max_copy;
+ params->tx_max_copy = tx_max_copy;
+ params->rx_max_intr = rx_max_intr;
+ params->rx_fifo_size = rx_fifo_size;
+ params->tx_fifo_size = tx_fifo_size;
+ params->rx_fifo_threshold = rx_fifo_threshold;
+ params->rx_fifo_low_mark = rx_fifo_low_mark;
+ params->tx_fifo_high_mark = tx_fifo_high_mark;
+ params->tx_fifo_threshold = tx_fifo_threshold;
+
+ params->rx_filter = rx_filter;
+ params->eaddr = hardware_address;
+ params->rx_thread = rx_thread;
+ params->tx_thread = tx_thread;
+ params->rss = rss;
+ params->virtual_count = virtual_count;
+ params->zero_copy = zero_copy;
+ params->delay_copy = delay_copy;
+ params->virtual_addr = virtual_addr;
+
+ return new Device(params);
+}
+
+REGISTER_SIM_OBJECT("Sinic", Device)
+
+/* namespace Sinic */ }
diff --git a/src/dev/sinic.hh b/src/dev/sinic.hh
new file mode 100644
index 000000000..1bb4c77e0
--- /dev/null
+++ b/src/dev/sinic.hh
@@ -0,0 +1,371 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __DEV_SINIC_HH__
+#define __DEV_SINIC_HH__
+
+#include "base/inet.hh"
+#include "base/statistics.hh"
+#include "dev/etherint.hh"
+#include "dev/etherpkt.hh"
+#include "dev/io_device.hh"
+#include "dev/pcidev.hh"
+#include "dev/pktfifo.hh"
+#include "dev/sinicreg.hh"
+#include "sim/eventq.hh"
+
+namespace Sinic {
+
+class Interface;
+class Base : public PciDev
+{
+ protected:
+ bool rxEnable;
+ bool txEnable;
+ Tick clock;
+ inline Tick cycles(int numCycles) const { return numCycles * clock; }
+
+ protected:
+ Tick intrDelay;
+ Tick intrTick;
+ bool cpuIntrEnable;
+ bool cpuPendingIntr;
+ void cpuIntrPost(Tick when);
+ void cpuInterrupt();
+ void cpuIntrClear();
+
+ typedef EventWrapper<Base, &Base::cpuInterrupt> IntrEvent;
+ friend void IntrEvent::process();
+ IntrEvent *intrEvent;
+ Interface *interface;
+
+ bool cpuIntrPending() const;
+ void cpuIntrAck() { cpuIntrClear(); }
+
+/**
+ * Serialization stuff
+ */
+ public:
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+
+/**
+ * Construction/Destruction/Parameters
+ */
+ public:
+ struct Params : public PciDev::Params
+ {
+ Tick clock;
+ Tick intr_delay;
+ };
+
+ Base(Params *p);
+};
+
+class Device : public Base
+{
+ protected:
+ /** Receive State Machine States */
+ enum RxState {
+ rxIdle,
+ rxFifoBlock,
+ rxBeginCopy,
+ rxCopy,
+ rxCopyDone
+ };
+
+ /** Transmit State Machine states */
+ enum TxState {
+ txIdle,
+ txFifoBlock,
+ txBeginCopy,
+ txCopy,
+ txCopyDone
+ };
+
+ /** device register file */
+ struct {
+ uint32_t Config; // 0x00
+ uint32_t Command; // 0x04
+ uint32_t IntrStatus; // 0x08
+ uint32_t IntrMask; // 0x0c
+ uint32_t RxMaxCopy; // 0x10
+ uint32_t TxMaxCopy; // 0x14
+ uint32_t RxMaxIntr; // 0x18
+ uint32_t VirtualCount; // 0x1c
+ uint32_t RxFifoSize; // 0x20
+ uint32_t TxFifoSize; // 0x24
+ uint32_t RxFifoMark; // 0x28
+ uint32_t TxFifoMark; // 0x2c
+ uint64_t RxData; // 0x30
+ uint64_t RxDone; // 0x38
+ uint64_t RxWait; // 0x40
+ uint64_t TxData; // 0x48
+ uint64_t TxDone; // 0x50
+ uint64_t TxWait; // 0x58
+ uint64_t HwAddr; // 0x60
+ } regs;
+
+ struct VirtualReg {
+ uint64_t RxData;
+ uint64_t RxDone;
+ uint64_t TxData;
+ uint64_t TxDone;
+
+ PacketFifo::iterator rxPacket;
+ int rxPacketOffset;
+ int rxPacketBytes;
+ uint64_t rxDoneData;
+
+ Counter rxUnique;
+ Counter txUnique;
+
+ VirtualReg()
+ : RxData(0), RxDone(0), TxData(0), TxDone(0),
+ rxPacketOffset(0), rxPacketBytes(0), rxDoneData(0)
+ { }
+ };
+ typedef std::vector<VirtualReg> VirtualRegs;
+ typedef std::list<int> VirtualList;
+ Counter rxUnique;
+ Counter txUnique;
+ VirtualRegs virtualRegs;
+ VirtualList rxList;
+ VirtualList rxBusy;
+ int rxActive;
+ VirtualList txList;
+
+ uint8_t &regData8(Addr daddr) { return *((uint8_t *)&regs + daddr); }
+ uint32_t &regData32(Addr daddr) { return *(uint32_t *)&regData8(daddr); }
+ uint64_t &regData64(Addr daddr) { return *(uint64_t *)&regData8(daddr); }
+
+ protected:
+ RxState rxState;
+ PacketFifo rxFifo;
+ PacketFifo::iterator rxFifoPtr;
+ bool rxEmpty;
+ bool rxLow;
+ Addr rxDmaAddr;
+ uint8_t *rxDmaData;
+ int rxDmaLen;
+
+ TxState txState;
+ PacketFifo txFifo;
+ bool txFull;
+ EthPacketPtr txPacket;
+ int txPacketOffset;
+ int txPacketBytes;
+ Addr txDmaAddr;
+ uint8_t *txDmaData;
+ int txDmaLen;
+
+ protected:
+ void reset();
+
+ void rxKick();
+ Tick rxKickTick;
+ typedef EventWrapper<Device, &Device::rxKick> RxKickEvent;
+ friend void RxKickEvent::process();
+
+ void txKick();
+ Tick txKickTick;
+ typedef EventWrapper<Device, &Device::txKick> TxKickEvent;
+ friend void TxKickEvent::process();
+
+ /**
+ * Retransmit event
+ */
+ void transmit();
+ void txEventTransmit()
+ {
+ transmit();
+ if (txState == txFifoBlock)
+ txKick();
+ }
+ typedef EventWrapper<Device, &Device::txEventTransmit> TxEvent;
+ friend void TxEvent::process();
+ TxEvent txEvent;
+
+ void txDump() const;
+ void rxDump() const;
+
+ /**
+ * receive address filter
+ */
+ bool rxFilter(const EthPacketPtr &packet);
+
+/**
+ * device configuration
+ */
+ void changeConfig(uint32_t newconfig);
+ void command(uint32_t command);
+
+/**
+ * device ethernet interface
+ */
+ public:
+ bool recvPacket(EthPacketPtr packet);
+ void transferDone();
+ void setInterface(Interface *i) { assert(!interface); interface = i; }
+
+/**
+ * DMA parameters
+ */
+ protected:
+ void rxDmaDone();
+ friend class EventWrapper<Device, &Device::rxDmaDone>;
+ EventWrapper<Device, &Device::rxDmaDone> rxDmaEvent;
+
+ void txDmaDone();
+ friend class EventWrapper<Device, &Device::txDmaDone>;
+ EventWrapper<Device, &Device::txDmaDone> txDmaEvent;
+
+ Tick dmaReadDelay;
+ Tick dmaReadFactor;
+ Tick dmaWriteDelay;
+ Tick dmaWriteFactor;
+
+/**
+ * Interrupt management
+ */
+ protected:
+ void devIntrPost(uint32_t interrupts);
+ void devIntrClear(uint32_t interrupts = Regs::Intr_All);
+ void devIntrChangeMask(uint32_t newmask);
+
+/**
+ * Memory Interface
+ */
+ public:
+ virtual Tick read(Packet *pkt);
+ virtual Tick write(Packet *pkt);
+
+ void prepareIO(int cpu, int index);
+ void prepareRead(int cpu, int index);
+ void prepareWrite(int cpu, int index);
+ // Fault iprRead(Addr daddr, int cpu, uint64_t &result);
+
+/**
+ * Statistics
+ */
+ private:
+ Stats::Scalar<> rxBytes;
+ Stats::Formula rxBandwidth;
+ Stats::Scalar<> rxPackets;
+ Stats::Formula rxPacketRate;
+ Stats::Scalar<> rxIpPackets;
+ Stats::Scalar<> rxTcpPackets;
+ Stats::Scalar<> rxUdpPackets;
+ Stats::Scalar<> rxIpChecksums;
+ Stats::Scalar<> rxTcpChecksums;
+ Stats::Scalar<> rxUdpChecksums;
+
+ Stats::Scalar<> txBytes;
+ Stats::Formula txBandwidth;
+ Stats::Formula totBandwidth;
+ Stats::Formula totPackets;
+ Stats::Formula totBytes;
+ Stats::Formula totPacketRate;
+ Stats::Scalar<> txPackets;
+ Stats::Formula txPacketRate;
+ Stats::Scalar<> txIpPackets;
+ Stats::Scalar<> txTcpPackets;
+ Stats::Scalar<> txUdpPackets;
+ Stats::Scalar<> txIpChecksums;
+ Stats::Scalar<> txTcpChecksums;
+ Stats::Scalar<> txUdpChecksums;
+
+ public:
+ virtual void regStats();
+
+/**
+ * Serialization stuff
+ */
+ public:
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+
+/**
+ * Construction/Destruction/Parameters
+ */
+ public:
+ struct Params : public Base::Params
+ {
+ Tick tx_delay;
+ Tick rx_delay;
+ bool rx_filter;
+ Net::EthAddr eaddr;
+ uint32_t rx_max_copy;
+ uint32_t tx_max_copy;
+ uint32_t rx_max_intr;
+ uint32_t rx_fifo_size;
+ uint32_t tx_fifo_size;
+ uint32_t rx_fifo_threshold;
+ uint32_t rx_fifo_low_mark;
+ uint32_t tx_fifo_high_mark;
+ uint32_t tx_fifo_threshold;
+ Tick dma_read_delay;
+ Tick dma_read_factor;
+ Tick dma_write_delay;
+ Tick dma_write_factor;
+ bool rx_thread;
+ bool tx_thread;
+ bool rss;
+ uint32_t virtual_count;
+ bool zero_copy;
+ bool delay_copy;
+ bool virtual_addr;
+ };
+
+ protected:
+ const Params *params() const { return (const Params *)_params; }
+
+ public:
+ Device(Params *params);
+ ~Device();
+};
+
+/*
+ * Ethernet Interface for an Ethernet Device
+ */
+class Interface : public EtherInt
+{
+ private:
+ Device *dev;
+
+ public:
+ Interface(const std::string &name, Device *d)
+ : EtherInt(name), dev(d) { dev->setInterface(this); }
+
+ virtual bool recvPacket(EthPacketPtr pkt) { return dev->recvPacket(pkt); }
+ virtual void sendDone() { dev->transferDone(); }
+};
+
+/* namespace Sinic */ }
+
+#endif // __DEV_SINIC_HH__
diff --git a/src/dev/sinicreg.hh b/src/dev/sinicreg.hh
new file mode 100644
index 000000000..d41eb5b16
--- /dev/null
+++ b/src/dev/sinicreg.hh
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __DEV_SINICREG_HH__
+#define __DEV_SINICREG_HH__
+
+#define __SINIC_REG32(NAME, VAL) static const uint32_t NAME = (VAL)
+#define __SINIC_REG64(NAME, VAL) static const uint64_t NAME = (VAL)
+
+#define __SINIC_VAL32(NAME, OFFSET, WIDTH) \
+ static const uint32_t NAME##_width = WIDTH; \
+ static const uint32_t NAME##_offset = OFFSET; \
+ static const uint32_t NAME##_mask = (1 << WIDTH) - 1; \
+ static const uint32_t NAME = ((1 << WIDTH) - 1) << OFFSET; \
+ static inline uint32_t get_##NAME(uint32_t reg) \
+ { return (reg & NAME) >> OFFSET; } \
+ static inline uint32_t set_##NAME(uint32_t reg, uint32_t val) \
+ { return (reg & ~NAME) | ((val << OFFSET) & NAME); }
+
+#define __SINIC_VAL64(NAME, OFFSET, WIDTH) \
+ static const uint64_t NAME##_width = WIDTH; \
+ static const uint64_t NAME##_offset = OFFSET; \
+ static const uint64_t NAME##_mask = (ULL(1) << WIDTH) - 1; \
+ static const uint64_t NAME = ((ULL(1) << WIDTH) - 1) << OFFSET; \
+ static inline uint64_t get_##NAME(uint64_t reg) \
+ { return (reg & NAME) >> OFFSET; } \
+ static inline uint64_t set_##NAME(uint64_t reg, uint64_t val) \
+ { return (reg & ~NAME) | ((val << OFFSET) & NAME); }
+
+namespace Sinic {
+namespace Regs {
+
+static const int VirtualShift = 8;
+static const int VirtualMask = 0xff;
+
+// Registers
+__SINIC_REG32(Config, 0x00); // 32: configuration register
+__SINIC_REG32(Command, 0x04); // 32: command register
+__SINIC_REG32(IntrStatus, 0x08); // 32: interrupt status
+__SINIC_REG32(IntrMask, 0x0c); // 32: interrupt mask
+__SINIC_REG32(RxMaxCopy, 0x10); // 32: max bytes per rx copy
+__SINIC_REG32(TxMaxCopy, 0x14); // 32: max bytes per tx copy
+__SINIC_REG32(RxMaxIntr, 0x18); // 32: max receives per interrupt
+__SINIC_REG32(VirtualCount, 0x1c); // 32: number of virutal NICs
+__SINIC_REG32(RxFifoSize, 0x20); // 32: rx fifo capacity in bytes
+__SINIC_REG32(TxFifoSize, 0x24); // 32: tx fifo capacity in bytes
+__SINIC_REG32(RxFifoMark, 0x28); // 32: rx fifo high watermark
+__SINIC_REG32(TxFifoMark, 0x2c); // 32: tx fifo low watermark
+__SINIC_REG32(RxData, 0x30); // 64: receive data
+__SINIC_REG32(RxDone, 0x38); // 64: receive done
+__SINIC_REG32(RxWait, 0x40); // 64: receive done (busy wait)
+__SINIC_REG32(TxData, 0x48); // 64: transmit data
+__SINIC_REG32(TxDone, 0x50); // 64: transmit done
+__SINIC_REG32(TxWait, 0x58); // 64: transmit done (busy wait)
+__SINIC_REG32(HwAddr, 0x60); // 64: mac address
+__SINIC_REG32(Size, 0x68); // register addres space size
+
+// Config register bits
+__SINIC_VAL32(Config_ZeroCopy, 12, 1); // enable zero copy
+__SINIC_VAL32(Config_DelayCopy,11, 1); // enable delayed copy
+__SINIC_VAL32(Config_RSS, 10, 1); // enable receive side scaling
+__SINIC_VAL32(Config_RxThread, 9, 1); // enable receive threads
+__SINIC_VAL32(Config_TxThread, 8, 1); // enable transmit thread
+__SINIC_VAL32(Config_Filter, 7, 1); // enable receive filter
+__SINIC_VAL32(Config_Vlan, 6, 1); // enable vlan tagging
+__SINIC_VAL32(Config_Vaddr, 5, 1); // enable virtual addressing
+__SINIC_VAL32(Config_Desc, 4, 1); // enable tx/rx descriptors
+__SINIC_VAL32(Config_Poll, 3, 1); // enable polling
+__SINIC_VAL32(Config_IntEn, 2, 1); // enable interrupts
+__SINIC_VAL32(Config_TxEn, 1, 1); // enable transmit
+__SINIC_VAL32(Config_RxEn, 0, 1); // enable receive
+
+// Command register bits
+__SINIC_VAL32(Command_Intr, 1, 1); // software interrupt
+__SINIC_VAL32(Command_Reset, 0, 1); // reset chip
+
+// Interrupt register bits
+__SINIC_VAL32(Intr_Soft, 8, 1); // software interrupt
+__SINIC_VAL32(Intr_TxLow, 7, 1); // tx fifo dropped below watermark
+__SINIC_VAL32(Intr_TxFull, 6, 1); // tx fifo full
+__SINIC_VAL32(Intr_TxDMA, 5, 1); // tx dma completed w/ interrupt
+__SINIC_VAL32(Intr_TxPacket, 4, 1); // packet transmitted
+__SINIC_VAL32(Intr_RxHigh, 3, 1); // rx fifo above high watermark
+__SINIC_VAL32(Intr_RxEmpty, 2, 1); // rx fifo empty
+__SINIC_VAL32(Intr_RxDMA, 1, 1); // rx dma completed w/ interrupt
+__SINIC_VAL32(Intr_RxPacket, 0, 1); // packet received
+__SINIC_REG32(Intr_All, 0x01ff); // all valid interrupts
+__SINIC_REG32(Intr_NoDelay, 0x01cc); // interrupts that aren't coalesced
+__SINIC_REG32(Intr_Res, ~0x01ff); // reserved interrupt bits
+
+// RX Data Description
+__SINIC_VAL64(RxData_Vaddr, 60, 1); // Addr is virtual
+__SINIC_VAL64(RxData_Len, 40, 20); // 0 - 256k
+__SINIC_VAL64(RxData_Addr, 0, 40); // Address 1TB
+
+// TX Data Description
+__SINIC_VAL64(TxData_More, 63, 1); // Packet not complete (will dma more)
+__SINIC_VAL64(TxData_Checksum, 62, 1); // do checksum
+__SINIC_VAL64(TxData_Vaddr, 60, 1); // Addr is virtual
+__SINIC_VAL64(TxData_Len, 40, 20); // 0 - 256k
+__SINIC_VAL64(TxData_Addr, 0, 40); // Address 1TB
+
+// RX Done/Busy Information
+__SINIC_VAL64(RxDone_Packets, 32, 16); // number of packets in rx fifo
+__SINIC_VAL64(RxDone_Busy, 31, 1); // receive dma busy copying
+__SINIC_VAL64(RxDone_Complete, 30, 1); // valid data (packet complete)
+__SINIC_VAL64(RxDone_More, 29, 1); // Packet has more data (dma again)
+__SINIC_VAL64(RxDone_Empty, 28, 1); // rx fifo is empty
+__SINIC_VAL64(RxDone_High, 27, 1); // rx fifo is above the watermark
+__SINIC_VAL64(RxDone_NotHigh, 26, 1); // rxfifo never hit the high watermark
+__SINIC_VAL64(RxDone_TcpError, 25, 1); // TCP packet error (bad checksum)
+__SINIC_VAL64(RxDone_UdpError, 24, 1); // UDP packet error (bad checksum)
+__SINIC_VAL64(RxDone_IpError, 23, 1); // IP packet error (bad checksum)
+__SINIC_VAL64(RxDone_TcpPacket, 22, 1); // this is a TCP packet
+__SINIC_VAL64(RxDone_UdpPacket, 21, 1); // this is a UDP packet
+__SINIC_VAL64(RxDone_IpPacket, 20, 1); // this is an IP packet
+__SINIC_VAL64(RxDone_CopyLen, 0, 20); // up to 256k
+
+// TX Done/Busy Information
+__SINIC_VAL64(TxDone_Packets, 32, 16); // number of packets in tx fifo
+__SINIC_VAL64(TxDone_Busy, 31, 1); // transmit dma busy copying
+__SINIC_VAL64(TxDone_Complete, 30, 1); // valid data (packet complete)
+__SINIC_VAL64(TxDone_Full, 29, 1); // tx fifo is full
+__SINIC_VAL64(TxDone_Low, 28, 1); // tx fifo is below the watermark
+__SINIC_VAL64(TxDone_Res0, 27, 1); // reserved
+__SINIC_VAL64(TxDone_Res1, 26, 1); // reserved
+__SINIC_VAL64(TxDone_Res2, 25, 1); // reserved
+__SINIC_VAL64(TxDone_Res3, 24, 1); // reserved
+__SINIC_VAL64(TxDone_Res4, 23, 1); // reserved
+__SINIC_VAL64(TxDone_Res5, 22, 1); // reserved
+__SINIC_VAL64(TxDone_Res6, 21, 1); // reserved
+__SINIC_VAL64(TxDone_Res7, 20, 1); // reserved
+__SINIC_VAL64(TxDone_CopyLen, 0, 20); // up to 256k
+
+struct Info
+{
+ uint8_t size;
+ bool read;
+ bool write;
+ const char *name;
+};
+
+/* namespace Regs */ }
+
+inline const Regs::Info&
+regInfo(Addr daddr)
+{
+ static Regs::Info invalid = { 0, false, false, "invalid" };
+ static Regs::Info info [] = {
+ { 4, true, true, "Config" },
+ { 4, false, true, "Command" },
+ { 4, true, true, "IntrStatus" },
+ { 4, true, true, "IntrMask" },
+ { 4, true, false, "RxMaxCopy" },
+ { 4, true, false, "TxMaxCopy" },
+ { 4, true, false, "RxMaxIntr" },
+ { 4, true, false, "VirtualCount" },
+ { 4, true, false, "RxFifoSize" },
+ { 4, true, false, "TxFifoSize" },
+ { 4, true, false, "RxFifoMark" },
+ { 4, true, false, "TxFifoMark" },
+ { 8, true, true, "RxData" },
+ invalid,
+ { 8, true, false, "RxDone" },
+ invalid,
+ { 8, true, false, "RxWait" },
+ invalid,
+ { 8, true, true, "TxData" },
+ invalid,
+ { 8, true, false, "TxDone" },
+ invalid,
+ { 8, true, false, "TxWait" },
+ invalid,
+ { 8, true, false, "HwAddr" },
+ invalid,
+ };
+
+ return info[daddr / 4];
+}
+
+inline bool
+regValid(Addr daddr)
+{
+ if (daddr > Regs::Size)
+ return false;
+
+ if (regInfo(daddr).size == 0)
+ return false;
+
+ return true;
+}
+
+/* namespace Sinic */ }
+
+#endif // __DEV_SINICREG_HH__
diff --git a/src/dev/tsunami.cc b/src/dev/tsunami.cc
new file mode 100644
index 000000000..ed011531d
--- /dev/null
+++ b/src/dev/tsunami.cc
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * Implementation of Tsunami platform.
+ */
+
+#include <deque>
+#include <string>
+#include <vector>
+
+#include "cpu/intr_control.hh"
+#include "dev/simconsole.hh"
+#include "dev/tsunami_cchip.hh"
+#include "dev/tsunami_pchip.hh"
+#include "dev/tsunami_io.hh"
+#include "dev/tsunami.hh"
+#include "sim/builder.hh"
+#include "sim/system.hh"
+
+using namespace std;
+//Should this be AlphaISA?
+using namespace TheISA;
+
+Tsunami::Tsunami(const string &name, System *s, IntrControl *ic)
+ : Platform(name, ic), system(s)
+{
+ // set the back pointer from the system to myself
+ system->platform = this;
+
+ for (int i = 0; i < Tsunami::Max_CPUs; i++)
+ intr_sum_type[i] = 0;
+}
+
+Tick
+Tsunami::intrFrequency()
+{
+ return io->frequency();
+}
+
+void
+Tsunami::postConsoleInt()
+{
+ io->postPIC(0x10);
+}
+
+void
+Tsunami::clearConsoleInt()
+{
+ io->clearPIC(0x10);
+}
+
+void
+Tsunami::postPciInt(int line)
+{
+ cchip->postDRIR(line);
+}
+
+void
+Tsunami::clearPciInt(int line)
+{
+ cchip->clearDRIR(line);
+}
+
+Addr
+Tsunami::pciToDma(Addr pciAddr) const
+{
+ return pchip->translatePciToDma(pciAddr);
+}
+
+void
+Tsunami::serialize(std::ostream &os)
+{
+ SERIALIZE_ARRAY(intr_sum_type, Tsunami::Max_CPUs);
+}
+
+void
+Tsunami::unserialize(Checkpoint *cp, const std::string &section)
+{
+ UNSERIALIZE_ARRAY(intr_sum_type, Tsunami::Max_CPUs);
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(Tsunami)
+
+ SimObjectParam<System *> system;
+ SimObjectParam<IntrControl *> intrctrl;
+
+END_DECLARE_SIM_OBJECT_PARAMS(Tsunami)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(Tsunami)
+
+ INIT_PARAM(system, "system"),
+ INIT_PARAM(intrctrl, "interrupt controller")
+
+END_INIT_SIM_OBJECT_PARAMS(Tsunami)
+
+CREATE_SIM_OBJECT(Tsunami)
+{
+ return new Tsunami(getInstanceName(), system, intrctrl);
+}
+
+REGISTER_SIM_OBJECT("Tsunami", Tsunami)
diff --git a/src/dev/tsunami.hh b/src/dev/tsunami.hh
new file mode 100644
index 000000000..668c82674
--- /dev/null
+++ b/src/dev/tsunami.hh
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * Declaration of top level class for the Tsunami chipset. This class just
+ * retains pointers to all its children so the children can communicate.
+ */
+
+#ifndef __DEV_TSUNAMI_HH__
+#define __DEV_TSUNAMI_HH__
+
+#include "dev/platform.hh"
+
+class IdeController;
+class TsunamiCChip;
+class TsunamiPChip;
+class TsunamiIO;
+class System;
+
+/**
+ * Top level class for Tsunami Chipset emulation.
+ * This structure just contains pointers to all the
+ * children so the children can commnicate to do the
+ * read work
+ */
+
+class Tsunami : public Platform
+{
+ public:
+ /** Max number of CPUs in a Tsunami */
+ static const int Max_CPUs = 64;
+
+ /** Pointer to the system */
+ System *system;
+
+ /** Pointer to the TsunamiIO device which has the RTC */
+ TsunamiIO *io;
+
+ /** Pointer to the Tsunami CChip.
+ * The chip contains some configuration information and
+ * all the interrupt mask and status registers
+ */
+ TsunamiCChip *cchip;
+
+ /** Pointer to the Tsunami PChip.
+ * The pchip is the interface to the PCI bus, in our case
+ * it does not have to do much.
+ */
+ TsunamiPChip *pchip;
+
+ int intr_sum_type[Tsunami::Max_CPUs];
+ int ipi_pending[Tsunami::Max_CPUs];
+
+ public:
+ /**
+ * Constructor for the Tsunami Class.
+ * @param name name of the object
+ * @param intrctrl pointer to the interrupt controller
+ */
+ Tsunami(const std::string &name, System *s, IntrControl *intctrl);
+
+ /**
+ * Return the interrupting frequency to AlphaAccess
+ * @return frequency of RTC interrupts
+ */
+ virtual Tick intrFrequency();
+
+ /**
+ * Cause the cpu to post a serial interrupt to the CPU.
+ */
+ virtual void postConsoleInt();
+
+ /**
+ * Clear a posted CPU interrupt (id=55)
+ */
+ virtual void clearConsoleInt();
+
+ /**
+ * Cause the chipset to post a cpi interrupt to the CPU.
+ */
+ virtual void postPciInt(int line);
+
+ /**
+ * Clear a posted PCI->CPU interrupt
+ */
+ virtual void clearPciInt(int line);
+
+ virtual Addr pciToDma(Addr pciAddr) const;
+
+ /**
+ * Serialize this object to the given output stream.
+ * @param os The stream to serialize to.
+ */
+ virtual void serialize(std::ostream &os);
+
+ /**
+ * Reconstruct the state of this object from a checkpoint.
+ * @param cp The checkpoint use.
+ * @param section The section name of this object
+ */
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+};
+
+#endif // __DEV_TSUNAMI_HH__
diff --git a/src/dev/tsunami_cchip.cc b/src/dev/tsunami_cchip.cc
new file mode 100644
index 000000000..7206a61bb
--- /dev/null
+++ b/src/dev/tsunami_cchip.cc
@@ -0,0 +1,554 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * Emulation of the Tsunami CChip CSRs
+ */
+
+#include <deque>
+#include <string>
+#include <vector>
+
+#include "arch/alpha/ev5.hh"
+#include "base/trace.hh"
+#include "dev/tsunami_cchip.hh"
+#include "dev/tsunamireg.h"
+#include "dev/tsunami.hh"
+#include "mem/port.hh"
+#include "cpu/exec_context.hh"
+#include "cpu/intr_control.hh"
+#include "sim/builder.hh"
+#include "sim/system.hh"
+
+using namespace std;
+//Should this be AlphaISA?
+using namespace TheISA;
+
+TsunamiCChip::TsunamiCChip(Params *p)
+ : BasicPioDevice(p), tsunami(p->tsunami)
+{
+ pioSize = 0xfffffff;
+
+ drir = 0;
+ ipint = 0;
+ itint = 0;
+
+ for (int x = 0; x < Tsunami::Max_CPUs; x++)
+ {
+ dim[x] = 0;
+ dir[x] = 0;
+ }
+
+ //Put back pointer in tsunami
+ tsunami->cchip = this;
+}
+
+Tick
+TsunamiCChip::read(Packet *pkt)
+{
+ DPRINTF(Tsunami, "read va=%#x size=%d\n", pkt->addr, pkt->size);
+
+ assert(pkt->result == Unknown);
+ assert(pkt->addr >= pioAddr && pkt->addr < pioAddr + pioSize);
+
+ pkt->time += pioDelay;
+ Addr regnum = (pkt->addr - pioAddr) >> 6;
+ Addr daddr = (pkt->addr - pioAddr);
+
+ pkt->allocate();
+ switch (pkt->size) {
+
+ case sizeof(uint64_t):
+ if (daddr & TSDEV_CC_BDIMS)
+ {
+ pkt->set(dim[(daddr >> 4) & 0x3F]);
+ break;
+ }
+
+ if (daddr & TSDEV_CC_BDIRS)
+ {
+ pkt->set(dir[(daddr >> 4) & 0x3F]);
+ break;
+ }
+
+ switch(regnum) {
+ case TSDEV_CC_CSR:
+ pkt->set(0x0);
+ break;
+ case TSDEV_CC_MTR:
+ panic("TSDEV_CC_MTR not implemeted\n");
+ break;
+ case TSDEV_CC_MISC:
+ pkt->set((ipint << 8) & 0xF | (itint << 4) & 0xF |
+ (pkt->req->getCpuNum() & 0x3));
+ break;
+ case TSDEV_CC_AAR0:
+ case TSDEV_CC_AAR1:
+ case TSDEV_CC_AAR2:
+ case TSDEV_CC_AAR3:
+ pkt->set(0);
+ break;
+ case TSDEV_CC_DIM0:
+ pkt->set(dim[0]);
+ break;
+ case TSDEV_CC_DIM1:
+ pkt->set(dim[1]);
+ break;
+ case TSDEV_CC_DIM2:
+ pkt->set(dim[2]);
+ break;
+ case TSDEV_CC_DIM3:
+ pkt->set(dim[3]);
+ break;
+ case TSDEV_CC_DIR0:
+ pkt->set(dir[0]);
+ break;
+ case TSDEV_CC_DIR1:
+ pkt->set(dir[1]);
+ break;
+ case TSDEV_CC_DIR2:
+ pkt->set(dir[2]);
+ break;
+ case TSDEV_CC_DIR3:
+ pkt->set(dir[3]);
+ break;
+ case TSDEV_CC_DRIR:
+ pkt->set(drir);
+ break;
+ case TSDEV_CC_PRBEN:
+ panic("TSDEV_CC_PRBEN not implemented\n");
+ break;
+ case TSDEV_CC_IIC0:
+ case TSDEV_CC_IIC1:
+ case TSDEV_CC_IIC2:
+ case TSDEV_CC_IIC3:
+ panic("TSDEV_CC_IICx not implemented\n");
+ break;
+ case TSDEV_CC_MPR0:
+ case TSDEV_CC_MPR1:
+ case TSDEV_CC_MPR2:
+ case TSDEV_CC_MPR3:
+ panic("TSDEV_CC_MPRx not implemented\n");
+ break;
+ case TSDEV_CC_IPIR:
+ pkt->set(ipint);
+ break;
+ case TSDEV_CC_ITIR:
+ pkt->set(itint);
+ break;
+ default:
+ panic("default in cchip read reached, accessing 0x%x\n");
+ } // uint64_t
+
+ break;
+ case sizeof(uint32_t):
+ case sizeof(uint16_t):
+ case sizeof(uint8_t):
+ default:
+ panic("invalid access size(?) for tsunami register!\n");
+ }
+ DPRINTF(Tsunami, "Tsunami CChip: read regnum=%#x size=%d data=%lld\n",
+ regnum, pkt->size, pkt->get<uint64_t>());
+
+ pkt->result = Success;
+ return pioDelay;
+}
+
+Tick
+TsunamiCChip::write(Packet *pkt)
+{
+ pkt->time += pioDelay;
+
+
+ assert(pkt->addr >= pioAddr && pkt->addr < pioAddr + pioSize);
+ Addr daddr = pkt->addr - pioAddr;
+ Addr regnum = (pkt->addr - pioAddr) >> 6 ;
+
+
+ assert(pkt->size == sizeof(uint64_t));
+
+ DPRINTF(Tsunami, "write - addr=%#x value=%#x\n", pkt->addr, pkt->get<uint64_t>());
+
+ bool supportedWrite = false;
+
+
+ if (daddr & TSDEV_CC_BDIMS)
+ {
+ int number = (daddr >> 4) & 0x3F;
+
+ uint64_t bitvector;
+ uint64_t olddim;
+ uint64_t olddir;
+
+ olddim = dim[number];
+ olddir = dir[number];
+ dim[number] = pkt->get<uint64_t>();
+ dir[number] = dim[number] & drir;
+ for(int x = 0; x < Tsunami::Max_CPUs; x++)
+ {
+ bitvector = ULL(1) << x;
+ // Figure out which bits have changed
+ if ((dim[number] & bitvector) != (olddim & bitvector))
+ {
+ // The bit is now set and it wasn't before (set)
+ if((dim[number] & bitvector) && (dir[number] & bitvector))
+ {
+ tsunami->intrctrl->post(number, TheISA::INTLEVEL_IRQ1, x);
+ DPRINTF(Tsunami, "dim write resulting in posting dir"
+ " interrupt to cpu %d\n", number);
+ }
+ else if ((olddir & bitvector) &&
+ !(dir[number] & bitvector))
+ {
+ // The bit was set and now its now clear and
+ // we were interrupting on that bit before
+ tsunami->intrctrl->clear(number, TheISA::INTLEVEL_IRQ1, x);
+ DPRINTF(Tsunami, "dim write resulting in clear"
+ " dir interrupt to cpu %d\n", number);
+
+ }
+
+
+ }
+ }
+ } else {
+ switch(regnum) {
+ case TSDEV_CC_CSR:
+ panic("TSDEV_CC_CSR write\n");
+ case TSDEV_CC_MTR:
+ panic("TSDEV_CC_MTR write not implemented\n");
+ case TSDEV_CC_MISC:
+ uint64_t ipreq;
+ ipreq = (pkt->get<uint64_t>() >> 12) & 0xF;
+ //If it is bit 12-15, this is an IPI post
+ if (ipreq) {
+ reqIPI(ipreq);
+ supportedWrite = true;
+ }
+
+ //If it is bit 8-11, this is an IPI clear
+ uint64_t ipintr;
+ ipintr = (pkt->get<uint64_t>() >> 8) & 0xF;
+ if (ipintr) {
+ clearIPI(ipintr);
+ supportedWrite = true;
+ }
+
+ //If it is the 4-7th bit, clear the RTC interrupt
+ uint64_t itintr;
+ itintr = (pkt->get<uint64_t>() >> 4) & 0xF;
+ if (itintr) {
+ clearITI(itintr);
+ supportedWrite = true;
+ }
+
+ // ignore NXMs
+ if (pkt->get<uint64_t>() & 0x10000000)
+ supportedWrite = true;
+
+ if(!supportedWrite)
+ panic("TSDEV_CC_MISC write not implemented\n");
+
+ break;
+ case TSDEV_CC_AAR0:
+ case TSDEV_CC_AAR1:
+ case TSDEV_CC_AAR2:
+ case TSDEV_CC_AAR3:
+ panic("TSDEV_CC_AARx write not implemeted\n");
+ case TSDEV_CC_DIM0:
+ case TSDEV_CC_DIM1:
+ case TSDEV_CC_DIM2:
+ case TSDEV_CC_DIM3:
+ int number;
+ if(regnum == TSDEV_CC_DIM0)
+ number = 0;
+ else if(regnum == TSDEV_CC_DIM1)
+ number = 1;
+ else if(regnum == TSDEV_CC_DIM2)
+ number = 2;
+ else
+ number = 3;
+
+ uint64_t bitvector;
+ uint64_t olddim;
+ uint64_t olddir;
+
+ olddim = dim[number];
+ olddir = dir[number];
+ dim[number] = pkt->get<uint64_t>();
+ dir[number] = dim[number] & drir;
+ for(int x = 0; x < 64; x++)
+ {
+ bitvector = ULL(1) << x;
+ // Figure out which bits have changed
+ if ((dim[number] & bitvector) != (olddim & bitvector))
+ {
+ // The bit is now set and it wasn't before (set)
+ if((dim[number] & bitvector) && (dir[number] & bitvector))
+ {
+ tsunami->intrctrl->post(number, TheISA::INTLEVEL_IRQ1, x);
+ DPRINTF(Tsunami, "posting dir interrupt to cpu 0\n");
+ }
+ else if ((olddir & bitvector) &&
+ !(dir[number] & bitvector))
+ {
+ // The bit was set and now its now clear and
+ // we were interrupting on that bit before
+ tsunami->intrctrl->clear(number, TheISA::INTLEVEL_IRQ1, x);
+ DPRINTF(Tsunami, "dim write resulting in clear"
+ " dir interrupt to cpu %d\n",
+ x);
+
+ }
+
+
+ }
+ }
+ break;
+ case TSDEV_CC_DIR0:
+ case TSDEV_CC_DIR1:
+ case TSDEV_CC_DIR2:
+ case TSDEV_CC_DIR3:
+ panic("TSDEV_CC_DIR write not implemented\n");
+ case TSDEV_CC_DRIR:
+ panic("TSDEV_CC_DRIR write not implemented\n");
+ case TSDEV_CC_PRBEN:
+ panic("TSDEV_CC_PRBEN write not implemented\n");
+ case TSDEV_CC_IIC0:
+ case TSDEV_CC_IIC1:
+ case TSDEV_CC_IIC2:
+ case TSDEV_CC_IIC3:
+ panic("TSDEV_CC_IICx write not implemented\n");
+ case TSDEV_CC_MPR0:
+ case TSDEV_CC_MPR1:
+ case TSDEV_CC_MPR2:
+ case TSDEV_CC_MPR3:
+ panic("TSDEV_CC_MPRx write not implemented\n");
+ case TSDEV_CC_IPIR:
+ clearIPI(pkt->get<uint64_t>());
+ break;
+ case TSDEV_CC_ITIR:
+ clearITI(pkt->get<uint64_t>());
+ break;
+ case TSDEV_CC_IPIQ:
+ reqIPI(pkt->get<uint64_t>());
+ break;
+ default:
+ panic("default in cchip read reached, accessing 0x%x\n");
+ } // swtich(regnum)
+ } // not BIG_TSUNAMI write
+ pkt->result = Success;
+ return pioDelay;
+}
+
+void
+TsunamiCChip::clearIPI(uint64_t ipintr)
+{
+ int numcpus = tsunami->intrctrl->cpu->system->execContexts.size();
+ assert(numcpus <= Tsunami::Max_CPUs);
+
+ if (ipintr) {
+ for (int cpunum=0; cpunum < numcpus; cpunum++) {
+ // Check each cpu bit
+ uint64_t cpumask = ULL(1) << cpunum;
+ if (ipintr & cpumask) {
+ // Check if there is a pending ipi
+ if (ipint & cpumask) {
+ ipint &= ~cpumask;
+ tsunami->intrctrl->clear(cpunum, TheISA::INTLEVEL_IRQ3, 0);
+ DPRINTF(IPI, "clear IPI IPI cpu=%d\n", cpunum);
+ }
+ else
+ warn("clear IPI for CPU=%d, but NO IPI\n", cpunum);
+ }
+ }
+ }
+ else
+ panic("Big IPI Clear, but not processors indicated\n");
+}
+
+void
+TsunamiCChip::clearITI(uint64_t itintr)
+{
+ int numcpus = tsunami->intrctrl->cpu->system->execContexts.size();
+ assert(numcpus <= Tsunami::Max_CPUs);
+
+ if (itintr) {
+ for (int i=0; i < numcpus; i++) {
+ uint64_t cpumask = ULL(1) << i;
+ if (itintr & cpumask & itint) {
+ tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ2, 0);
+ itint &= ~cpumask;
+ DPRINTF(Tsunami, "clearing rtc interrupt to cpu=%d\n", i);
+ }
+ }
+ }
+ else
+ panic("Big ITI Clear, but not processors indicated\n");
+}
+
+void
+TsunamiCChip::reqIPI(uint64_t ipreq)
+{
+ int numcpus = tsunami->intrctrl->cpu->system->execContexts.size();
+ assert(numcpus <= Tsunami::Max_CPUs);
+
+ if (ipreq) {
+ for (int cpunum=0; cpunum < numcpus; cpunum++) {
+ // Check each cpu bit
+ uint64_t cpumask = ULL(1) << cpunum;
+ if (ipreq & cpumask) {
+ // Check if there is already an ipi (bits 8:11)
+ if (!(ipint & cpumask)) {
+ ipint |= cpumask;
+ tsunami->intrctrl->post(cpunum, TheISA::INTLEVEL_IRQ3, 0);
+ DPRINTF(IPI, "send IPI cpu=%d\n", cpunum);
+ }
+ else
+ warn("post IPI for CPU=%d, but IPI already\n", cpunum);
+ }
+ }
+ }
+ else
+ panic("Big IPI Request, but not processors indicated\n");
+}
+
+
+void
+TsunamiCChip::postRTC()
+{
+ int size = tsunami->intrctrl->cpu->system->execContexts.size();
+ assert(size <= Tsunami::Max_CPUs);
+
+ for (int i = 0; i < size; i++) {
+ uint64_t cpumask = ULL(1) << i;
+ if (!(cpumask & itint)) {
+ itint |= cpumask;
+ tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ2, 0);
+ DPRINTF(Tsunami, "Posting RTC interrupt to cpu=%d", i);
+ }
+ }
+
+}
+
+void
+TsunamiCChip::postDRIR(uint32_t interrupt)
+{
+ uint64_t bitvector = ULL(1) << interrupt;
+ uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size();
+ assert(size <= Tsunami::Max_CPUs);
+ drir |= bitvector;
+
+ for(int i=0; i < size; i++) {
+ dir[i] = dim[i] & drir;
+ if (dim[i] & bitvector) {
+ tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ1, interrupt);
+ DPRINTF(Tsunami, "posting dir interrupt to cpu %d,"
+ "interrupt %d\n",i, interrupt);
+ }
+ }
+}
+
+void
+TsunamiCChip::clearDRIR(uint32_t interrupt)
+{
+ uint64_t bitvector = ULL(1) << interrupt;
+ uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size();
+ assert(size <= Tsunami::Max_CPUs);
+
+ if (drir & bitvector)
+ {
+ drir &= ~bitvector;
+ for(int i=0; i < size; i++) {
+ if (dir[i] & bitvector) {
+ tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ1, interrupt);
+ DPRINTF(Tsunami, "clearing dir interrupt to cpu %d,"
+ "interrupt %d\n",i, interrupt);
+
+ }
+ dir[i] = dim[i] & drir;
+ }
+ }
+ else
+ DPRINTF(Tsunami, "Spurrious clear? interrupt %d\n", interrupt);
+}
+
+
+void
+TsunamiCChip::serialize(std::ostream &os)
+{
+ SERIALIZE_ARRAY(dim, Tsunami::Max_CPUs);
+ SERIALIZE_ARRAY(dir, Tsunami::Max_CPUs);
+ SERIALIZE_SCALAR(ipint);
+ SERIALIZE_SCALAR(itint);
+ SERIALIZE_SCALAR(drir);
+}
+
+void
+TsunamiCChip::unserialize(Checkpoint *cp, const std::string &section)
+{
+ UNSERIALIZE_ARRAY(dim, Tsunami::Max_CPUs);
+ UNSERIALIZE_ARRAY(dir, Tsunami::Max_CPUs);
+ UNSERIALIZE_SCALAR(ipint);
+ UNSERIALIZE_SCALAR(itint);
+ UNSERIALIZE_SCALAR(drir);
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip)
+
+ Param<Addr> pio_addr;
+ Param<Tick> pio_latency;
+ SimObjectParam<Platform *> platform;
+ SimObjectParam<System *> system;
+ SimObjectParam<Tsunami *> tsunami;
+
+END_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiCChip)
+
+ INIT_PARAM(pio_addr, "Device Address"),
+ INIT_PARAM(pio_latency, "Programmed IO latency"),
+ INIT_PARAM(platform, "platform"),
+ INIT_PARAM(system, "system object"),
+ INIT_PARAM(tsunami, "Tsunami")
+
+END_INIT_SIM_OBJECT_PARAMS(TsunamiCChip)
+
+CREATE_SIM_OBJECT(TsunamiCChip)
+{
+ TsunamiCChip::Params *p = new TsunamiCChip::Params;
+ p->name = getInstanceName();
+ p->pio_addr = pio_addr;
+ p->pio_delay = pio_latency;
+ p->platform = platform;
+ p->system = system;
+ p->tsunami = tsunami;
+ return new TsunamiCChip(p);
+}
+
+REGISTER_SIM_OBJECT("TsunamiCChip", TsunamiCChip)
diff --git a/src/dev/tsunami_cchip.hh b/src/dev/tsunami_cchip.hh
new file mode 100644
index 000000000..3dde0131e
--- /dev/null
+++ b/src/dev/tsunami_cchip.hh
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * Emulation of the Tsunami CChip CSRs
+ */
+
+#ifndef __TSUNAMI_CCHIP_HH__
+#define __TSUNAMI_CCHIP_HH__
+
+#include "dev/tsunami.hh"
+#include "base/range.hh"
+#include "dev/io_device.hh"
+
+
+/**
+ * Tsunami CChip CSR Emulation. This device includes all the interrupt
+ * handling code for the chipset.
+ */
+class TsunamiCChip : public BasicPioDevice
+{
+ protected:
+ /**
+ * pointer to the tsunami object.
+ * This is our access to all the other tsunami
+ * devices.
+ */
+ Tsunami *tsunami;
+
+ /**
+ * The dims are device interrupt mask registers.
+ * One exists for each CPU, the DRIR X DIM = DIR
+ */
+ uint64_t dim[Tsunami::Max_CPUs];
+
+ /**
+ * The dirs are device interrupt registers.
+ * One exists for each CPU, the DRIR X DIM = DIR
+ */
+ uint64_t dir[Tsunami::Max_CPUs];
+
+ /**
+ * This register contains bits for each PCI interrupt
+ * that can occur.
+ */
+ uint64_t drir;
+
+ /** Indicator of which CPUs have an IPI interrupt */
+ uint64_t ipint;
+
+ /** Indicator of which CPUs have an RTC interrupt */
+ uint64_t itint;
+
+ public:
+ struct Params : public BasicPioDevice::Params
+ {
+ Tsunami *tsunami;
+ };
+ protected:
+ const Params *params() const {return (const Params *)_params; }
+
+ public:
+ /**
+ * Initialize the Tsunami CChip by setting all of the
+ * device register to 0.
+ * @param p params struct
+ */
+ TsunamiCChip(Params *p);
+
+ virtual Tick read(Packet *pkt);
+
+ virtual Tick write(Packet *pkt);
+
+ /**
+ * post an RTC interrupt to the CPU
+ */
+ void postRTC();
+
+ /**
+ * post an interrupt to the CPU.
+ * @param interrupt the interrupt number to post (0-64)
+ */
+ void postDRIR(uint32_t interrupt);
+
+ /**
+ * clear an interrupt previously posted to the CPU.
+ * @param interrupt the interrupt number to post (0-64)
+ */
+ void clearDRIR(uint32_t interrupt);
+
+ /**
+ * post an ipi interrupt to the CPU.
+ * @param ipintr the cpu number to clear(bitvector)
+ */
+ void clearIPI(uint64_t ipintr);
+
+ /**
+ * clear a timer interrupt previously posted to the CPU.
+ * @param itintr the cpu number to clear(bitvector)
+ */
+ void clearITI(uint64_t itintr);
+
+ /**
+ * request an interrupt be posted to the CPU.
+ * @param ipreq the cpu number to interrupt(bitvector)
+ */
+ void reqIPI(uint64_t ipreq);
+
+
+ /**
+ * Serialize this object to the given output stream.
+ * @param os The stream to serialize to.
+ */
+ virtual void serialize(std::ostream &os);
+
+ /**
+ * Reconstruct the state of this object from a checkpoint.
+ * @param cp The checkpoint use.
+ * @param section The section name of this object
+ */
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+
+};
+
+#endif // __TSUNAMI_CCHIP_HH__
diff --git a/src/dev/tsunami_io.cc b/src/dev/tsunami_io.cc
new file mode 100644
index 000000000..dd9feae99
--- /dev/null
+++ b/src/dev/tsunami_io.cc
@@ -0,0 +1,679 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * Tsunami I/O including PIC, PIT, RTC, DMA
+ */
+
+#include <sys/time.h>
+
+#include <deque>
+#include <string>
+#include <vector>
+
+#include "base/trace.hh"
+#include "dev/pitreg.h"
+#include "dev/rtcreg.h"
+#include "dev/tsunami_cchip.hh"
+#include "dev/tsunami.hh"
+#include "dev/tsunami_io.hh"
+#include "dev/tsunamireg.h"
+#include "mem/port.hh"
+#include "sim/builder.hh"
+#include "sim/system.hh"
+
+using namespace std;
+//Should this be AlphaISA?
+using namespace TheISA;
+
+TsunamiIO::RTC::RTC(const string &name, Tsunami* t, Tick i)
+ : _name(name), event(t, i), addr(0)
+{
+ memset(clock_data, 0, sizeof(clock_data));
+ stat_regA = RTCA_32768HZ | RTCA_1024HZ;
+ stat_regB = RTCB_PRDC_IE |RTCB_BIN | RTCB_24HR;
+}
+
+void
+TsunamiIO::RTC::set_time(time_t t)
+{
+ struct tm tm;
+ gmtime_r(&t, &tm);
+
+ sec = tm.tm_sec;
+ min = tm.tm_min;
+ hour = tm.tm_hour;
+ wday = tm.tm_wday + 1;
+ mday = tm.tm_mday;
+ mon = tm.tm_mon + 1;
+ year = tm.tm_year;
+
+ DPRINTFN("Real-time clock set to %s", asctime(&tm));
+}
+
+void
+TsunamiIO::RTC::writeAddr(const uint8_t data)
+{
+ if (data <= RTC_STAT_REGD)
+ addr = data;
+ else
+ panic("RTC addresses over 0xD are not implemented.\n");
+}
+
+void
+TsunamiIO::RTC::writeData(const uint8_t data)
+{
+ if (addr < RTC_STAT_REGA)
+ clock_data[addr] = data;
+ else {
+ switch (addr) {
+ case RTC_STAT_REGA:
+ if (data != (RTCA_32768HZ | RTCA_1024HZ))
+ panic("Unimplemented RTC register A value write!\n");
+ stat_regA = data;
+ break;
+ case RTC_STAT_REGB:
+ if ((data & ~(RTCB_PRDC_IE | RTCB_SQWE)) != (RTCB_BIN | RTCB_24HR))
+ panic("Write to RTC reg B bits that are not implemented!\n");
+
+ if (data & RTCB_PRDC_IE) {
+ if (!event.scheduled())
+ event.scheduleIntr();
+ } else {
+ if (event.scheduled())
+ event.deschedule();
+ }
+ stat_regB = data;
+ break;
+ case RTC_STAT_REGC:
+ case RTC_STAT_REGD:
+ panic("RTC status registers C and D are not implemented.\n");
+ break;
+ }
+ }
+}
+
+void
+TsunamiIO::RTC::readData(uint8_t *data)
+{
+ if (addr < RTC_STAT_REGA)
+ *data = clock_data[addr];
+ else {
+ switch (addr) {
+ case RTC_STAT_REGA:
+ // toggle UIP bit for linux
+ stat_regA ^= RTCA_UIP;
+ *data = stat_regA;
+ break;
+ case RTC_STAT_REGB:
+ *data = stat_regB;
+ break;
+ case RTC_STAT_REGC:
+ case RTC_STAT_REGD:
+ *data = 0x00;
+ break;
+ }
+ }
+}
+
+void
+TsunamiIO::RTC::serialize(const string &base, ostream &os)
+{
+ paramOut(os, base + ".addr", addr);
+ arrayParamOut(os, base + ".clock_data", clock_data, sizeof(clock_data));
+ paramOut(os, base + ".stat_regA", stat_regA);
+ paramOut(os, base + ".stat_regB", stat_regB);
+}
+
+void
+TsunamiIO::RTC::unserialize(const string &base, Checkpoint *cp,
+ const string &section)
+{
+ paramIn(cp, section, base + ".addr", addr);
+ arrayParamIn(cp, section, base + ".clock_data", clock_data,
+ sizeof(clock_data));
+ paramIn(cp, section, base + ".stat_regA", stat_regA);
+ paramIn(cp, section, base + ".stat_regB", stat_regB);
+
+ // We're not unserializing the event here, but we need to
+ // rescehedule the event since curTick was moved forward by the
+ // checkpoint
+ event.reschedule(curTick + event.interval);
+}
+
+TsunamiIO::RTC::RTCEvent::RTCEvent(Tsunami*t, Tick i)
+ : Event(&mainEventQueue), tsunami(t), interval(i)
+{
+ DPRINTF(MC146818, "RTC Event Initilizing\n");
+ schedule(curTick + interval);
+}
+
+void
+TsunamiIO::RTC::RTCEvent::scheduleIntr()
+{
+ schedule(curTick + interval);
+}
+
+void
+TsunamiIO::RTC::RTCEvent::process()
+{
+ DPRINTF(MC146818, "RTC Timer Interrupt\n");
+ schedule(curTick + interval);
+ //Actually interrupt the processor here
+ tsunami->cchip->postRTC();
+}
+
+const char *
+TsunamiIO::RTC::RTCEvent::description()
+{
+ return "tsunami RTC interrupt";
+}
+
+TsunamiIO::PITimer::PITimer(const string &name)
+ : _name(name), counter0(name + ".counter0"), counter1(name + ".counter1"),
+ counter2(name + ".counter2")
+{
+ counter[0] = &counter0;
+ counter[1] = &counter0;
+ counter[2] = &counter0;
+}
+
+void
+TsunamiIO::PITimer::writeControl(const uint8_t data)
+{
+ int rw;
+ int sel;
+
+ sel = GET_CTRL_SEL(data);
+
+ if (sel == PIT_READ_BACK)
+ panic("PITimer Read-Back Command is not implemented.\n");
+
+ rw = GET_CTRL_RW(data);
+
+ if (rw == PIT_RW_LATCH_COMMAND)
+ counter[sel]->latchCount();
+ else {
+ counter[sel]->setRW(rw);
+ counter[sel]->setMode(GET_CTRL_MODE(data));
+ counter[sel]->setBCD(GET_CTRL_BCD(data));
+ }
+}
+
+void
+TsunamiIO::PITimer::serialize(const string &base, ostream &os)
+{
+ // serialize the counters
+ counter0.serialize(base + ".counter0", os);
+ counter1.serialize(base + ".counter1", os);
+ counter2.serialize(base + ".counter2", os);
+}
+
+void
+TsunamiIO::PITimer::unserialize(const string &base, Checkpoint *cp,
+ const string &section)
+{
+ // unserialze the counters
+ counter0.unserialize(base + ".counter0", cp, section);
+ counter1.unserialize(base + ".counter1", cp, section);
+ counter2.unserialize(base + ".counter2", cp, section);
+}
+
+TsunamiIO::PITimer::Counter::Counter(const string &name)
+ : _name(name), event(this), count(0), latched_count(0), period(0),
+ mode(0), output_high(false), latch_on(false), read_byte(LSB),
+ write_byte(LSB)
+{
+
+}
+
+void
+TsunamiIO::PITimer::Counter::latchCount()
+{
+ // behave like a real latch
+ if(!latch_on) {
+ latch_on = true;
+ read_byte = LSB;
+ latched_count = count;
+ }
+}
+
+void
+TsunamiIO::PITimer::Counter::read(uint8_t *data)
+{
+ if (latch_on) {
+ switch (read_byte) {
+ case LSB:
+ read_byte = MSB;
+ *data = (uint8_t)latched_count;
+ break;
+ case MSB:
+ read_byte = LSB;
+ latch_on = false;
+ *data = latched_count >> 8;
+ break;
+ }
+ } else {
+ switch (read_byte) {
+ case LSB:
+ read_byte = MSB;
+ *data = (uint8_t)count;
+ break;
+ case MSB:
+ read_byte = LSB;
+ *data = count >> 8;
+ break;
+ }
+ }
+}
+
+void
+TsunamiIO::PITimer::Counter::write(const uint8_t data)
+{
+ switch (write_byte) {
+ case LSB:
+ count = (count & 0xFF00) | data;
+
+ if (event.scheduled())
+ event.deschedule();
+ output_high = false;
+ write_byte = MSB;
+ break;
+
+ case MSB:
+ count = (count & 0x00FF) | (data << 8);
+ period = count;
+
+ if (period > 0) {
+ DPRINTF(Tsunami, "Timer set to curTick + %d\n",
+ count * event.interval);
+ event.schedule(curTick + count * event.interval);
+ }
+ write_byte = LSB;
+ break;
+ }
+}
+
+void
+TsunamiIO::PITimer::Counter::setRW(int rw_val)
+{
+ if (rw_val != PIT_RW_16BIT)
+ panic("Only LSB/MSB read/write is implemented.\n");
+}
+
+void
+TsunamiIO::PITimer::Counter::setMode(int mode_val)
+{
+ if(mode_val != PIT_MODE_INTTC && mode_val != PIT_MODE_RATEGEN &&
+ mode_val != PIT_MODE_SQWAVE)
+ panic("PIT mode %#x is not implemented: \n", mode_val);
+
+ mode = mode_val;
+}
+
+void
+TsunamiIO::PITimer::Counter::setBCD(int bcd_val)
+{
+ if (bcd_val != PIT_BCD_FALSE)
+ panic("PITimer does not implement BCD counts.\n");
+}
+
+bool
+TsunamiIO::PITimer::Counter::outputHigh()
+{
+ return output_high;
+}
+
+void
+TsunamiIO::PITimer::Counter::serialize(const string &base, ostream &os)
+{
+ paramOut(os, base + ".count", count);
+ paramOut(os, base + ".latched_count", latched_count);
+ paramOut(os, base + ".period", period);
+ paramOut(os, base + ".mode", mode);
+ paramOut(os, base + ".output_high", output_high);
+ paramOut(os, base + ".latch_on", latch_on);
+ paramOut(os, base + ".read_byte", read_byte);
+ paramOut(os, base + ".write_byte", write_byte);
+
+ Tick event_tick = 0;
+ if (event.scheduled())
+ event_tick = event.when();
+ paramOut(os, base + ".event_tick", event_tick);
+}
+
+void
+TsunamiIO::PITimer::Counter::unserialize(const string &base, Checkpoint *cp,
+ const string &section)
+{
+ paramIn(cp, section, base + ".count", count);
+ paramIn(cp, section, base + ".latched_count", latched_count);
+ paramIn(cp, section, base + ".period", period);
+ paramIn(cp, section, base + ".mode", mode);
+ paramIn(cp, section, base + ".output_high", output_high);
+ paramIn(cp, section, base + ".latch_on", latch_on);
+ paramIn(cp, section, base + ".read_byte", read_byte);
+ paramIn(cp, section, base + ".write_byte", write_byte);
+
+ Tick event_tick;
+ paramIn(cp, section, base + ".event_tick", event_tick);
+ if (event_tick)
+ event.schedule(event_tick);
+}
+
+TsunamiIO::PITimer::Counter::CounterEvent::CounterEvent(Counter* c_ptr)
+ : Event(&mainEventQueue)
+{
+ interval = (Tick)(Clock::Float::s / 1193180.0);
+ counter = c_ptr;
+}
+
+void
+TsunamiIO::PITimer::Counter::CounterEvent::process()
+{
+ DPRINTF(Tsunami, "Timer Interrupt\n");
+ switch (counter->mode) {
+ case PIT_MODE_INTTC:
+ counter->output_high = true;
+ case PIT_MODE_RATEGEN:
+ case PIT_MODE_SQWAVE:
+ break;
+ default:
+ panic("Unimplemented PITimer mode.\n");
+ }
+}
+
+const char *
+TsunamiIO::PITimer::Counter::CounterEvent::description()
+{
+ return "tsunami 8254 Interval timer";
+}
+
+TsunamiIO::TsunamiIO(Params *p)
+ : BasicPioDevice(p), tsunami(p->tsunami), pitimer(p->name + "pitimer"),
+ rtc(p->name + ".rtc", p->tsunami, p->frequency)
+{
+ pioSize = 0xff;
+
+ // set the back pointer from tsunami to myself
+ tsunami->io = this;
+
+ timerData = 0;
+ rtc.set_time(p->init_time == 0 ? time(NULL) : p->init_time);
+ picr = 0;
+ picInterrupting = false;
+}
+
+Tick
+TsunamiIO::frequency() const
+{
+ return Clock::Frequency / params()->frequency;
+}
+
+Tick
+TsunamiIO::read(Packet *pkt)
+{
+ assert(pkt->result == Unknown);
+ assert(pkt->addr >= pioAddr && pkt->addr < pioAddr + pioSize);
+
+ pkt->time += pioDelay;
+ Addr daddr = pkt->addr - pioAddr;
+
+ DPRINTF(Tsunami, "io read va=%#x size=%d IOPorrt=%#x\n", pkt->addr,
+ pkt->size, daddr);
+
+ pkt->allocate();
+
+ if (pkt->size == sizeof(uint8_t)) {
+ switch(daddr) {
+ // PIC1 mask read
+ case TSDEV_PIC1_MASK:
+ pkt->set(~mask1);
+ break;
+ case TSDEV_PIC2_MASK:
+ pkt->set(~mask2);
+ break;
+ case TSDEV_PIC1_ISR:
+ // !!! If this is modified 64bit case needs to be too
+ // Pal code has to do a 64 bit physical read because there is
+ // no load physical byte instruction
+ pkt->set(picr);
+ break;
+ case TSDEV_PIC2_ISR:
+ // PIC2 not implemnted... just return 0
+ pkt->set(0x00);
+ break;
+ case TSDEV_TMR0_DATA:
+ pitimer.counter0.read(pkt->getPtr<uint8_t>());
+ break;
+ case TSDEV_TMR1_DATA:
+ pitimer.counter1.read(pkt->getPtr<uint8_t>());
+ break;
+ case TSDEV_TMR2_DATA:
+ pitimer.counter2.read(pkt->getPtr<uint8_t>());
+ break;
+ case TSDEV_RTC_DATA:
+ rtc.readData(pkt->getPtr<uint8_t>());
+ break;
+ case TSDEV_CTRL_PORTB:
+ if (pitimer.counter2.outputHigh())
+ pkt->set(PORTB_SPKR_HIGH);
+ else
+ pkt->set(0x00);
+ break;
+ default:
+ panic("I/O Read - va%#x size %d\n", pkt->addr, pkt->size);
+ }
+ } else if (pkt->size == sizeof(uint64_t)) {
+ if (daddr == TSDEV_PIC1_ISR)
+ pkt->set<uint64_t>(picr);
+ else
+ panic("I/O Read - invalid addr - va %#x size %d\n",
+ pkt->addr, pkt->size);
+ } else {
+ panic("I/O Read - invalid size - va %#x size %d\n", pkt->addr, pkt->size);
+ }
+ pkt->result = Success;
+ return pioDelay;
+}
+
+Tick
+TsunamiIO::write(Packet *pkt)
+{
+ pkt->time += pioDelay;
+
+ assert(pkt->result == Unknown);
+ assert(pkt->addr >= pioAddr && pkt->addr < pioAddr + pioSize);
+ Addr daddr = pkt->addr - pioAddr;
+
+ DPRINTF(Tsunami, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n",
+ pkt->addr, pkt->size, pkt->addr & 0xfff, (uint32_t)pkt->get<uint8_t>());
+
+ assert(pkt->size == sizeof(uint8_t));
+
+ switch(daddr) {
+ case TSDEV_PIC1_MASK:
+ mask1 = ~(pkt->get<uint8_t>());
+ if ((picr & mask1) && !picInterrupting) {
+ picInterrupting = true;
+ tsunami->cchip->postDRIR(55);
+ DPRINTF(Tsunami, "posting pic interrupt to cchip\n");
+ }
+ if ((!(picr & mask1)) && picInterrupting) {
+ picInterrupting = false;
+ tsunami->cchip->clearDRIR(55);
+ DPRINTF(Tsunami, "clearing pic interrupt\n");
+ }
+ break;
+ case TSDEV_PIC2_MASK:
+ mask2 = pkt->get<uint8_t>();
+ //PIC2 Not implemented to interrupt
+ break;
+ case TSDEV_PIC1_ACK:
+ // clear the interrupt on the PIC
+ picr &= ~(1 << (pkt->get<uint8_t>() & 0xF));
+ if (!(picr & mask1))
+ tsunami->cchip->clearDRIR(55);
+ break;
+ case TSDEV_DMA1_MODE:
+ mode1 = pkt->get<uint8_t>();
+ break;
+ case TSDEV_DMA2_MODE:
+ mode2 = pkt->get<uint8_t>();
+ break;
+ case TSDEV_TMR0_DATA:
+ pitimer.counter0.write(pkt->get<uint8_t>());
+ break;
+ case TSDEV_TMR1_DATA:
+ pitimer.counter1.write(pkt->get<uint8_t>());
+ break;
+ case TSDEV_TMR2_DATA:
+ pitimer.counter2.write(pkt->get<uint8_t>());
+ break;
+ case TSDEV_TMR_CTRL:
+ pitimer.writeControl(pkt->get<uint8_t>());
+ break;
+ case TSDEV_RTC_ADDR:
+ rtc.writeAddr(pkt->get<uint8_t>());
+ break;
+ case TSDEV_RTC_DATA:
+ rtc.writeData(pkt->get<uint8_t>());
+ break;
+ case TSDEV_KBD:
+ case TSDEV_DMA1_CMND:
+ case TSDEV_DMA2_CMND:
+ case TSDEV_DMA1_MMASK:
+ case TSDEV_DMA2_MMASK:
+ case TSDEV_PIC2_ACK:
+ case TSDEV_DMA1_RESET:
+ case TSDEV_DMA2_RESET:
+ case TSDEV_DMA1_MASK:
+ case TSDEV_DMA2_MASK:
+ case TSDEV_CTRL_PORTB:
+ break;
+ default:
+ panic("I/O Write - va%#x size %d data %#x\n", pkt->addr, pkt->size, pkt->get<uint8_t>());
+ }
+
+ pkt->result = Success;
+ return pioDelay;
+}
+
+void
+TsunamiIO::postPIC(uint8_t bitvector)
+{
+ //PIC2 Is not implemented, because nothing of interest there
+ picr |= bitvector;
+ if (picr & mask1) {
+ tsunami->cchip->postDRIR(55);
+ DPRINTF(Tsunami, "posting pic interrupt to cchip\n");
+ }
+}
+
+void
+TsunamiIO::clearPIC(uint8_t bitvector)
+{
+ //PIC2 Is not implemented, because nothing of interest there
+ picr &= ~bitvector;
+ if (!(picr & mask1)) {
+ tsunami->cchip->clearDRIR(55);
+ DPRINTF(Tsunami, "clearing pic interrupt to cchip\n");
+ }
+}
+
+void
+TsunamiIO::serialize(ostream &os)
+{
+ SERIALIZE_SCALAR(timerData);
+ SERIALIZE_SCALAR(mask1);
+ SERIALIZE_SCALAR(mask2);
+ SERIALIZE_SCALAR(mode1);
+ SERIALIZE_SCALAR(mode2);
+ SERIALIZE_SCALAR(picr);
+ SERIALIZE_SCALAR(picInterrupting);
+
+ // Serialize the timers
+ pitimer.serialize("pitimer", os);
+ rtc.serialize("rtc", os);
+}
+
+void
+TsunamiIO::unserialize(Checkpoint *cp, const string &section)
+{
+ UNSERIALIZE_SCALAR(timerData);
+ UNSERIALIZE_SCALAR(mask1);
+ UNSERIALIZE_SCALAR(mask2);
+ UNSERIALIZE_SCALAR(mode1);
+ UNSERIALIZE_SCALAR(mode2);
+ UNSERIALIZE_SCALAR(picr);
+ UNSERIALIZE_SCALAR(picInterrupting);
+
+ // Unserialize the timers
+ pitimer.unserialize("pitimer", cp, section);
+ rtc.unserialize("rtc", cp, section);
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
+
+ Param<Addr> pio_addr;
+ Param<Tick> pio_latency;
+ Param<Tick> frequency;
+ SimObjectParam<Platform *> platform;
+ SimObjectParam<System *> system;
+ Param<time_t> time;
+ SimObjectParam<Tsunami *> tsunami;
+
+END_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiIO)
+
+ INIT_PARAM(pio_addr, "Device Address"),
+ INIT_PARAM(pio_latency, "Programmed IO latency"),
+ INIT_PARAM(frequency, "clock interrupt frequency"),
+ INIT_PARAM(platform, "platform"),
+ INIT_PARAM(system, "system object"),
+ INIT_PARAM(time, "System time to use (0 for actual time"),
+ INIT_PARAM(tsunami, "Tsunami")
+
+END_INIT_SIM_OBJECT_PARAMS(TsunamiIO)
+
+CREATE_SIM_OBJECT(TsunamiIO)
+{
+ TsunamiIO::Params *p = new TsunamiIO::Params;
+ p->frequency = frequency;
+ p->name = getInstanceName();
+ p->pio_addr = pio_addr;
+ p->pio_delay = pio_latency;
+ p->platform = platform;
+ p->system = system;
+ p->init_time = time;
+ p->tsunami = tsunami;
+ return new TsunamiIO(p);
+}
+
+REGISTER_SIM_OBJECT("TsunamiIO", TsunamiIO)
diff --git a/src/dev/tsunami_io.hh b/src/dev/tsunami_io.hh
new file mode 100644
index 000000000..4e4fb2036
--- /dev/null
+++ b/src/dev/tsunami_io.hh
@@ -0,0 +1,351 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * Tsunami I/O Space mapping including RTC/timer interrupts
+ */
+
+#ifndef __DEV_TSUNAMI_IO_HH__
+#define __DEV_TSUNAMI_IO_HH__
+
+#include "dev/io_device.hh"
+#include "base/range.hh"
+#include "dev/tsunami.hh"
+#include "sim/eventq.hh"
+
+/**
+ * Tsunami I/O device is a catch all for all the south bridge stuff we care
+ * to implement.
+ */
+class TsunamiIO : public BasicPioDevice
+{
+ private:
+ struct tm tm;
+
+ protected:
+ /** Real-Time Clock (MC146818) */
+ class RTC
+ {
+ private:
+ /** Event for RTC periodic interrupt */
+ struct RTCEvent : public Event
+ {
+ /** A pointer back to tsunami to create interrupt the processor. */
+ Tsunami* tsunami;
+ Tick interval;
+
+ RTCEvent(Tsunami* t, Tick i);
+
+ /** Schedule the RTC periodic interrupt */
+ void scheduleIntr();
+
+ /** Event process to occur at interrupt*/
+ virtual void process();
+
+ /** Event description */
+ virtual const char *description();
+ };
+
+ private:
+ std::string _name;
+ const std::string &name() const { return _name; }
+
+ /** RTC periodic interrupt event */
+ RTCEvent event;
+
+ /** Current RTC register address/index */
+ int addr;
+
+ /** Data for real-time clock function */
+ union {
+ uint8_t clock_data[10];
+
+ struct {
+ uint8_t sec;
+ uint8_t sec_alrm;
+ uint8_t min;
+ uint8_t min_alrm;
+ uint8_t hour;
+ uint8_t hour_alrm;
+ uint8_t wday;
+ uint8_t mday;
+ uint8_t mon;
+ uint8_t year;
+ };
+ };
+
+ /** RTC status register A */
+ uint8_t stat_regA;
+
+ /** RTC status register B */
+ uint8_t stat_regB;
+
+ public:
+ RTC(const std::string &name, Tsunami* t, Tick i);
+
+ /** Set the initial RTC time/date */
+ void set_time(time_t t);
+
+ /** RTC address port: write address of RTC RAM data to access */
+ void writeAddr(const uint8_t data);
+
+ /** RTC write data */
+ void writeData(const uint8_t data);
+
+ /** RTC read data */
+ void readData(uint8_t *data);
+
+ /**
+ * Serialize this object to the given output stream.
+ * @param os The stream to serialize to.
+ */
+ void serialize(const std::string &base, std::ostream &os);
+
+ /**
+ * Reconstruct the state of this object from a checkpoint.
+ * @param cp The checkpoint use.
+ * @param section The section name of this object
+ */
+ void unserialize(const std::string &base, Checkpoint *cp,
+ const std::string &section);
+ };
+
+ /** Programmable Interval Timer (Intel 8254) */
+ class PITimer
+ {
+ /** Counter element for PIT */
+ class Counter
+ {
+ /** Event for counter interrupt */
+ class CounterEvent : public Event
+ {
+ private:
+ /** Pointer back to Counter */
+ Counter* counter;
+ Tick interval;
+
+ public:
+ CounterEvent(Counter*);
+
+ /** Event process */
+ virtual void process();
+
+ /** Event description */
+ virtual const char *description();
+
+ friend class Counter;
+ };
+
+ private:
+ std::string _name;
+ const std::string &name() const { return _name; }
+
+ CounterEvent event;
+
+ /** Current count value */
+ uint16_t count;
+
+ /** Latched count */
+ uint16_t latched_count;
+
+ /** Interrupt period */
+ uint16_t period;
+
+ /** Current mode of operation */
+ uint8_t mode;
+
+ /** Output goes high when the counter reaches zero */
+ bool output_high;
+
+ /** State of the count latch */
+ bool latch_on;
+
+ /** Set of values for read_byte and write_byte */
+ enum {LSB, MSB};
+
+ /** Determine which byte of a 16-bit count value to read/write */
+ uint8_t read_byte, write_byte;
+
+ public:
+ Counter(const std::string &name);
+
+ /** Latch the current count (if one is not already latched) */
+ void latchCount();
+
+ /** Set the read/write mode */
+ void setRW(int rw_val);
+
+ /** Set operational mode */
+ void setMode(int mode_val);
+
+ /** Set count encoding */
+ void setBCD(int bcd_val);
+
+ /** Read a count byte */
+ void read(uint8_t *data);
+
+ /** Write a count byte */
+ void write(const uint8_t data);
+
+ /** Is the output high? */
+ bool outputHigh();
+
+ /**
+ * Serialize this object to the given output stream.
+ * @param os The stream to serialize to.
+ */
+ void serialize(const std::string &base, std::ostream &os);
+
+ /**
+ * Reconstruct the state of this object from a checkpoint.
+ * @param cp The checkpoint use.
+ * @param section The section name of this object
+ */
+ void unserialize(const std::string &base, Checkpoint *cp,
+ const std::string &section);
+ };
+
+ private:
+ std::string _name;
+ const std::string &name() const { return _name; }
+
+ /** PIT has three seperate counters */
+ Counter *counter[3];
+
+ public:
+ /** Public way to access individual counters (avoid array accesses) */
+ Counter counter0;
+ Counter counter1;
+ Counter counter2;
+
+ PITimer(const std::string &name);
+
+ /** Write control word */
+ void writeControl(const uint8_t data);
+
+ /**
+ * Serialize this object to the given output stream.
+ * @param os The stream to serialize to.
+ */
+ void serialize(const std::string &base, std::ostream &os);
+
+ /**
+ * Reconstruct the state of this object from a checkpoint.
+ * @param cp The checkpoint use.
+ * @param section The section name of this object
+ */
+ void unserialize(const std::string &base, Checkpoint *cp,
+ const std::string &section);
+ };
+
+ /** Mask of the PIC1 */
+ uint8_t mask1;
+
+ /** Mask of the PIC2 */
+ uint8_t mask2;
+
+ /** Mode of PIC1. Not used for anything */
+ uint8_t mode1;
+
+ /** Mode of PIC2. Not used for anything */
+ uint8_t mode2;
+
+ /** Raw PIC interrupt register before masking */
+ uint8_t picr; //Raw PIC interrput register
+
+ /** Is the pic interrupting right now or not. */
+ bool picInterrupting;
+
+ /** A pointer to the Tsunami device which be belong to */
+ Tsunami *tsunami;
+
+ /** Intel 8253 Periodic Interval Timer */
+ PITimer pitimer;
+
+ RTC rtc;
+
+ /** The interval is set via two writes to the PIT.
+ * This variable contains a flag as to how many writes have happened, and
+ * the time so far.
+ */
+ uint16_t timerData;
+
+ public:
+ /**
+ * Return the freqency of the RTC
+ * @return interrupt rate of the RTC
+ */
+ Tick frequency() const;
+
+ struct Params : public BasicPioDevice::Params
+ {
+ Tick frequency;
+ Tsunami *tsunami;
+ time_t init_time;
+ };
+ protected:
+ const Params *params() const { return (const Params*)_params; }
+
+ public:
+ /**
+ * Initialize all the data for devices supported by Tsunami I/O.
+ * @param p pointer to Params struct
+ */
+ TsunamiIO(Params *p);
+
+ virtual Tick read(Packet *pkt);
+ virtual Tick write(Packet *pkt);
+
+ /**
+ * Post an PIC interrupt to the CPU via the CChip
+ * @param bitvector interrupt to post.
+ */
+ void postPIC(uint8_t bitvector);
+
+ /**
+ * Clear a posted interrupt
+ * @param bitvector interrupt to clear
+ */
+ void clearPIC(uint8_t bitvector);
+
+ /**
+ * Serialize this object to the given output stream.
+ * @param os The stream to serialize to.
+ */
+ virtual void serialize(std::ostream &os);
+
+ /**
+ * Reconstruct the state of this object from a checkpoint.
+ * @param cp The checkpoint use.
+ * @param section The section name of this object
+ */
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+
+};
+
+#endif // __DEV_TSUNAMI_IO_HH__
diff --git a/src/dev/tsunami_pchip.cc b/src/dev/tsunami_pchip.cc
new file mode 100644
index 000000000..999278e37
--- /dev/null
+++ b/src/dev/tsunami_pchip.cc
@@ -0,0 +1,358 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * Tsunami PChip (pci)
+ */
+
+#include <deque>
+#include <string>
+#include <vector>
+
+#include "base/trace.hh"
+#include "dev/tsunami_pchip.hh"
+#include "dev/tsunamireg.h"
+#include "dev/tsunami.hh"
+#include "mem/packet.hh"
+#include "sim/builder.hh"
+#include "sim/system.hh"
+
+using namespace std;
+//Should this be AlphaISA?
+using namespace TheISA;
+
+TsunamiPChip::TsunamiPChip(Params *p)
+: BasicPioDevice(p)
+{
+ pioSize = 0xfff;
+
+ for (int i = 0; i < 4; i++) {
+ wsba[i] = 0;
+ wsm[i] = 0;
+ tba[i] = 0;
+ }
+
+ // initialize pchip control register
+ pctl = (ULL(0x1) << 20) | (ULL(0x1) << 32) | (ULL(0x2) << 36);
+
+ //Set back pointer in tsunami
+ p->tsunami->pchip = this;
+}
+
+Tick
+TsunamiPChip::read(Packet *pkt)
+{
+ assert(pkt->result == Unknown);
+ assert(pkt->addr >= pioAddr && pkt->addr < pioAddr + pioSize);
+
+
+ pkt->time += pioDelay;
+ pkt->allocate();
+ Addr daddr = (pkt->addr - pioAddr) >> 6;;
+ assert(pkt->size == sizeof(uint64_t));
+
+
+ DPRINTF(Tsunami, "read va=%#x size=%d\n", pkt->addr, pkt->size);
+
+ switch(daddr) {
+ case TSDEV_PC_WSBA0:
+ pkt->set(wsba[0]);
+ break;
+ case TSDEV_PC_WSBA1:
+ pkt->set(wsba[1]);
+ break;
+ case TSDEV_PC_WSBA2:
+ pkt->set(wsba[2]);
+ break;
+ case TSDEV_PC_WSBA3:
+ pkt->set(wsba[3]);
+ break;
+ case TSDEV_PC_WSM0:
+ pkt->set(wsm[0]);
+ break;
+ case TSDEV_PC_WSM1:
+ pkt->set(wsm[1]);
+ break;
+ case TSDEV_PC_WSM2:
+ pkt->set(wsm[2]);
+ break;
+ case TSDEV_PC_WSM3:
+ pkt->set(wsm[3]);
+ break;
+ case TSDEV_PC_TBA0:
+ pkt->set(tba[0]);
+ break;
+ case TSDEV_PC_TBA1:
+ pkt->set(tba[1]);
+ break;
+ case TSDEV_PC_TBA2:
+ pkt->set(tba[2]);
+ break;
+ case TSDEV_PC_TBA3:
+ pkt->set(tba[3]);
+ break;
+ case TSDEV_PC_PCTL:
+ pkt->set(pctl);
+ break;
+ case TSDEV_PC_PLAT:
+ panic("PC_PLAT not implemented\n");
+ case TSDEV_PC_RES:
+ panic("PC_RES not implemented\n");
+ case TSDEV_PC_PERROR:
+ pkt->set((uint64_t)0x00);
+ break;
+ case TSDEV_PC_PERRMASK:
+ pkt->set((uint64_t)0x00);
+ break;
+ case TSDEV_PC_PERRSET:
+ panic("PC_PERRSET not implemented\n");
+ case TSDEV_PC_TLBIV:
+ panic("PC_TLBIV not implemented\n");
+ case TSDEV_PC_TLBIA:
+ pkt->set((uint64_t)0x00); // shouldn't be readable, but linux
+ break;
+ case TSDEV_PC_PMONCTL:
+ panic("PC_PMONCTL not implemented\n");
+ case TSDEV_PC_PMONCNT:
+ panic("PC_PMONCTN not implemented\n");
+ default:
+ panic("Default in PChip Read reached reading 0x%x\n", daddr);
+ }
+ pkt->result = Success;
+ return pioDelay;
+
+}
+
+Tick
+TsunamiPChip::write(Packet *pkt)
+{
+ pkt->time += pioDelay;
+
+ assert(pkt->result == Unknown);
+ assert(pkt->addr >= pioAddr && pkt->addr < pioAddr + pioSize);
+ Addr daddr = (pkt->addr - pioAddr) >> 6;
+
+ assert(pkt->size == sizeof(uint64_t));
+
+ DPRINTF(Tsunami, "write - va=%#x size=%d \n", pkt->addr, pkt->size);
+
+ switch(daddr) {
+ case TSDEV_PC_WSBA0:
+ wsba[0] = pkt->get<uint64_t>();
+ break;
+ case TSDEV_PC_WSBA1:
+ wsba[1] = pkt->get<uint64_t>();
+ break;
+ case TSDEV_PC_WSBA2:
+ wsba[2] = pkt->get<uint64_t>();
+ break;
+ case TSDEV_PC_WSBA3:
+ wsba[3] = pkt->get<uint64_t>();
+ break;
+ case TSDEV_PC_WSM0:
+ wsm[0] = pkt->get<uint64_t>();
+ break;
+ case TSDEV_PC_WSM1:
+ wsm[1] = pkt->get<uint64_t>();
+ break;
+ case TSDEV_PC_WSM2:
+ wsm[2] = pkt->get<uint64_t>();
+ break;
+ case TSDEV_PC_WSM3:
+ wsm[3] = pkt->get<uint64_t>();
+ break;
+ case TSDEV_PC_TBA0:
+ tba[0] = pkt->get<uint64_t>();
+ break;
+ case TSDEV_PC_TBA1:
+ tba[1] = pkt->get<uint64_t>();
+ break;
+ case TSDEV_PC_TBA2:
+ tba[2] = pkt->get<uint64_t>();
+ break;
+ case TSDEV_PC_TBA3:
+ tba[3] = pkt->get<uint64_t>();
+ break;
+ case TSDEV_PC_PCTL:
+ pctl = pkt->get<uint64_t>();
+ break;
+ case TSDEV_PC_PLAT:
+ panic("PC_PLAT not implemented\n");
+ case TSDEV_PC_RES:
+ panic("PC_RES not implemented\n");
+ case TSDEV_PC_PERROR:
+ break;
+ case TSDEV_PC_PERRMASK:
+ panic("PC_PERRMASK not implemented\n");
+ case TSDEV_PC_PERRSET:
+ panic("PC_PERRSET not implemented\n");
+ case TSDEV_PC_TLBIV:
+ panic("PC_TLBIV not implemented\n");
+ case TSDEV_PC_TLBIA:
+ break; // value ignored, supposted to invalidate SG TLB
+ case TSDEV_PC_PMONCTL:
+ panic("PC_PMONCTL not implemented\n");
+ case TSDEV_PC_PMONCNT:
+ panic("PC_PMONCTN not implemented\n");
+ default:
+ panic("Default in PChip write reached reading 0x%x\n", daddr);
+
+ } // uint64_t
+
+ pkt->result = Success;
+ return pioDelay;
+}
+
+#define DMA_ADDR_MASK ULL(0x3ffffffff)
+
+Addr
+TsunamiPChip::translatePciToDma(Addr busAddr)
+{
+ // compare the address to the window base registers
+ uint64_t tbaMask = 0;
+ uint64_t baMask = 0;
+
+ uint64_t windowMask = 0;
+ uint64_t windowBase = 0;
+
+ uint64_t pteEntry = 0;
+
+ Addr pteAddr;
+ Addr dmaAddr;
+
+#if 0
+ DPRINTF(IdeDisk, "Translation for bus address: %#x\n", busAddr);
+ for (int i = 0; i < 4; i++) {
+ DPRINTF(IdeDisk, "(%d) base:%#x mask:%#x\n",
+ i, wsba[i], wsm[i]);
+
+ windowBase = wsba[i];
+ windowMask = ~wsm[i] & (ULL(0xfff) << 20);
+
+ if ((busAddr & windowMask) == (windowBase & windowMask)) {
+ DPRINTF(IdeDisk, "Would have matched %d (wb:%#x wm:%#x --> ba&wm:%#x wb&wm:%#x)\n",
+ i, windowBase, windowMask, (busAddr & windowMask),
+ (windowBase & windowMask));
+ }
+ }
+#endif
+
+ for (int i = 0; i < 4; i++) {
+
+ windowBase = wsba[i];
+ windowMask = ~wsm[i] & (ULL(0xfff) << 20);
+
+ if ((busAddr & windowMask) == (windowBase & windowMask)) {
+
+ if (wsba[i] & 0x1) { // see if enabled
+ if (wsba[i] & 0x2) { // see if SG bit is set
+ /** @todo
+ This currently is faked by just doing a direct
+ read from memory, however, to be realistic, this
+ needs to actually do a bus transaction. The process
+ is explained in the tsunami documentation on page
+ 10-12 and basically munges the address to look up a
+ PTE from a table in memory and then uses that mapping
+ to create an address for the SG page
+ */
+
+ tbaMask = ~(((wsm[i] & (ULL(0xfff) << 20)) >> 10) | ULL(0x3ff));
+ baMask = (wsm[i] & (ULL(0xfff) << 20)) | (ULL(0x7f) << 13);
+ pteAddr = (tba[i] & tbaMask) | ((busAddr & baMask) >> 10);
+
+ pioPort->readBlob(pteAddr, (uint8_t*)&pteEntry, sizeof(uint64_t));
+
+ dmaAddr = ((pteEntry & ~ULL(0x1)) << 12) | (busAddr & ULL(0x1fff));
+
+ } else {
+ baMask = (wsm[i] & (ULL(0xfff) << 20)) | ULL(0xfffff);
+ tbaMask = ~baMask;
+ dmaAddr = (tba[i] & tbaMask) | (busAddr & baMask);
+ }
+
+ return (dmaAddr & DMA_ADDR_MASK);
+ }
+ }
+ }
+
+ // if no match was found, then return the original address
+ return busAddr;
+}
+
+void
+TsunamiPChip::serialize(std::ostream &os)
+{
+ SERIALIZE_SCALAR(pctl);
+ SERIALIZE_ARRAY(wsba, 4);
+ SERIALIZE_ARRAY(wsm, 4);
+ SERIALIZE_ARRAY(tba, 4);
+}
+
+void
+TsunamiPChip::unserialize(Checkpoint *cp, const std::string &section)
+{
+ UNSERIALIZE_SCALAR(pctl);
+ UNSERIALIZE_ARRAY(wsba, 4);
+ UNSERIALIZE_ARRAY(wsm, 4);
+ UNSERIALIZE_ARRAY(tba, 4);
+}
+
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiPChip)
+
+ Param<Addr> pio_addr;
+ Param<Tick> pio_latency;
+ SimObjectParam<Platform *> platform;
+ SimObjectParam<System *> system;
+ SimObjectParam<Tsunami *> tsunami;
+
+END_DECLARE_SIM_OBJECT_PARAMS(TsunamiPChip)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiPChip)
+
+ INIT_PARAM(pio_addr, "Device Address"),
+ INIT_PARAM(pio_latency, "Programmed IO latency"),
+ INIT_PARAM(platform, "platform"),
+ INIT_PARAM(system, "system object"),
+ INIT_PARAM(tsunami, "Tsunami")
+
+END_INIT_SIM_OBJECT_PARAMS(TsunamiPChip)
+
+CREATE_SIM_OBJECT(TsunamiPChip)
+{
+ TsunamiPChip::Params *p = new TsunamiPChip::Params;
+ p->name = getInstanceName();
+ p->pio_addr = pio_addr;
+ p->pio_delay = pio_latency;
+ p->platform = platform;
+ p->system = system;
+ p->tsunami = tsunami;
+ return new TsunamiPChip(p);
+}
+
+REGISTER_SIM_OBJECT("TsunamiPChip", TsunamiPChip)
diff --git a/src/dev/tsunami_pchip.hh b/src/dev/tsunami_pchip.hh
new file mode 100644
index 000000000..bb84339c9
--- /dev/null
+++ b/src/dev/tsunami_pchip.hh
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * Tsunami PCI interface CSRs
+ */
+
+#ifndef __TSUNAMI_PCHIP_HH__
+#define __TSUNAMI_PCHIP_HH__
+
+#include "dev/tsunami.hh"
+#include "base/range.hh"
+#include "dev/io_device.hh"
+
+/**
+ * A very simple implementation of the Tsunami PCI interface chips.
+ */
+class TsunamiPChip : public BasicPioDevice
+{
+ protected:
+ /** Pchip control register */
+ uint64_t pctl;
+
+ /** Window Base addresses */
+ uint64_t wsba[4];
+
+ /** Window masks */
+ uint64_t wsm[4];
+
+ /** Translated Base Addresses */
+ uint64_t tba[4];
+
+ public:
+ struct Params : public BasicPioDevice::Params
+ {
+ Tsunami *tsunami;
+ };
+ protected:
+ const Params *params() const { return (const Params*)_params; }
+
+ public:
+ /**
+ * Register the PChip with the mmu and init all wsba, wsm, and tba to 0
+ * @param p pointer to the parameters struct
+ */
+ TsunamiPChip(Params *p);
+
+ /**
+ * Translate a PCI bus address to a memory address for DMA.
+ * @todo Andrew says this needs to be fixed. What's wrong with it?
+ * @param busAddr PCI address to translate.
+ * @return memory system address
+ */
+ Addr translatePciToDma(Addr busAddr);
+
+ virtual Tick read(Packet *pkt);
+ virtual Tick write(Packet *pkt);
+
+ /**
+ * Serialize this object to the given output stream.
+ * @param os The stream to serialize to.
+ */
+ virtual void serialize(std::ostream &os);
+
+ /**
+ * Reconstruct the state of this object from a checkpoint.
+ * @param cp The checkpoint use.
+ * @param section The section name of this object
+ */
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+};
+
+#endif // __TSUNAMI_PCHIP_HH__
diff --git a/src/dev/tsunamireg.h b/src/dev/tsunamireg.h
new file mode 100644
index 000000000..a10259900
--- /dev/null
+++ b/src/dev/tsunamireg.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * List of Tsunami CSRs
+ */
+
+#ifndef __TSUNAMIREG_H__
+#define __TSUNAMIREG_H__
+
+#define ALPHA_K0SEG_BASE ULL(0xfffffc0000000000)
+
+// CChip Registers
+#define TSDEV_CC_CSR 0x00
+#define TSDEV_CC_MTR 0x01
+#define TSDEV_CC_MISC 0x02
+
+#define TSDEV_CC_AAR0 0x04
+#define TSDEV_CC_AAR1 0x05
+#define TSDEV_CC_AAR2 0x06
+#define TSDEV_CC_AAR3 0x07
+#define TSDEV_CC_DIM0 0x08
+#define TSDEV_CC_DIM1 0x09
+#define TSDEV_CC_DIR0 0x0A
+#define TSDEV_CC_DIR1 0x0B
+#define TSDEV_CC_DRIR 0x0C
+#define TSDEV_CC_PRBEN 0x0D
+#define TSDEV_CC_IIC0 0x0E
+#define TSDEV_CC_IIC1 0x0F
+#define TSDEV_CC_MPR0 0x10
+#define TSDEV_CC_MPR1 0x11
+#define TSDEV_CC_MPR2 0x12
+#define TSDEV_CC_MPR3 0x13
+
+#define TSDEV_CC_DIM2 0x18
+#define TSDEV_CC_DIM3 0x19
+#define TSDEV_CC_DIR2 0x1A
+#define TSDEV_CC_DIR3 0x1B
+#define TSDEV_CC_IIC2 0x1C
+#define TSDEV_CC_IIC3 0x1D
+
+// BigTsunami Registers
+#define TSDEV_CC_BDIMS 0x1000000
+#define TSDEV_CC_BDIRS 0x2000000
+#define TSDEV_CC_IPIQ 0x20 //0xf01a000800
+#define TSDEV_CC_IPIR 0x21 //0xf01a000840
+#define TSDEV_CC_ITIR 0x22 //0xf01a000880
+
+
+// PChip Registers
+#define TSDEV_PC_WSBA0 0x00
+#define TSDEV_PC_WSBA1 0x01
+#define TSDEV_PC_WSBA2 0x02
+#define TSDEV_PC_WSBA3 0x03
+#define TSDEV_PC_WSM0 0x04
+#define TSDEV_PC_WSM1 0x05
+#define TSDEV_PC_WSM2 0x06
+#define TSDEV_PC_WSM3 0x07
+#define TSDEV_PC_TBA0 0x08
+#define TSDEV_PC_TBA1 0x09
+#define TSDEV_PC_TBA2 0x0A
+#define TSDEV_PC_TBA3 0x0B
+#define TSDEV_PC_PCTL 0x0C
+#define TSDEV_PC_PLAT 0x0D
+#define TSDEV_PC_RES 0x0E
+#define TSDEV_PC_PERROR 0x0F
+#define TSDEV_PC_PERRMASK 0x10
+#define TSDEV_PC_PERRSET 0x11
+#define TSDEV_PC_TLBIV 0x12
+#define TSDEV_PC_TLBIA 0x13
+#define TSDEV_PC_PMONCTL 0x14
+#define TSDEV_PC_PMONCNT 0x15
+
+#define TSDEV_PC_SPST 0x20
+
+
+// DChip Registers
+#define TSDEV_DC_DSC 0x20
+#define TSDEV_DC_STR 0x21
+#define TSDEV_DC_DREV 0x22
+#define TSDEV_DC_DSC2 0x23
+
+// I/O Ports
+#define TSDEV_PIC1_MASK 0x21
+#define TSDEV_PIC2_MASK 0xA1
+#define TSDEV_PIC1_ISR 0x20
+#define TSDEV_PIC2_ISR 0xA0
+#define TSDEV_PIC1_ACK 0x20
+#define TSDEV_PIC2_ACK 0xA0
+#define TSDEV_DMA1_RESET 0x0D
+#define TSDEV_DMA2_RESET 0xDA
+#define TSDEV_DMA1_MODE 0x0B
+#define TSDEV_DMA2_MODE 0xD6
+#define TSDEV_DMA1_MASK 0x0A
+#define TSDEV_DMA2_MASK 0xD4
+#define TSDEV_CTRL_PORTB 0x61
+#define TSDEV_TMR0_DATA 0x40
+#define TSDEV_TMR1_DATA 0x41
+#define TSDEV_TMR2_DATA 0x42
+#define TSDEV_TMR_CTRL 0x43
+#define TSDEV_KBD 0x64
+#define TSDEV_DMA1_CMND 0x08
+#define TSDEV_DMA1_STAT TSDEV_DMA1_CMND
+#define TSDEV_DMA2_CMND 0xD0
+#define TSDEV_DMA2_STAT TSDEV_DMA2_CMND
+#define TSDEV_DMA1_MMASK 0x0F
+#define TSDEV_DMA2_MMASK 0xDE
+
+/* Added for keyboard accesses */
+#define TSDEV_KBD 0x64
+
+/* Added for ATA PCI DMA */
+#define ATA_PCI_DMA 0x00
+#define ATA_PCI_DMA2 0x02
+#define ATA_PCI_DMA3 0x16
+#define ATA_PCI_DMA4 0x17
+#define ATA_PCI_DMA5 0x1a
+#define ATA_PCI_DMA6 0x11
+#define ATA_PCI_DMA7 0x14
+
+#define TSDEV_RTC_ADDR 0x70
+#define TSDEV_RTC_DATA 0x71
+
+#define PCHIP_PCI0_MEMORY ULL(0x00000000000)
+#define PCHIP_PCI0_IO ULL(0x001FC000000)
+#define TSUNAMI_UNCACHABLE_BIT ULL(0x80000000000)
+#define TSUNAMI_PCI0_MEMORY TSUNAMI_UNCACHABLE_BIT + PCHIP_PCI0_MEMORY
+#define TSUNAMI_PCI0_IO TSUNAMI_UNCACHABLE_BIT + PCHIP_PCI0_IO
+
+
+// UART Defines
+#define UART_IER_RDI 0x01
+#define UART_IER_THRI 0x02
+#define UART_IER_RLSI 0x04
+
+
+#define UART_LSR_TEMT 0x40
+#define UART_LSR_THRE 0x20
+#define UART_LSR_DR 0x01
+
+#define UART_MCR_LOOP 0x10
+
+// System Control PortB Status Bits
+#define PORTB_SPKR_HIGH 0x20
+
+#endif // __TSUNAMIREG_H__
diff --git a/src/dev/uart.cc b/src/dev/uart.cc
new file mode 100644
index 000000000..4a9f2b505
--- /dev/null
+++ b/src/dev/uart.cc
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * Implements a base class for UARTs
+ */
+
+#include "dev/simconsole.hh"
+#include "dev/uart.hh"
+#include "dev/platform.hh"
+#include "sim/builder.hh"
+
+using namespace std;
+
+Uart::Uart(Params *p)
+ : BasicPioDevice(p), platform(p->platform), cons(p->cons)
+{
+
+ status = 0;
+
+ // set back pointers
+ cons->uart = this;
+ platform->uart = this;
+}
+
+DEFINE_SIM_OBJECT_CLASS_NAME("Uart", Uart)
+
diff --git a/src/dev/uart.hh b/src/dev/uart.hh
new file mode 100644
index 000000000..2dd15d9b8
--- /dev/null
+++ b/src/dev/uart.hh
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * Base class for UART
+ */
+
+#ifndef __UART_HH__
+#define __UART_HH__
+
+#include "base/range.hh"
+#include "dev/io_device.hh"
+
+class SimConsole;
+class Platform;
+
+const int RX_INT = 0x1;
+const int TX_INT = 0x2;
+
+
+class Uart : public BasicPioDevice
+{
+
+ protected:
+ int status;
+ Platform *platform;
+ SimConsole *cons;
+
+ public:
+ struct Params : public BasicPioDevice::Params
+ {
+ SimConsole *cons;
+ };
+
+ Uart(Params *p);
+
+ /**
+ * Inform the uart that there is data available.
+ */
+ virtual void dataAvailable() = 0;
+
+
+ /**
+ * Return if we have an interrupt pending
+ * @return interrupt status
+ */
+ bool intStatus() { return status ? true : false; }
+
+ protected:
+ const Params *params() const {return (const Params *)_params; }
+
+};
+
+#endif // __UART_HH__
diff --git a/src/dev/uart8250.cc b/src/dev/uart8250.cc
new file mode 100644
index 000000000..a4b30cf25
--- /dev/null
+++ b/src/dev/uart8250.cc
@@ -0,0 +1,366 @@
+/*
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * Implements a 8250 UART
+ */
+
+#include <string>
+#include <vector>
+
+#include "arch/alpha/ev5.hh"
+#include "base/inifile.hh"
+#include "base/str.hh" // for to_number
+#include "base/trace.hh"
+#include "dev/simconsole.hh"
+#include "dev/uart8250.hh"
+#include "dev/platform.hh"
+#include "sim/builder.hh"
+
+using namespace std;
+using namespace TheISA;
+
+Uart8250::IntrEvent::IntrEvent(Uart8250 *u, int bit)
+ : Event(&mainEventQueue), uart(u)
+{
+ DPRINTF(Uart, "UART Interrupt Event Initilizing\n");
+ intrBit = bit;
+}
+
+const char *
+Uart8250::IntrEvent::description()
+{
+ return "uart interrupt delay event";
+}
+
+void
+Uart8250::IntrEvent::process()
+{
+ if (intrBit & uart->IER) {
+ DPRINTF(Uart, "UART InterEvent, interrupting\n");
+ uart->platform->postConsoleInt();
+ uart->status |= intrBit;
+ }
+ else
+ DPRINTF(Uart, "UART InterEvent, not interrupting\n");
+
+}
+
+/* The linux serial driver (8250.c about line 1182) loops reading from
+ * the device until the device reports it has no more data to
+ * read. After a maximum of 255 iterations the code prints "serial8250
+ * too much work for irq X," and breaks out of the loop. Since the
+ * simulated system is so much slower than the actual system, if a
+ * user is typing on the keyboard it is very easy for them to provide
+ * input at a fast enough rate to not allow the loop to exit and thus
+ * the error to be printed. This magic number provides a delay between
+ * the time the UART receives a character to send to the simulated
+ * system and the time it actually notifies the system it has a
+ * character to send to alleviate this problem. --Ali
+ */
+void
+Uart8250::IntrEvent::scheduleIntr()
+{
+ static const Tick interval = (Tick)((Clock::Float::s / 2e9) * 450);
+ DPRINTF(Uart, "Scheduling IER interrupt for %#x, at cycle %lld\n", intrBit,
+ curTick + interval);
+ if (!scheduled())
+ schedule(curTick + interval);
+ else
+ reschedule(curTick + interval);
+}
+
+
+Uart8250::Uart8250(Params *p)
+ : Uart(p), txIntrEvent(this, TX_INT), rxIntrEvent(this, RX_INT)
+{
+ pioSize = 8;
+
+ IER = 0;
+ DLAB = 0;
+ LCR = 0;
+ MCR = 0;
+}
+
+Tick
+Uart8250::read(Packet *pkt)
+{
+ assert(pkt->result == Unknown);
+ assert(pkt->addr >= pioAddr && pkt->addr < pioAddr + pioSize);
+ assert(pkt->size == 1);
+
+ pkt->time += pioDelay;
+ Addr daddr = pkt->addr - pioAddr;
+ pkt->allocate();
+
+ DPRINTF(Uart, " read register %#x\n", daddr);
+
+ switch (daddr) {
+ case 0x0:
+ if (!(LCR & 0x80)) { // read byte
+ if (cons->dataAvailable())
+ cons->in(*pkt->getPtr<uint8_t>());
+ else {
+ pkt->set((uint8_t)0);
+ // A limited amount of these are ok.
+ DPRINTF(Uart, "empty read of RX register\n");
+ }
+ status &= ~RX_INT;
+ platform->clearConsoleInt();
+
+ if (cons->dataAvailable() && (IER & UART_IER_RDI))
+ rxIntrEvent.scheduleIntr();
+ } else { // dll divisor latch
+ ;
+ }
+ break;
+ case 0x1:
+ if (!(LCR & 0x80)) { // Intr Enable Register(IER)
+ pkt->set(IER);
+ } else { // DLM divisor latch MSB
+ ;
+ }
+ break;
+ case 0x2: // Intr Identification Register (IIR)
+ DPRINTF(Uart, "IIR Read, status = %#x\n", (uint32_t)status);
+
+ if (status & RX_INT) /* Rx data interrupt has a higher priority */
+ pkt->set(IIR_RXID);
+ else if (status & TX_INT)
+ pkt->set(IIR_TXID);
+ else
+ pkt->set(IIR_NOPEND);
+
+ //Tx interrupts are cleared on IIR reads
+ status &= ~TX_INT;
+ break;
+ case 0x3: // Line Control Register (LCR)
+ pkt->set(LCR);
+ break;
+ case 0x4: // Modem Control Register (MCR)
+ break;
+ case 0x5: // Line Status Register (LSR)
+ uint8_t lsr;
+ lsr = 0;
+ // check if there are any bytes to be read
+ if (cons->dataAvailable())
+ lsr = UART_LSR_DR;
+ lsr |= UART_LSR_TEMT | UART_LSR_THRE;
+ pkt->set(lsr);
+ break;
+ case 0x6: // Modem Status Register (MSR)
+ pkt->set((uint8_t)0);
+ break;
+ case 0x7: // Scratch Register (SCR)
+ pkt->set((uint8_t)0); // doesn't exist with at 8250.
+ break;
+ default:
+ panic("Tried to access a UART port that doesn't exist\n");
+ break;
+ }
+/* uint32_t d32 = *data;
+ DPRINTF(Uart, "Register read to register %#x returned %#x\n", daddr, d32);
+*/
+ pkt->result = Success;
+ return pioDelay;
+}
+
+Tick
+Uart8250::write(Packet *pkt)
+{
+
+ assert(pkt->result == Unknown);
+ assert(pkt->addr >= pioAddr && pkt->addr < pioAddr + pioSize);
+ assert(pkt->size == 1);
+
+ pkt->time += pioDelay;
+ Addr daddr = pkt->addr - pioAddr;
+
+ DPRINTF(Uart, " write register %#x value %#x\n", daddr, pkt->get<uint8_t>());
+
+ switch (daddr) {
+ case 0x0:
+ if (!(LCR & 0x80)) { // write byte
+ cons->out(pkt->get<uint8_t>());
+ platform->clearConsoleInt();
+ status &= ~TX_INT;
+ if (UART_IER_THRI & IER)
+ txIntrEvent.scheduleIntr();
+ } else { // dll divisor latch
+ ;
+ }
+ break;
+ case 0x1:
+ if (!(LCR & 0x80)) { // Intr Enable Register(IER)
+ IER = pkt->get<uint8_t>();
+ if (UART_IER_THRI & IER)
+ {
+ DPRINTF(Uart, "IER: IER_THRI set, scheduling TX intrrupt\n");
+ txIntrEvent.scheduleIntr();
+ }
+ else
+ {
+ DPRINTF(Uart, "IER: IER_THRI cleared, descheduling TX intrrupt\n");
+ if (txIntrEvent.scheduled())
+ txIntrEvent.deschedule();
+ if (status & TX_INT)
+ platform->clearConsoleInt();
+ status &= ~TX_INT;
+ }
+
+ if ((UART_IER_RDI & IER) && cons->dataAvailable()) {
+ DPRINTF(Uart, "IER: IER_RDI set, scheduling RX intrrupt\n");
+ rxIntrEvent.scheduleIntr();
+ } else {
+ DPRINTF(Uart, "IER: IER_RDI cleared, descheduling RX intrrupt\n");
+ if (rxIntrEvent.scheduled())
+ rxIntrEvent.deschedule();
+ if (status & RX_INT)
+ platform->clearConsoleInt();
+ status &= ~RX_INT;
+ }
+ } else { // DLM divisor latch MSB
+ ;
+ }
+ break;
+ case 0x2: // FIFO Control Register (FCR)
+ break;
+ case 0x3: // Line Control Register (LCR)
+ LCR = pkt->get<uint8_t>();
+ break;
+ case 0x4: // Modem Control Register (MCR)
+ if (pkt->get<uint8_t>() == (UART_MCR_LOOP | 0x0A))
+ MCR = 0x9A;
+ break;
+ case 0x7: // Scratch Register (SCR)
+ // We are emulating a 8250 so we don't have a scratch reg
+ break;
+ default:
+ panic("Tried to access a UART port that doesn't exist\n");
+ break;
+ }
+ pkt->result = Success;
+ return pioDelay;
+}
+
+void
+Uart8250::dataAvailable()
+{
+ // if the kernel wants an interrupt when we have data
+ if (IER & UART_IER_RDI)
+ {
+ platform->postConsoleInt();
+ status |= RX_INT;
+ }
+
+}
+
+void
+Uart8250::addressRanges(AddrRangeList &range_list)
+{
+ assert(pioSize != 0);
+ range_list.clear();
+ range_list.push_back(RangeSize(pioAddr, pioSize));
+}
+
+
+
+void
+Uart8250::serialize(ostream &os)
+{
+ SERIALIZE_SCALAR(status);
+ SERIALIZE_SCALAR(IER);
+ SERIALIZE_SCALAR(DLAB);
+ SERIALIZE_SCALAR(LCR);
+ SERIALIZE_SCALAR(MCR);
+ Tick rxintrwhen;
+ if (rxIntrEvent.scheduled())
+ rxintrwhen = rxIntrEvent.when();
+ else
+ rxintrwhen = 0;
+ Tick txintrwhen;
+ if (txIntrEvent.scheduled())
+ txintrwhen = txIntrEvent.when();
+ else
+ txintrwhen = 0;
+ SERIALIZE_SCALAR(rxintrwhen);
+ SERIALIZE_SCALAR(txintrwhen);
+}
+
+void
+Uart8250::unserialize(Checkpoint *cp, const std::string &section)
+{
+ UNSERIALIZE_SCALAR(status);
+ UNSERIALIZE_SCALAR(IER);
+ UNSERIALIZE_SCALAR(DLAB);
+ UNSERIALIZE_SCALAR(LCR);
+ UNSERIALIZE_SCALAR(MCR);
+ Tick rxintrwhen;
+ Tick txintrwhen;
+ UNSERIALIZE_SCALAR(rxintrwhen);
+ UNSERIALIZE_SCALAR(txintrwhen);
+ if (rxintrwhen != 0)
+ rxIntrEvent.schedule(rxintrwhen);
+ if (txintrwhen != 0)
+ txIntrEvent.schedule(txintrwhen);
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(Uart8250)
+
+ Param<Addr> pio_addr;
+ Param<Tick> pio_latency;
+ SimObjectParam<Platform *> platform;
+ SimObjectParam<SimConsole *> sim_console;
+ SimObjectParam<System *> system;
+
+END_DECLARE_SIM_OBJECT_PARAMS(Uart8250)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(Uart8250)
+
+ INIT_PARAM(pio_addr, "Device Address"),
+ INIT_PARAM_DFLT(pio_latency, "Programmed IO latency", 1000),
+ INIT_PARAM(platform, "platform"),
+ INIT_PARAM(sim_console, "The Simulator Console"),
+ INIT_PARAM(system, "system object")
+
+END_INIT_SIM_OBJECT_PARAMS(Uart8250)
+
+CREATE_SIM_OBJECT(Uart8250)
+{
+ Uart8250::Params *p = new Uart8250::Params;
+ p->name = getInstanceName();
+ p->pio_addr = pio_addr;
+ p->pio_delay = pio_latency;
+ p->platform = platform;
+ p->cons = sim_console;
+ p->system = system;
+ return new Uart8250(p);
+}
+
+REGISTER_SIM_OBJECT("Uart8250", Uart8250)
+
diff --git a/src/dev/uart8250.hh b/src/dev/uart8250.hh
new file mode 100644
index 000000000..4b7c2f1e4
--- /dev/null
+++ b/src/dev/uart8250.hh
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * Defines a 8250 UART
+ */
+
+#ifndef __DEV_UART8250_HH__
+#define __DEV_UART8250_HH__
+
+#include "dev/tsunamireg.h"
+#include "base/range.hh"
+#include "dev/io_device.hh"
+#include "dev/uart.hh"
+
+
+/* UART8250 Interrupt ID Register
+ * bit 0 Interrupt Pending 0 = true, 1 = false
+ * bit 2:1 ID of highest priority interrupt
+ * bit 7:3 zeroes
+ */
+const uint8_t IIR_NOPEND = 0x1;
+
+// Interrupt IDs
+const uint8_t IIR_MODEM = 0x00; /* Modem Status (lowest priority) */
+const uint8_t IIR_TXID = 0x02; /* Tx Data */
+const uint8_t IIR_RXID = 0x04; /* Rx Data */
+const uint8_t IIR_LINE = 0x06; /* Rx Line Status (highest priority)*/
+
+class SimConsole;
+class Platform;
+
+class Uart8250 : public Uart
+{
+
+
+ protected:
+ uint8_t IER, DLAB, LCR, MCR;
+
+ class IntrEvent : public Event
+ {
+ protected:
+ Uart8250 *uart;
+ int intrBit;
+ public:
+ IntrEvent(Uart8250 *u, int bit);
+ virtual void process();
+ virtual const char *description();
+ void scheduleIntr();
+ };
+
+ IntrEvent txIntrEvent;
+ IntrEvent rxIntrEvent;
+
+ public:
+ Uart8250(Params *p);
+
+ virtual Tick read(Packet *pkt);
+ virtual Tick write(Packet *pkt);
+ virtual void addressRanges(AddrRangeList &range_list);
+
+
+ /**
+ * Inform the uart that there is data available.
+ */
+ virtual void dataAvailable();
+
+
+ /**
+ * Return if we have an interrupt pending
+ * @return interrupt status
+ */
+ virtual bool intStatus() { return status ? true : false; }
+
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+
+};
+
+#endif // __TSUNAMI_UART_HH__
diff --git a/src/kern/kernel_stats.cc b/src/kern/kernel_stats.cc
new file mode 100644
index 000000000..b85d88145
--- /dev/null
+++ b/src/kern/kernel_stats.cc
@@ -0,0 +1,299 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <map>
+#include <stack>
+#include <string>
+
+#include "arch/alpha/osfpal.hh"
+#include "base/trace.hh"
+#include "cpu/exec_context.hh"
+#include "kern/kernel_stats.hh"
+#include "kern/tru64/tru64_syscalls.hh"
+#include "sim/system.hh"
+
+using namespace std;
+using namespace Stats;
+
+namespace Kernel {
+
+const char *modestr[] = { "kernel", "user", "idle", "interrupt" };
+
+Statistics::Statistics(System *system)
+ : idleProcess((Addr)-1), themode(kernel), lastModeTick(0),
+ iplLast(0), iplLastTick(0)
+{
+ bin_int = system->params()->bin_int;
+}
+
+void
+Statistics::regStats(const string &_name)
+{
+ myname = _name;
+
+ _arm
+ .name(name() + ".inst.arm")
+ .desc("number of arm instructions executed")
+ ;
+
+ _quiesce
+ .name(name() + ".inst.quiesce")
+ .desc("number of quiesce instructions executed")
+ ;
+
+ _ivlb
+ .name(name() + ".inst.ivlb")
+ .desc("number of ivlb instructions executed")
+ ;
+
+ _ivle
+ .name(name() + ".inst.ivle")
+ .desc("number of ivle instructions executed")
+ ;
+
+ _hwrei
+ .name(name() + ".inst.hwrei")
+ .desc("number of hwrei instructions executed")
+ ;
+
+ _iplCount
+ .init(32)
+ .name(name() + ".ipl_count")
+ .desc("number of times we switched to this ipl")
+ .flags(total | pdf | nozero | nonan)
+ ;
+
+ _iplGood
+ .init(32)
+ .name(name() + ".ipl_good")
+ .desc("number of times we switched to this ipl from a different ipl")
+ .flags(total | pdf | nozero | nonan)
+ ;
+
+ _iplTicks
+ .init(32)
+ .name(name() + ".ipl_ticks")
+ .desc("number of cycles we spent at this ipl")
+ .flags(total | pdf | nozero | nonan)
+ ;
+
+ _iplUsed
+ .name(name() + ".ipl_used")
+ .desc("fraction of swpipl calls that actually changed the ipl")
+ .flags(total | nozero | nonan)
+ ;
+
+ _iplUsed = _iplGood / _iplCount;
+
+ _callpal
+ .init(256)
+ .name(name() + ".callpal")
+ .desc("number of callpals executed")
+ .flags(total | pdf | nozero | nonan)
+ ;
+
+ for (int i = 0; i < PAL::NumCodes; ++i) {
+ const char *str = PAL::name(i);
+ if (str)
+ _callpal.subname(i, str);
+ }
+
+ _syscall
+ .init(SystemCalls<Tru64>::Number)
+ .name(name() + ".syscall")
+ .desc("number of syscalls executed")
+ .flags(total | pdf | nozero | nonan)
+ ;
+
+ for (int i = 0; i < SystemCalls<Tru64>::Number; ++i) {
+ const char *str = SystemCalls<Tru64>::name(i);
+ if (str) {
+ _syscall.subname(i, str);
+ }
+ }
+
+ _mode
+ .init(cpu_mode_num)
+ .name(name() + ".mode_switch")
+ .desc("number of protection mode switches")
+ ;
+
+ for (int i = 0; i < cpu_mode_num; ++i)
+ _mode.subname(i, modestr[i]);
+
+ _modeGood
+ .init(cpu_mode_num)
+ .name(name() + ".mode_good")
+ ;
+
+ for (int i = 0; i < cpu_mode_num; ++i)
+ _modeGood.subname(i, modestr[i]);
+
+ _modeFraction
+ .name(name() + ".mode_switch_good")
+ .desc("fraction of useful protection mode switches")
+ .flags(total)
+ ;
+
+ for (int i = 0; i < cpu_mode_num; ++i)
+ _modeFraction.subname(i, modestr[i]);
+
+ _modeFraction = _modeGood / _mode;
+
+ _modeTicks
+ .init(cpu_mode_num)
+ .name(name() + ".mode_ticks")
+ .desc("number of ticks spent at the given mode")
+ .flags(pdf)
+ ;
+ for (int i = 0; i < cpu_mode_num; ++i)
+ _modeTicks.subname(i, modestr[i]);
+
+ _swap_context
+ .name(name() + ".swap_context")
+ .desc("number of times the context was actually changed")
+ ;
+}
+
+void
+Statistics::setIdleProcess(Addr idlepcbb, ExecContext *xc)
+{
+ assert(themode == kernel || themode == interrupt);
+ idleProcess = idlepcbb;
+ themode = idle;
+ changeMode(themode, xc);
+}
+
+void
+Statistics::changeMode(cpu_mode newmode, ExecContext *xc)
+{
+ _mode[newmode]++;
+
+ if (newmode == themode)
+ return;
+
+ DPRINTF(Context, "old mode=%-8s new mode=%-8s\n",
+ modestr[themode], modestr[newmode]);
+
+ _modeGood[newmode]++;
+ _modeTicks[themode] += curTick - lastModeTick;
+
+ xc->getSystemPtr()->kernelBinning->changeMode(newmode);
+
+ lastModeTick = curTick;
+ themode = newmode;
+}
+
+void
+Statistics::swpipl(int ipl)
+{
+ assert(ipl >= 0 && ipl <= 0x1f && "invalid IPL\n");
+
+ _iplCount[ipl]++;
+
+ if (ipl == iplLast)
+ return;
+
+ _iplGood[ipl]++;
+ _iplTicks[iplLast] += curTick - iplLastTick;
+ iplLastTick = curTick;
+ iplLast = ipl;
+}
+
+void
+Statistics::mode(cpu_mode newmode, ExecContext *xc)
+{
+ Addr pcbb = xc->readMiscReg(AlphaISA::IPR_PALtemp23);
+
+ if ((newmode == kernel || newmode == interrupt) &&
+ pcbb == idleProcess)
+ newmode = idle;
+
+ if (bin_int == false && newmode == interrupt)
+ newmode = kernel;
+
+ changeMode(newmode, xc);
+}
+
+void
+Statistics::context(Addr oldpcbb, Addr newpcbb, ExecContext *xc)
+{
+ assert(themode != user);
+
+ _swap_context++;
+ changeMode(newpcbb == idleProcess ? idle : kernel, xc);
+}
+
+void
+Statistics::callpal(int code, ExecContext *xc)
+{
+ if (!PAL::name(code))
+ return;
+
+ _callpal[code]++;
+
+ switch (code) {
+ case PAL::callsys: {
+ int number = xc->readIntReg(0);
+ if (SystemCalls<Tru64>::validSyscallNumber(number)) {
+ int cvtnum = SystemCalls<Tru64>::convert(number);
+ _syscall[cvtnum]++;
+ }
+ } break;
+
+ case PAL::swpctx:
+ if (xc->getSystemPtr()->kernelBinning)
+ xc->getSystemPtr()->kernelBinning->palSwapContext(xc);
+ break;
+ }
+}
+
+void
+Statistics::serialize(ostream &os)
+{
+ int exemode = themode;
+ SERIALIZE_SCALAR(exemode);
+ SERIALIZE_SCALAR(idleProcess);
+ SERIALIZE_SCALAR(iplLast);
+ SERIALIZE_SCALAR(iplLastTick);
+ SERIALIZE_SCALAR(lastModeTick);
+}
+
+void
+Statistics::unserialize(Checkpoint *cp, const string &section)
+{
+ int exemode;
+ UNSERIALIZE_SCALAR(exemode);
+ UNSERIALIZE_SCALAR(idleProcess);
+ UNSERIALIZE_SCALAR(iplLast);
+ UNSERIALIZE_SCALAR(iplLastTick);
+ UNSERIALIZE_SCALAR(lastModeTick);
+ themode = (cpu_mode)exemode;
+}
+
+/* end namespace Kernel */ }
diff --git a/src/kern/kernel_stats.hh b/src/kern/kernel_stats.hh
new file mode 100644
index 000000000..16ec721d0
--- /dev/null
+++ b/src/kern/kernel_stats.hh
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __KERNEL_STATS_HH__
+#define __KERNEL_STATS_HH__
+
+#include <map>
+#include <stack>
+#include <string>
+#include <vector>
+
+#include "cpu/static_inst.hh"
+
+class BaseCPU;
+class ExecContext;
+class FnEvent;
+// What does kernel stats expect is included?
+class System;
+
+namespace Kernel {
+
+enum cpu_mode { kernel, user, idle, interrupt, cpu_mode_num };
+extern const char *modestr[];
+
+class Binning
+{
+ private:
+ std::string myname;
+ System *system;
+
+ private:
+ // lisa's binning stuff
+ struct fnCall
+ {
+ Stats::MainBin *myBin;
+ std::string name;
+ };
+
+ struct SWContext
+ {
+ Counter calls;
+ std::stack<fnCall *> callStack;
+ };
+
+ std::map<const std::string, Stats::MainBin *> fnBins;
+ std::map<const Addr, SWContext *> swCtxMap;
+
+ std::multimap<const std::string, std::string> callerMap;
+ void populateMap(std::string caller, std::string callee);
+
+ std::vector<FnEvent *> fnEvents;
+
+ Stats::Scalar<> fnCalls;
+
+ Stats::MainBin *getBin(const std::string &name);
+ bool findCaller(std::string, std::string) const;
+
+ SWContext *findContext(Addr pcb);
+ bool addContext(Addr pcb, SWContext *ctx)
+ {
+ return (swCtxMap.insert(std::make_pair(pcb, ctx))).second;
+ }
+
+ void remContext(Addr pcb)
+ {
+ swCtxMap.erase(pcb);
+ }
+
+ void dumpState() const;
+
+ SWContext *swctx;
+ std::vector<std::string> binned_fns;
+
+ private:
+ Stats::MainBin *modeBin[cpu_mode_num];
+
+ public:
+ const bool bin;
+ const bool fnbin;
+
+ cpu_mode themode;
+ void palSwapContext(ExecContext *xc);
+ void execute(ExecContext *xc, StaticInstPtr inst);
+ void call(ExecContext *xc, Stats::MainBin *myBin);
+ void changeMode(cpu_mode mode);
+
+ public:
+ Binning(System *sys);
+ virtual ~Binning();
+
+ const std::string name() const { return myname; }
+ void regStats(const std::string &name);
+
+ public:
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+};
+
+class Statistics : public Serializable
+{
+ private:
+ friend class Binning;
+
+ private:
+ std::string myname;
+
+ Addr idleProcess;
+ cpu_mode themode;
+ Tick lastModeTick;
+ bool bin_int;
+
+ void changeMode(cpu_mode newmode, ExecContext *xc);
+
+ private:
+ Stats::Scalar<> _arm;
+ Stats::Scalar<> _quiesce;
+ Stats::Scalar<> _ivlb;
+ Stats::Scalar<> _ivle;
+ Stats::Scalar<> _hwrei;
+
+ Stats::Vector<> _iplCount;
+ Stats::Vector<> _iplGood;
+ Stats::Vector<> _iplTicks;
+ Stats::Formula _iplUsed;
+
+ Stats::Vector<> _callpal;
+ Stats::Vector<> _syscall;
+// Stats::Vector<> _faults;
+
+ Stats::Vector<> _mode;
+ Stats::Vector<> _modeGood;
+ Stats::Formula _modeFraction;
+ Stats::Vector<> _modeTicks;
+
+ Stats::Scalar<> _swap_context;
+
+ private:
+ int iplLast;
+ Tick iplLastTick;
+
+ public:
+ Statistics(System *system);
+
+ const std::string name() const { return myname; }
+ void regStats(const std::string &name);
+
+ public:
+ void arm() { _arm++; }
+ void quiesce() { _quiesce++; }
+ void ivlb() { _ivlb++; }
+ void ivle() { _ivle++; }
+ void hwrei() { _hwrei++; }
+ void swpipl(int ipl);
+ void mode(cpu_mode newmode, ExecContext *xc);
+ void context(Addr oldpcbb, Addr newpcbb, ExecContext *xc);
+ void callpal(int code, ExecContext *xc);
+
+ void setIdleProcess(Addr idle, ExecContext *xc);
+
+ public:
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+};
+
+/* end namespace Kernel */ }
+
+#endif // __KERNEL_STATS_HH__
diff --git a/src/kern/linux/events.cc b/src/kern/linux/events.cc
new file mode 100644
index 000000000..b688e9dd0
--- /dev/null
+++ b/src/kern/linux/events.cc
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2004-2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "arch/arguments.hh"
+#include "base/trace.hh"
+#include "cpu/exec_context.hh"
+#include "kern/linux/events.hh"
+#include "kern/linux/printk.hh"
+#include "kern/system_events.hh"
+#include "sim/system.hh"
+
+
+namespace Linux {
+
+void
+DebugPrintkEvent::process(ExecContext *xc)
+{
+ if (DTRACE(DebugPrintf)) {
+ if (!raw) {
+ StringWrap name(xc->getSystemPtr()->name() + ".dprintk");
+ DPRINTFN("");
+ }
+
+ AlphaISA::AlphaArguments args(xc);
+ Printk(args);
+ SkipFuncEvent::process(xc);
+ }
+}
+
+} // namespace linux
diff --git a/src/kern/linux/events.hh b/src/kern/linux/events.hh
new file mode 100644
index 000000000..95c268976
--- /dev/null
+++ b/src/kern/linux/events.hh
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2004-2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __KERN_LINUX_EVENTS_HH__
+#define __KERN_LINUX_EVENTS_HH__
+
+#include "kern/system_events.hh"
+
+namespace Linux {
+
+class DebugPrintkEvent : public SkipFuncEvent
+{
+ private:
+ bool raw;
+
+ public:
+ DebugPrintkEvent(PCEventQueue *q, const std::string &desc, Addr addr,
+ bool r = false)
+ : SkipFuncEvent(q, desc, addr), raw(r) {}
+ virtual void process(ExecContext *xc);
+};
+
+}
+
+#endif
diff --git a/src/kern/linux/linux.hh b/src/kern/linux/linux.hh
new file mode 100644
index 000000000..63e0dd5ca
--- /dev/null
+++ b/src/kern/linux/linux.hh
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __LINUX_HH__
+#define __LINUX_HH__
+#include "config/full_system.hh"
+
+#if FULL_SYSTEM
+
+class Linux {};
+
+#else //!FULL_SYSTEM
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h> // for host open() flags
+#include <string.h> // for memset()
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "arch/isa_traits.hh"
+#include "sim/syscall_emul.hh"
+
+class TranslatingPort;
+
+///
+/// This class encapsulates the types, structures, constants,
+/// functions, and syscall-number mappings specific to the Alpha Linux
+/// syscall interface.
+///
+class Linux {
+
+ public:
+
+ //@{
+ /// Basic Linux types.
+ typedef uint64_t size_t;
+ typedef uint64_t off_t;
+ typedef int64_t time_t;
+ typedef uint32_t uid_t;
+ typedef uint32_t gid_t;
+ //@}
+
+#if BSD_HOST
+ typedef struct stat hst_stat;
+ typedef struct stat hst_stat64;
+#else
+ typedef struct stat hst_stat ;
+ typedef struct stat64 hst_stat64;
+#endif
+
+ /// Stat buffer. Note that we can't call it 'stat' since that
+ /// gets #defined to something else on some systems.
+ struct tgt_stat {
+ uint32_t st_dev; //!< device
+ uint32_t st_ino; //!< inode
+ uint32_t st_mode; //!< mode
+ uint32_t st_nlink; //!< link count
+ uint32_t st_uid; //!< owner's user ID
+ uint32_t st_gid; //!< owner's group ID
+ uint32_t st_rdev; //!< device number
+ int32_t _pad1; //!< for alignment
+ int64_t st_size; //!< file size in bytes
+ uint64_t st_atimeX; //!< time of last access
+ uint64_t st_mtimeX; //!< time of last modification
+ uint64_t st_ctimeX; //!< time of last status change
+ uint32_t st_blksize; //!< optimal I/O block size
+ int32_t st_blocks; //!< number of blocks allocated
+ uint32_t st_flags; //!< flags
+ uint32_t st_gen; //!< unknown
+ };
+
+ // same for stat64
+ struct tgt_stat64 {
+ uint64_t st_dev;
+ uint64_t st_ino;
+ uint64_t st_rdev;
+ int64_t st_size;
+ uint64_t st_blocks;
+
+ uint32_t st_mode;
+ uint32_t st_uid;
+ uint32_t st_gid;
+ uint32_t st_blksize;
+ uint32_t st_nlink;
+ uint32_t __pad0;
+
+ uint64_t tgt_st_atime;
+ uint64_t st_atime_nsec;
+ uint64_t tgt_st_mtime;
+ uint64_t st_mtime_nsec;
+ uint64_t tgt_st_ctime;
+ uint64_t st_ctime_nsec;
+ int64_t ___unused[3];
+ };
+
+ /// Length of strings in struct utsname (plus 1 for null char).
+ static const int _SYS_NMLN = 65;
+
+ /// Interface struct for uname().
+ struct utsname {
+ char sysname[_SYS_NMLN]; //!< System name.
+ char nodename[_SYS_NMLN]; //!< Node name.
+ char release[_SYS_NMLN]; //!< OS release.
+ char version[_SYS_NMLN]; //!< OS version.
+ char machine[_SYS_NMLN]; //!< Machine type.
+ };
+
+ /// Limit struct for getrlimit/setrlimit.
+ struct rlimit {
+ uint64_t rlim_cur; //!< soft limit
+ uint64_t rlim_max; //!< hard limit
+ };
+
+ /// For gettimeofday().
+ struct timeval {
+ int64_t tv_sec; //!< seconds
+ int64_t tv_usec; //!< microseconds
+ };
+
+ // For writev/readv
+ struct tgt_iovec {
+ uint64_t iov_base; // void *
+ uint64_t iov_len;
+ };
+
+
+ /// For getrusage().
+ struct rusage {
+ struct timeval ru_utime; //!< user time used
+ struct timeval ru_stime; //!< system time used
+ int64_t ru_maxrss; //!< max rss
+ int64_t ru_ixrss; //!< integral shared memory size
+ int64_t ru_idrss; //!< integral unshared data "
+ int64_t ru_isrss; //!< integral unshared stack "
+ int64_t ru_minflt; //!< page reclaims - total vmfaults
+ int64_t ru_majflt; //!< page faults
+ int64_t ru_nswap; //!< swaps
+ int64_t ru_inblock; //!< block input operations
+ int64_t ru_oublock; //!< block output operations
+ int64_t ru_msgsnd; //!< messages sent
+ int64_t ru_msgrcv; //!< messages received
+ int64_t ru_nsignals; //!< signals received
+ int64_t ru_nvcsw; //!< voluntary context switches
+ int64_t ru_nivcsw; //!< involuntary "
+ };
+
+ /// Helper function to convert a host stat buffer to a target stat
+ /// buffer. Also copies the target buffer out to the simulated
+ /// memory space. Used by stat(), fstat(), and lstat().
+#if !BSD_HOST
+ static void
+ copyOutStatBuf(TranslatingPort *mem, Addr addr, hst_stat *host)
+ {
+ using namespace TheISA;
+
+ TypedBufferArg<Linux::tgt_stat> tgt(addr);
+
+ tgt->st_dev = htog(host->st_dev);
+ tgt->st_ino = htog(host->st_ino);
+ tgt->st_mode = htog(host->st_mode);
+ tgt->st_nlink = htog(host->st_nlink);
+ tgt->st_uid = htog(host->st_uid);
+ tgt->st_gid = htog(host->st_gid);
+ tgt->st_rdev = htog(host->st_rdev);
+ tgt->st_size = htog(host->st_size);
+ tgt->st_atimeX = htog(host->st_atime);
+ tgt->st_mtimeX = htog(host->st_mtime);
+ tgt->st_ctimeX = htog(host->st_ctime);
+ tgt->st_blksize = htog(host->st_blksize);
+ tgt->st_blocks = htog(host->st_blocks);
+
+ tgt.copyOut(mem);
+ }
+#else
+ // Third version for bsd systems which no longer have any support for
+ // the old stat() call and stat() is actually a stat64()
+ static void
+ copyOutStatBuf(TranslatingPort *mem, Addr addr, hst_stat64 *host)
+ {
+ using namespace TheISA;
+
+ TypedBufferArg<Linux::tgt_stat> tgt(addr);
+
+ tgt->st_dev = htog(host->st_dev);
+ tgt->st_ino = htog(host->st_ino);
+ tgt->st_mode = htog(host->st_mode);
+ tgt->st_nlink = htog(host->st_nlink);
+ tgt->st_uid = htog(host->st_uid);
+ tgt->st_gid = htog(host->st_gid);
+ tgt->st_rdev = htog(host->st_rdev);
+ tgt->st_size = htog(host->st_size);
+ tgt->st_atimeX = htog(host->st_atime);
+ tgt->st_mtimeX = htog(host->st_mtime);
+ tgt->st_ctimeX = htog(host->st_ctime);
+ tgt->st_blksize = htog(host->st_blksize);
+ tgt->st_blocks = htog(host->st_blocks);
+
+ tgt.copyOut(mem);
+ }
+#endif
+
+
+ // Same for stat64
+ static void
+ copyOutStat64Buf(TranslatingPort *mem, int fd, Addr addr, hst_stat64 *host)
+ {
+ using namespace TheISA;
+
+ TypedBufferArg<Linux::tgt_stat64> tgt(addr);
+
+ // fd == 1 checks are because libc does some checks
+ // that the stdout is interactive vs. a file
+ // this makes it work on non-linux systems
+ if (fd == 1)
+ tgt->st_dev = htog((uint64_t)0xA);
+ else
+ tgt->st_dev = htog((uint64_t)host->st_dev);
+ // XXX What about STAT64_HAS_BROKEN_ST_INO ???
+ tgt->st_ino = htog((uint64_t)host->st_ino);
+ if (fd == 1)
+ tgt->st_rdev = htog((uint64_t)0x880d);
+ else
+ tgt->st_rdev = htog((uint64_t)host->st_rdev);
+ tgt->st_size = htog((int64_t)host->st_size);
+ tgt->st_blocks = htog((uint64_t)host->st_blocks);
+
+ if (fd == 1)
+ tgt->st_mode = htog((uint32_t)0x2190);
+ else
+ tgt->st_mode = htog((uint32_t)host->st_mode);
+ tgt->st_uid = htog((uint32_t)host->st_uid);
+ tgt->st_gid = htog((uint32_t)host->st_gid);
+ tgt->st_blksize = htog((uint32_t)host->st_blksize);
+ tgt->st_nlink = htog((uint32_t)host->st_nlink);
+ tgt->tgt_st_atime = htog((uint64_t)host->st_atime);
+ tgt->tgt_st_mtime = htog((uint64_t)host->st_mtime);
+ tgt->tgt_st_ctime = htog((uint64_t)host->st_ctime);
+#if defined(STAT_HAVE_NSEC)
+ tgt->st_atime_nsec = htog(host->st_atime_nsec);
+ tgt->st_mtime_nsec = htog(host->st_mtime_nsec);
+ tgt->st_ctime_nsec = htog(host->st_ctime_nsec);
+#else
+ tgt->st_atime_nsec = 0;
+ tgt->st_mtime_nsec = 0;
+ tgt->st_ctime_nsec = 0;
+#endif
+
+ tgt.copyOut(mem);
+ }
+
+}; // class Linux
+
+
+#endif // FULL_SYSTEM
+
+#endif // __LINUX_HH__
diff --git a/src/kern/linux/linux_syscalls.cc b/src/kern/linux/linux_syscalls.cc
new file mode 100644
index 000000000..c85b6d28f
--- /dev/null
+++ b/src/kern/linux/linux_syscalls.cc
@@ -0,0 +1,374 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "kern/linux/linux_syscalls.hh"
+
+namespace {
+ const char *
+ standard_strings[SystemCalls<Linux>::Number] = {
+
+
+ "llseek", //0
+ "newselect", //1
+ "sysctl", //2
+ "access", //3
+ "acct", //4
+ "adjtimex", //5
+ "afs_syscall", //6
+ "alarm", //7
+ "bdflush", //8
+ "break", //9
+
+
+ "brk", //10
+ "capget", //11
+ "capset", //12
+ "chdir", //13
+ "chmod", //14
+ "chown", //15
+ "chown32", //16
+ "chroot", //17
+ "clock_getres", //18
+ "clock_gettime", //19
+
+
+ "clock_nanosleep", //20
+ "clock_settime", //21
+ "clone", //22
+ "close", //23
+ "creat", //24
+ "create_module", //25
+ "delete_module", //26
+ "dup", //27
+ "dup2", //28
+ "epoll_create", //29
+
+
+ "epoll_ctl", //30
+ "epoll_wait", //31
+ "execve", //32
+ "exit", //33
+ "exit_group", //34
+ "fadvise64", //35
+ "fadvise64_64", //36
+ "fchdir", //37
+ "fchmod", //38
+ "fchown", //39
+
+
+ "fchown32", //40
+ "fcntl", //41
+ "fcntl64", //42
+ "fdatasync", //43
+ "fgetxattr", //44
+ "flistxattr", //45
+ "flock", //46
+ "fork", //47
+ "fremovexattr", //48
+ "fsetxattr", //49
+
+
+ "fstat", //50
+ "fstat64", //51
+ "fstatfs", //52
+ "fstatfs64", //53
+ "fsync", //54
+ "ftime", //55
+ "ftruncate", //56
+ "ftruncate64", //57
+ "futex", //58
+ "get_kernel_syms", //59
+
+
+ "get_thread_area", //60
+ "getcwd", //61
+ "getdents", //62
+ "getdents64", //63
+ "getegid", //64
+ "getegid32", //65
+ "geteuid", //66
+ "geteuid32", //67
+ "getgid", //68
+ "getgid32", //69
+
+
+ "getgroups", //70
+ "getgroups32", //71
+ "getitimer", //72
+ "getpgid", //73
+ "getpgrp", //74
+ "getpid", //75
+ "getpmsg", //76
+ "getppid", //77
+ "getpriority", //78
+ "getresgid", //79
+
+
+ "getresgid32", //80
+ "getresuid", //81
+ "getresuid32", //82
+ "getrlimit", //83
+ "getrusage", //84
+ "getsid", //85
+ "gettid", //86
+ "gettimeofday", //87
+ "getuid", //88
+ "getuid32", //89
+
+
+ "getxattr", //90
+ "gtty", //91
+ "idle", //92
+ "init_module", //93
+ "io_cancel", //94
+ "io_destroy", //95
+ "io_getevents", //96
+ "io_setup", //97
+ "io_submit", //98
+ "ioctl", //99
+
+
+ "ioperm", //100
+ "iopl", //101
+ "ipc", //102
+ "kill", //103
+ "lchown", //104
+ "lchown32", //105
+ "lgetxattr", //106
+ "link", //107
+ "listxattr", //108
+ "llistxattr", //109
+
+
+ "lock", //110
+ "lookup_dcookie", //111
+ "lremovexattr", //112
+ "lseek", //113
+ "lsetxattr", //114
+ "lstat", //115
+ "lstat64", //116
+ "madvise", //117
+ "madvise1", //118
+ "mincore", //119
+
+
+ "mkdir", //120
+ "mknod", //121
+ "mlock", //122
+ "mlockall", //123
+ "mmap", //124
+ "mmap2", //125
+ "modify_ldt", //126
+ "mount", //127
+ "mprotect", //128
+ "mpx", //129
+
+
+ "mremap", //130
+ "msync", //131
+ "munlock", //132
+ "munlockall", //133
+ "munmap", //134
+ "nanosleep", //135
+ "nfsservctl", //136
+ "nice", //137
+ "oldfstat", //138
+ "oldlstat", //139
+
+
+ "oldolduname", //140
+ "oldstat", //141
+ "olduname", //142
+ "open", //143
+ "pause", //144
+ "personality", //145
+ "pipe", //146
+ "pivot_root", //147
+ "poll", //148
+ "prctl", //149
+
+
+ "pread64", //150
+ "prof", //151
+ "profil", //152
+ "ptrace", //153
+ "putpmsg", //154
+ "pwrite64", //155
+ "query_module", //156
+ "quotactl", //157
+ "read", //158
+ "readahead", //159
+
+
+ "readdir", //160
+ "readlink", //161
+ "readv", //162
+ "reboot", //163
+ "remap_file_pages", //164
+ "removexattr", //165
+ "rename", //166
+ "restart_syscall", //167
+ "rmdir", //168
+ "rt_sigaction", //169
+
+
+ "rt_sigpending", //170
+ "rt_sigprocmask", //171
+ "rt_sigqueueinfo", //172
+ "rt_sigreturn", //173
+ "rt_sigsuspend", //174
+ "rt_sigtimedwait", //175
+ "sched_get_priority_max", //176
+ "sched_get_priority_min", //177
+ "sched_getaffinity", //178
+ "sched_getparam", //179
+
+
+ "sched_getscheduler", //180
+ "sched_rr_get_interval", //181
+ "sched_setaffinity", //182
+ "sched_setparam", //183
+ "sched_setscheduler", //184
+ "sched_yield", //185
+ "select", //186
+ "sendfile", //187
+ "sendfile64", //188
+ "set_thread_area", //189
+
+
+ "set_tid_address", //190
+ "setdomainname", //191
+ "setfsgid", //192
+ "setfsgid32", //193
+ "setfsuid", //194
+ "setfsuid32", //195
+ "setgid", //196
+ "setgid32", //197
+ "setgroups", //198
+ "setgroups32", //199
+
+
+ "sethostname", //200
+ "setitimer", //201
+ "setpgid", //202
+ "setpriority", //203
+ "setregid", //204
+ "setregid32", //205
+ "setresgid", //206
+ "setresgid32", //207
+ "setresuid", //208
+ "setresuid32", //209
+
+
+ "setreuid", //210
+ "setreuid32", //211
+ "setrlimit", //212
+ "setsid", //213
+ "settimeofday", //214
+ "setuid", //215
+ "setuid32", //216
+ "setxattr", //217
+ "sgetmask", //218
+ "sigaction", //219
+
+
+ "sigaltstack", //220
+ "signal", //221
+ "sigpending", //222
+ "sigprocmask", //223
+ "sigreturn", //224
+ "sigsuspend", //225
+ "socketcall", //226
+ "ssetmask", //227
+ "stat", //228
+ "stat64", //229
+
+
+ "statfs", //230
+ "statfs64", //231
+ "stime", //232
+ "stty", //233
+ "swapoff", //234
+ "swapon", //235
+ "symlink", //236
+ "sync", //237
+ "sysfs", //238
+ "sysinfo", //239
+
+
+ "syslog", //240
+ "tgkill", //241
+ "time", //242
+ "timer_create", //243
+ "timer_delete", //244
+ "timer_getoverrun", //245
+ "timer_gettime", //246
+ "timer_settime", //247
+ "times", //248
+ "tkill", //249
+
+
+ "truncate", //250
+ "truncate64", //251
+ "ugetrlimit", //252
+ "ulimit", //253
+ "umask", //254
+ "umount", //255
+ "umount2", //256
+ "uname", //257
+ "unlink", //258
+ "uselib", //259
+
+
+ "ustat", //260
+ "utime", //261
+ "utimes", //262
+ "vfork", //263
+ "vhangup", //264
+ "vm86", //265
+ "vm86old", //266
+ "vserver", //267
+ "wait4", //268
+ "waitpid", //269
+
+
+ "write", //270
+ "writev", //271
+ };
+
+
+}
+
+const char *
+SystemCalls<Linux>::name(int num)
+{
+ if ((num >= 0) && (num < Number))
+ return standard_strings[num];
+ else
+ return 0;
+}
diff --git a/src/kern/linux/linux_syscalls.hh b/src/kern/linux/linux_syscalls.hh
new file mode 100644
index 000000000..7f2a08ea9
--- /dev/null
+++ b/src/kern/linux/linux_syscalls.hh
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __KERN_LINUX_LINUX_SYSCALLS_HH__
+#define __KERN_LINUX_LINUX_SYSCALLS_HH__
+
+#include "kern/linux/linux.hh"
+
+template <class OS>
+class SystemCalls;
+
+template <>
+class SystemCalls<Linux>
+{
+ public:
+ enum {
+ syscall = 0,
+ llseek = 1,
+ newselect = 2,
+ sysctl = 3,
+ access = 4,
+ acct = 5,
+ adjtimex = 6,
+ afs_syscall = 7,
+ alarm = 8,
+ bdflush = 9,
+ _break = 10, /*renamed from break*/
+ brk = 11,
+ capget = 12,
+ capset = 13,
+ chdir = 14,
+ chmod = 15,
+ chown = 16,
+ chown32 = 17,
+ chroot = 18,
+ clock_getres = 19,
+ clock_gettime = 20,
+ clock_nanosleep = 21,
+ clock_settime = 22,
+ clone = 23,
+ close = 24,
+ creat = 25,
+ create_module = 26,
+ delete_module = 27,
+ dup = 28,
+ dup2 = 29,
+ epoll_create = 30,
+ epoll_ctl = 31,
+ epoll_wait = 32,
+ execve = 33,
+ exit = 34,
+ exit_group = 35,
+ fadvise64 = 36,
+ fadvise64_64 = 37,
+ fchdir = 38,
+ fchmod = 39,
+ fchown = 40,
+ fchown32 = 41,
+ fcntl = 42,
+ fcntl64 = 43,
+ fdatasync = 44,
+ fgetxattr = 45,
+ flistxattr = 46,
+ flock = 47,
+ fork = 48,
+ fremovexattr = 49,
+ fsetxattr = 50,
+ fstat = 51,
+ fstat64 = 52,
+ fstatfs = 53,
+ fstatfs64 = 54,
+ fsync = 55,
+ ftime = 56,
+ ftruncate = 57,
+ ftruncate64 = 58,
+ futex = 59,
+ get_kernel_syms = 60,
+ get_thread_area = 61,
+ getcwd = 62,
+ getdents = 63,
+ getdents64 = 64,
+ getegid = 65,
+ getegid32 = 66,
+ geteuid = 67,
+ geteuid32 = 68,
+ getgid = 69,
+ getgid32 = 70,
+ getgroups = 71,
+ getgroups32 = 72,
+ getitimer = 73,
+ getpgid = 74,
+ getpgrp = 75,
+ getpid = 76,
+ getpmsg = 77,
+ getppid = 78,
+ getpriority = 79,
+ getresgid = 80,
+ getresgid32 = 81,
+ getresuid = 82,
+ getresuid32 = 83,
+ getrlimit = 84,
+ getrusage = 85,
+ getsid = 86,
+ gettid = 87,
+ gettimeofday = 88,
+ getuid = 89,
+ getuid32 = 90,
+ getxattr = 91,
+ gtty = 92,
+ idle = 93,
+ init_module = 94,
+ io_cancel = 95,
+ io_destroy = 96,
+ io_getevents = 97,
+ io_setup = 98,
+ io_submit = 99,
+ ioctl = 100,
+ ioperm = 101,
+ iopl = 102,
+ ipc = 103,
+ kill = 104,
+ lchown = 105,
+ lchown32 = 106,
+ lgetxattr = 107,
+ link = 108,
+ listxattr = 109,
+ llistxattr = 110,
+ lock = 111,
+ lookup_dcookie = 112,
+ lremovexattr = 113,
+ lseek = 114,
+ lsetxattr = 115,
+ lstat = 116,
+ lstat64 = 117,
+ madvise = 118,
+ madvise1 = 119,
+ mincore = 120,
+ mkdir = 121,
+ mknod = 122,
+ mlock = 123,
+ mlockall = 124,
+ mmap = 125,
+ mmap2 = 126,
+ modify_ldt = 127,
+ mount = 128,
+ mprotect = 129,
+ mpx = 130,
+ mremap = 131,
+ msync = 132,
+ munlock = 133,
+ munlockall = 134,
+ munmap = 135,
+ nanosleep = 136,
+ nfsservctl = 137,
+ nice = 138,
+ oldfstat = 139,
+ oldlstat = 140,
+ oldolduname = 141,
+ oldstat = 142,
+ olduname = 143,
+ open = 144,
+ pause = 145,
+ personality = 146,
+ pipe = 147,
+ pivot_root = 148,
+ poll = 149,
+ prctl = 150,
+ pread64 = 151,
+ prof = 152,
+ profil = 153,
+ ptrace = 154,
+ putpmsg = 155,
+ pwrite64 = 156,
+ query_module = 157,
+ quotactl = 158,
+ read = 159,
+ readahead = 160,
+ readdir = 161,
+ readlink = 162,
+ readv = 163,
+ reboot = 164,
+ remap_file_pages = 165,
+ removexattr = 166,
+ rename = 167,
+ restart_syscall = 168,
+ rmdir = 169,
+ rt_sigaction = 170,
+ rt_sigpending = 171,
+ rt_sigprocmask = 172,
+ rt_sigqueueinfo = 173,
+ rt_sigreturn = 174,
+ rt_sigsuspend = 175,
+ rt_sigtimedwait = 176,
+ sched_get_priority_max = 177,
+ sched_get_priority_min = 178,
+ sched_getaffinity = 179,
+ sched_getparam = 180,
+ sched_getscheduler = 181,
+ sched_rr_get_interval = 182,
+ sched_setaffinity = 183,
+ sched_setparam = 184,
+ sched_setscheduler = 185,
+ sched_yield = 186,
+ select = 187,
+ sendfile = 188,
+ sendfile64 = 189,
+ set_thread_area = 190,
+ set_tid_address = 191,
+ setdomainname = 192,
+ setfsgid = 193,
+ setfsgid32 = 194,
+ setfsuid = 195,
+ setfsuid32 = 196,
+ setgid = 197,
+ setgid32 = 198,
+ setgroups = 199,
+ setgroups32 = 200,
+ sethostname = 201,
+ setitimer = 202,
+ setpgid = 203,
+ setpriority = 204,
+ setregid = 205,
+ setregid32 = 206,
+ setresgid = 207,
+ setresgid32 = 208,
+ setresuid = 209,
+ setresuid32 = 210,
+ setreuid = 211,
+ setreuid32 = 212,
+ setrlimit = 213,
+ setsid = 214,
+ settimeofday = 215,
+ setuid = 216,
+ setuid32 = 217,
+ setxattr = 218,
+ sgetmask = 219,
+ sigaction = 220,
+ sigaltstack = 221,
+ signal = 222,
+ sigpending = 223,
+ sigprocmask = 224,
+ sigreturn = 225,
+ sigsuspend = 226,
+ socketcall = 227,
+ ssetmask = 228,
+ stat = 229,
+ stat64 = 230,
+ statfs = 231,
+ statfs64 = 232,
+ stime = 233,
+ stty = 234,
+ swapoff = 235,
+ swapon = 236,
+ symlink = 237,
+ sync = 238,
+ sysfs = 239,
+ sysinfo = 240,
+ syslog = 241,
+ tgkill = 242,
+ time = 243,
+ timer_create = 244,
+ timer_delete = 245,
+ timer_getoverrun = 246,
+ timer_gettime = 247,
+ timer_settime = 248,
+ times = 249,
+ tkill = 250,
+ truncate = 251,
+ truncate64 = 252,
+ ugetrlimit = 253,
+ ulimit = 254,
+ umask = 255,
+ umount = 256,
+ umount2 = 257,
+ uname = 258,
+ unlink = 259,
+ uselib = 260,
+ ustat = 261,
+ utime = 262,
+ utimes = 263,
+ vfork = 264,
+ vhangup = 265,
+ vm86 = 266,
+ vm86old = 267,
+ vserver = 268,
+ wait4 = 269,
+ waitpid = 270,
+ write = 271,
+ writev = 272,
+ Number
+ };
+
+ static const char *name(int num);
+
+ static bool validSyscallNumber(int num) {
+ return num < Number;
+ }
+
+};
+
+#endif // __KERN_LINUX_LINUX_SYSCALLS_HH__
diff --git a/src/kern/linux/printk.cc b/src/kern/linux/printk.cc
new file mode 100644
index 000000000..918b8dabe
--- /dev/null
+++ b/src/kern/linux/printk.cc
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <algorithm>
+
+#include "base/trace.hh"
+#include "arch/arguments.hh"
+
+using namespace std;
+
+
+void
+Printk(AlphaISA::AlphaArguments args)
+{
+ char *p = (char *)args++;
+
+ ios::fmtflags saved_flags = DebugOut().flags();
+ char old_fill = DebugOut().fill();
+ int old_precision = DebugOut().precision();
+
+ while (*p) {
+ switch (*p) {
+ case '%': {
+ bool more = true;
+ bool islong = false;
+ bool leftjustify = false;
+ bool format = false;
+ bool zero = false;
+ int width = 0;
+ while (more && *++p) {
+ switch (*p) {
+ case 'l':
+ case 'L':
+ islong = true;
+ break;
+ case '-':
+ leftjustify = true;
+ break;
+ case '#':
+ format = true;
+ break;
+ case '0':
+ if (width)
+ width *= 10;
+ else
+ zero = true;
+ break;
+ default:
+ if (*p >= '1' && *p <= '9')
+ width = 10 * width + *p - '0';
+ else
+ more = false;
+ break;
+ }
+ }
+
+ bool hexnum = false;
+ bool octal = false;
+ bool sign = false;
+ switch (*p) {
+ case 'X':
+ case 'x':
+ hexnum = true;
+ break;
+ case 'O':
+ case 'o':
+ octal = true;
+ break;
+ case 'D':
+ case 'd':
+ sign = true;
+ break;
+ case 'P':
+ format = true;
+ case 'p':
+ hexnum = true;
+ break;
+ }
+
+ switch (*p) {
+ case 'D':
+ case 'd':
+ case 'U':
+ case 'u':
+ case 'X':
+ case 'x':
+ case 'O':
+ case 'o':
+ case 'P':
+ case 'p': {
+ if (hexnum)
+ DebugOut() << hex;
+
+ if (octal)
+ DebugOut() << oct;
+
+ if (format) {
+ if (!zero)
+ DebugOut().setf(ios::showbase);
+ else {
+ if (hexnum) {
+ DebugOut() << "0x";
+ width -= 2;
+ } else if (octal) {
+ DebugOut() << "0";
+ width -= 1;
+ }
+ }
+ }
+
+ if (zero)
+ DebugOut().fill('0');
+
+ if (width > 0)
+ DebugOut().width(width);
+
+ if (leftjustify && !zero)
+ DebugOut().setf(ios::left);
+
+ if (sign) {
+ if (islong)
+ DebugOut() << (int64_t)args;
+ else
+ DebugOut() << (int32_t)args;
+ } else {
+ if (islong)
+ DebugOut() << (uint64_t)args;
+ else
+ DebugOut() << (uint32_t)args;
+ }
+
+ if (zero)
+ DebugOut().fill(' ');
+
+ if (width > 0)
+ DebugOut().width(0);
+
+ DebugOut() << dec;
+
+ ++args;
+ }
+ break;
+
+ case 's': {
+ char *s = (char *)args;
+ if (!s)
+ s = "<NULL>";
+
+ if (width > 0)
+ DebugOut().width(width);
+ if (leftjustify)
+ DebugOut().setf(ios::left);
+
+ DebugOut() << s;
+ ++args;
+ }
+ break;
+ case 'C':
+ case 'c': {
+ uint64_t mask = (*p == 'C') ? 0xffL : 0x7fL;
+ uint64_t num;
+ int width;
+
+ if (islong) {
+ num = (uint64_t)args;
+ width = sizeof(uint64_t);
+ } else {
+ num = (uint32_t)args;
+ width = sizeof(uint32_t);
+ }
+
+ while (width-- > 0) {
+ char c = (char)(num & mask);
+ if (c)
+ DebugOut() << c;
+ num >>= 8;
+ }
+
+ ++args;
+ }
+ break;
+ case 'b': {
+ uint64_t n = (uint64_t)args++;
+ char *s = (char *)args++;
+ DebugOut() << s << ": " << n;
+ }
+ break;
+ case 'n':
+ case 'N': {
+ args += 2;
+#if 0
+ uint64_t n = (uint64_t)args++;
+ struct reg_values *rv = (struct reg_values *)args++;
+#endif
+ }
+ break;
+ case 'r':
+ case 'R': {
+ args += 2;
+#if 0
+ uint64_t n = (uint64_t)args++;
+ struct reg_desc *rd = (struct reg_desc *)args++;
+#endif
+ }
+ break;
+ case '%':
+ DebugOut() << '%';
+ break;
+ }
+ ++p;
+ }
+ break;
+ case '\n':
+ DebugOut() << endl;
+ ++p;
+ break;
+ case '\r':
+ ++p;
+ if (*p != '\n')
+ DebugOut() << endl;
+ break;
+
+ default: {
+ size_t len = strcspn(p, "%\n\r\0");
+ DebugOut().write(p, len);
+ p += len;
+ }
+ }
+ }
+
+ DebugOut().flags(saved_flags);
+ DebugOut().fill(old_fill);
+ DebugOut().precision(old_precision);
+}
+
diff --git a/src/kern/linux/printk.hh b/src/kern/linux/printk.hh
new file mode 100644
index 000000000..b88c40f5e
--- /dev/null
+++ b/src/kern/linux/printk.hh
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __PRINTK_HH__
+#define __PRINTK_HH__
+
+class AlphaISA::AlphaArguments;
+
+void Printk(AlphaISA::AlphaArguments args);
+
+#endif // __PRINTK_HH__
diff --git a/src/kern/linux/sched.hh b/src/kern/linux/sched.hh
new file mode 100644
index 000000000..a11fa590d
--- /dev/null
+++ b/src/kern/linux/sched.hh
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __KERN_LINUX_SCHED_HH__
+#define __KERN_LINUX_SCHED_HH__
+
+namespace Linux {
+ struct task_struct {
+ uint8_t junk1[0xf4];
+ int32_t pid;
+ uint8_t junk2[0x190];
+ uint64_ta start;
+ uint8_t junk3[0x5c];
+ char name[16];
+ };
+
+
+}
+
+#endif // __KERN_LINUX_SCHED_HH__
diff --git a/src/kern/solaris/solaris.hh b/src/kern/solaris/solaris.hh
new file mode 100644
index 000000000..e2b61d613
--- /dev/null
+++ b/src/kern/solaris/solaris.hh
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SOLARIS_HH__
+#define __SOLARIS_HH__
+#include "config/full_system.hh"
+
+#if FULL_SYSTEM
+
+class Solaris {};
+
+#else //!FULL_SYSTEM
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h> // for host open() flags
+#include <string.h> // for memset()
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "arch/isa_traits.hh"
+#include "sim/syscall_emul.hh"
+
+class TranslatingPort;
+
+///
+/// This class encapsulates the types, structures, constants,
+/// functions, and syscall-number mappings specific to the Solaris
+/// syscall interface.
+///
+class Solaris {
+
+ public:
+
+ //@{
+ /// Basic Solaris types.
+ typedef uint64_t size_t;
+ typedef uint64_t off_t;
+ typedef int64_t time_t;
+ typedef int32_t uid_t;
+ typedef int32_t gid_t;
+ typedef uint64_t rlim_t;
+ typedef uint64_t ino_t;
+ typedef uint64_t dev_t;
+ typedef uint32_t mode_t;
+ typedef uint32_t nlink_t;
+ //@}
+
+#if BSD_HOST
+ typedef struct stat hst_stat;
+ typedef struct stat hst_stat64;
+#else
+ typedef struct stat hst_stat ;
+ typedef struct stat64 hst_stat64;
+#endif
+ struct tgt_timespec {
+ int64_t tv_sec;
+ int64_t tv_nsec;
+ };
+
+ /// Stat buffer. Note that we can't call it 'stat' since that
+ /// gets #defined to something else on some systems.
+ struct tgt_stat {
+ uint64_t st_dev; //!< device
+ uint64_t st_ino; //!< inode
+ uint32_t st_mode; //!< mode
+ uint32_t st_nlink; //!< link count
+ int32_t st_uid; //!< owner's user ID
+ int32_t st_gid; //!< owner's group ID
+ uint64_t st_rdev; //!< device number
+ int64_t st_size; //!< file size in bytes
+ struct tgt_timespec st_atimeX; //!< time of last access
+ struct tgt_timespec st_mtimeX; //!< time of last modification
+ struct tgt_timespec st_ctimeX; //!< time of last status change
+ int32_t st_blksize; //!< optimal I/O block size
+ int64_t st_blocks; //!< number of blocks allocated
+ char st_fstype[16];
+ };
+
+ // same for stat64
+ struct tgt_stat64 {
+ uint64_t st_dev; //!< device
+ uint64_t st_ino; //!< inode
+ uint32_t st_mode; //!< mode
+ uint32_t st_nlink; //!< link count
+ int32_t st_uid; //!< owner's user ID
+ int32_t st_gid; //!< owner's group ID
+ uint64_t st_rdev; //!< device number
+ int64_t st_size; //!< file size in bytes
+ struct tgt_timespec st_atimeX; //!< time of last access
+ struct tgt_timespec st_mtimeX; //!< time of last modification
+ struct tgt_timespec st_ctimeX; //!< time of last status change
+ int32_t st_blksize; //!< optimal I/O block size
+ int64_t st_blocks; //!< number of blocks allocated
+ char st_fstype[16];
+ };
+
+ /// Length of strings in struct utsname (plus 1 for null char).
+ static const int _SYS_NMLN = 257;
+
+ /// Interface struct for uname().
+ struct utsname {
+ char sysname[_SYS_NMLN]; //!< System name.
+ char nodename[_SYS_NMLN]; //!< Node name.
+ char release[_SYS_NMLN]; //!< OS release.
+ char version[_SYS_NMLN]; //!< OS version.
+ char machine[_SYS_NMLN]; //!< Machine type.
+ };
+
+ /// Limit struct for getrlimit/setrlimit.
+ struct rlimit {
+ uint64_t rlim_cur; //!< soft limit
+ uint64_t rlim_max; //!< hard limit
+ };
+
+ /// For gettimeofday().
+ struct timeval {
+ int64_t tv_sec; //!< seconds
+ int64_t tv_usec; //!< microseconds
+ };
+
+ // For writev/readv
+ struct tgt_iovec {
+ uint64_t iov_base; // void *
+ uint64_t iov_len;
+ };
+
+
+ /// For getrusage().
+ struct rusage {
+ struct timeval ru_utime; //!< user time used
+ struct timeval ru_stime; //!< system time used
+ int64_t ru_maxrss; //!< max rss
+ int64_t ru_ixrss; //!< integral shared memory size
+ int64_t ru_idrss; //!< integral unshared data "
+ int64_t ru_isrss; //!< integral unshared stack "
+ int64_t ru_minflt; //!< page reclaims - total vmfaults
+ int64_t ru_majflt; //!< page faults
+ int64_t ru_nswap; //!< swaps
+ int64_t ru_inblock; //!< block input operations
+ int64_t ru_oublock; //!< block output operations
+ int64_t ru_msgsnd; //!< messages sent
+ int64_t ru_msgrcv; //!< messages received
+ int64_t ru_nsignals; //!< signals received
+ int64_t ru_nvcsw; //!< voluntary context switches
+ int64_t ru_nivcsw; //!< involuntary "
+ };
+
+ /// Helper function to convert a host stat buffer to a target stat
+ /// buffer. Also copies the target buffer out to the simulated
+ /// memory space. Used by stat(), fstat(), and lstat().
+#if !BSD_HOST
+ static void
+ copyOutStatBuf(TranslatingPort *mem, Addr addr, hst_stat *host)
+ {
+ using namespace TheISA;
+
+ TypedBufferArg<Solaris::tgt_stat> tgt(addr);
+
+ tgt->st_dev = htog(host->st_dev);
+ tgt->st_ino = htog(host->st_ino);
+ tgt->st_mode = htog(host->st_mode);
+ tgt->st_nlink = htog(host->st_nlink);
+ tgt->st_uid = htog(host->st_uid);
+ tgt->st_gid = htog(host->st_gid);
+ tgt->st_rdev = htog(host->st_rdev);
+ tgt->st_size = htog(host->st_size);
+ tgt->st_atimeX.tv_sec = htog((uint64_t)host->st_atime);
+ tgt->st_mtimeX.tv_sec = htog((uint64_t)host->st_mtime);
+ tgt->st_ctimeX.tv_sec = htog((uint64_t)host->st_ctime);
+#if defined(STAT_HAVE_NSEC)
+ tgt->st_atimeX.tv_nsec = htog(host->st_atime_nsec);
+ tgt->st_mtimeX.tv_nsec = htog(host->st_mtime_nsec);
+ tgt->st_ctimeX.tv_nsec = htog(host->st_ctime_nsec);
+#else
+ tgt->st_atimeX.tv_nsec = 0;
+ tgt->st_mtimeX.tv_nsec = 0;
+ tgt->st_ctimeX.tv_nsec = 0;
+#endif
+ tgt->st_blksize = htog(host->st_blksize);
+ tgt->st_blocks = htog(host->st_blocks);
+ strncpy(tgt->st_fstype, "????", 16);
+
+ tgt.copyOut(mem);
+ }
+#else
+ // Third version for bsd systems which no longer have any support for
+ // the old stat() call and stat() is actually a stat64()
+ static void
+ copyOutStatBuf(TranslatingPort *mem, Addr addr, hst_stat64 *host)
+ {
+ using namespace TheISA;
+
+ TypedBufferArg<Solaris::tgt_stat> tgt(addr);
+
+ tgt->st_dev = htog(host->st_dev);
+ tgt->st_ino = htog(host->st_ino);
+ tgt->st_mode = htog(host->st_mode);
+ tgt->st_nlink = htog(host->st_nlink);
+ tgt->st_uid = htog(host->st_uid);
+ tgt->st_gid = htog(host->st_gid);
+ tgt->st_rdev = htog(host->st_rdev);
+ tgt->st_size = htog(host->st_size);
+ tgt->st_atimeX.tv_sec = htog((uint64_t)host->st_atime);
+ tgt->st_mtimeX.tv_sec = htog((uint64_t)host->st_mtime);
+ tgt->st_ctimeX.tv_sec = htog((uint64_t)host->st_ctime);
+#if defined(STAT_HAVE_NSEC)
+ tgt->st_atimeX.tv_nsec = htog(host->st_atime_nsec);
+ tgt->st_mtimeX.tv_nsec = htog(host->st_mtime_nsec);
+ tgt->st_ctimeX.tv_nsec = htog(host->st_ctime_nsec);
+#else
+ tgt->st_atimeX.tv_nsec = 0;
+ tgt->st_mtimeX.tv_nsec = 0;
+ tgt->st_ctimeX.tv_nsec = 0;
+#endif
+ tgt->st_blksize = htog(host->st_blksize);
+ tgt->st_blocks = htog(host->st_blocks);
+ strncpy(tgt->st_fstype, "????", 16);
+
+ tgt.copyOut(mem);
+ }
+#endif
+
+
+ // Same for stat64
+ static void
+ copyOutStat64Buf(TranslatingPort *mem, int fd, Addr addr, hst_stat64 *host)
+ {
+ using namespace TheISA;
+
+ TypedBufferArg<Solaris::tgt_stat64> tgt(addr);
+
+ // fd == 1 checks are because libc does some checks
+ // that the stdout is interactive vs. a file
+ // this makes it work on non-solaris systems
+ if (fd == 1)
+ tgt->st_dev = htog((uint64_t)0xA);
+ else
+ tgt->st_dev = htog((uint64_t)host->st_dev);
+ // XXX What about STAT64_HAS_BROKEN_ST_INO ???
+ tgt->st_ino = htog((uint64_t)host->st_ino);
+ if (fd == 1)
+ tgt->st_rdev = htog((uint64_t)0x880d);
+ else
+ tgt->st_rdev = htog((uint64_t)host->st_rdev);
+ tgt->st_size = htog((int64_t)host->st_size);
+ tgt->st_blocks = htog((uint64_t)host->st_blocks);
+
+ if (fd == 1)
+ tgt->st_mode = htog((uint32_t)0x2190);
+ else
+ tgt->st_mode = htog((uint32_t)host->st_mode);
+ tgt->st_uid = htog((uint32_t)host->st_uid);
+ tgt->st_gid = htog((uint32_t)host->st_gid);
+ tgt->st_blksize = htog((uint32_t)host->st_blksize);
+ tgt->st_nlink = htog((uint32_t)host->st_nlink);
+ tgt->st_atimeX.tv_sec = htog((uint64_t)host->st_atime);
+ tgt->st_mtimeX.tv_sec = htog((uint64_t)host->st_mtime);
+ tgt->st_ctimeX.tv_sec = htog((uint64_t)host->st_ctime);
+#if defined(STAT_HAVE_NSEC)
+ tgt->st_atimeX.tv_nsec = htog(host->st_atime_nsec);
+ tgt->st_mtimeX.tv_nsec = htog(host->st_mtime_nsec);
+ tgt->st_ctimeX.tv_nsec = htog(host->st_ctime_nsec);
+#else
+ tgt->st_atimeX.tv_nsec = 0;
+ tgt->st_mtimeX.tv_nsec = 0;
+ tgt->st_ctimeX.tv_nsec = 0;
+#endif
+
+ tgt.copyOut(mem);
+ }
+
+}; // class Solaris
+
+
+#endif // FULL_SYSTEM
+
+#endif // __SOLARIS_HH__
diff --git a/src/kern/system_events.cc b/src/kern/system_events.cc
new file mode 100644
index 000000000..fd5c12e44
--- /dev/null
+++ b/src/kern/system_events.cc
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "cpu/base.hh"
+#include "cpu/cpu_exec_context.hh"
+#include "kern/kernel_stats.hh"
+#include "kern/system_events.hh"
+#include "sim/system.hh"
+
+using namespace TheISA;
+
+void
+SkipFuncEvent::process(ExecContext *xc)
+{
+ Addr newpc = xc->readIntReg(ReturnAddressReg);
+
+ DPRINTF(PCEvent, "skipping %s: pc=%x, newpc=%x\n", description,
+ xc->readPC(), newpc);
+
+ xc->setPC(newpc);
+ xc->setNextPC(xc->readPC() + sizeof(TheISA::MachInst));
+/*
+ BranchPred *bp = xc->getCpuPtr()->getBranchPred();
+ if (bp != NULL) {
+ bp->popRAS(xc->getThreadNum());
+ }
+*/
+}
+
+
+FnEvent::FnEvent(PCEventQueue *q, const std::string &desc, Addr addr,
+ Stats::MainBin *bin)
+ : PCEvent(q, desc, addr), _name(desc), mybin(bin)
+{
+}
+
+void
+FnEvent::process(ExecContext *xc)
+{
+ if (xc->misspeculating())
+ return;
+
+ xc->getSystemPtr()->kernelBinning->call(xc, mybin);
+}
+
+void
+IdleStartEvent::process(ExecContext *xc)
+{
+ xc->getCpuPtr()->kernelStats->setIdleProcess(
+ xc->readMiscReg(AlphaISA::IPR_PALtemp23), xc);
+ remove();
+}
+
+void
+InterruptStartEvent::process(ExecContext *xc)
+{
+ xc->getCpuPtr()->kernelStats->mode(Kernel::interrupt, xc);
+}
+
+void
+InterruptEndEvent::process(ExecContext *xc)
+{
+ // We go back to kernel, if we are user, inside the rti
+ // pal code we will get switched to user because of the ICM write
+ xc->getCpuPtr()->kernelStats->mode(Kernel::kernel, xc);
+}
diff --git a/src/kern/system_events.hh b/src/kern/system_events.hh
new file mode 100644
index 000000000..246140a09
--- /dev/null
+++ b/src/kern/system_events.hh
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SYSTEM_EVENTS_HH__
+#define __SYSTEM_EVENTS_HH__
+
+#include "cpu/pc_event.hh"
+
+class System;
+
+class SkipFuncEvent : public PCEvent
+{
+ public:
+ SkipFuncEvent(PCEventQueue *q, const std::string &desc, Addr addr)
+ : PCEvent(q, desc, addr)
+ {}
+ virtual void process(ExecContext *xc);
+};
+
+class FnEvent : public PCEvent
+{
+ public:
+ FnEvent(PCEventQueue *q, const std::string &desc, Addr addr,
+ Stats::MainBin *bin);
+ virtual void process(ExecContext *xc);
+ std::string myname() const { return _name; }
+
+ private:
+ std::string _name;
+ Stats::MainBin *mybin;
+};
+
+class IdleStartEvent : public PCEvent
+{
+ public:
+ IdleStartEvent(PCEventQueue *q, const std::string &desc, Addr addr)
+ : PCEvent(q, desc, addr)
+ {}
+ virtual void process(ExecContext *xc);
+};
+
+class InterruptStartEvent : public PCEvent
+{
+ public:
+ InterruptStartEvent(PCEventQueue *q, const std::string &desc, Addr addr)
+ : PCEvent(q, desc, addr)
+ {}
+ virtual void process(ExecContext *xc);
+};
+
+class InterruptEndEvent : public PCEvent
+{
+ public:
+ InterruptEndEvent(PCEventQueue *q, const std::string &desc, Addr addr)
+ : PCEvent(q, desc, addr)
+ {}
+ virtual void process(ExecContext *xc);
+};
+
+
+#endif // __SYSTEM_EVENTS_HH__
diff --git a/src/kern/tru64/dump_mbuf.cc b/src/kern/tru64/dump_mbuf.cc
new file mode 100644
index 000000000..c3c37531a
--- /dev/null
+++ b/src/kern/tru64/dump_mbuf.cc
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <algorithm>
+
+#include "base/cprintf.hh"
+#include "base/trace.hh"
+#include "base/loader/symtab.hh"
+#include "cpu/exec_context.hh"
+#include "kern/tru64/mbuf.hh"
+#include "sim/host.hh"
+#include "sim/system.hh"
+#include "arch/arguments.hh"
+#include "arch/isa_traits.hh"
+#include "arch/vtophys.hh"
+
+using namespace TheISA;
+
+namespace tru64 {
+
+void
+DumpMbuf(AlphaArguments args)
+{
+ ExecContext *xc = args.getExecContext();
+ Addr addr = (Addr)args;
+ struct mbuf m;
+
+ CopyOut(xc, &m, addr, sizeof(m));
+
+ int count = m.m_pkthdr.len;
+
+ ccprintf(DebugOut(), "m=%#lx, m->m_pkthdr.len=%#d\n", addr,
+ m.m_pkthdr.len);
+
+ while (count > 0) {
+ ccprintf(DebugOut(), "m=%#lx, m->m_data=%#lx, m->m_len=%d\n",
+ addr, m.m_data, m.m_len);
+ char *buffer = new char[m.m_len];
+ CopyOut(xc, buffer, m.m_data, m.m_len);
+ Trace::dataDump(curTick, xc->getSystemPtr()->name(), (uint8_t *)buffer,
+ m.m_len);
+ delete [] buffer;
+
+ count -= m.m_len;
+ if (!m.m_next)
+ break;
+
+ CopyOut(xc, &m, m.m_next, sizeof(m));
+ }
+}
+
+} // namespace Tru64
diff --git a/src/kern/tru64/dump_mbuf.hh b/src/kern/tru64/dump_mbuf.hh
new file mode 100644
index 000000000..9e1698ff1
--- /dev/null
+++ b/src/kern/tru64/dump_mbuf.hh
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __DUMP_MBUF_HH__
+#define __DUMP_MBUF_HH__
+
+#include "arch/arguments.hh"
+
+namespace tru64 {
+ void DumpMbuf(AlphaISA::AlphaArguments args);
+}
+
+#endif // __DUMP_MBUF_HH__
diff --git a/src/kern/tru64/mbuf.hh b/src/kern/tru64/mbuf.hh
new file mode 100644
index 000000000..93424858f
--- /dev/null
+++ b/src/kern/tru64/mbuf.hh
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MBUF_HH__
+#define __MBUF_HH__
+
+#include "sim/host.hh"
+#include "arch/isa_traits.hh"
+
+namespace tru64 {
+
+struct m_hdr {
+ Addr mh_next; // 0x00
+ Addr mh_nextpkt; // 0x08
+ Addr mh_data; // 0x10
+ int32_t mh_len; // 0x18
+ int32_t mh_type; // 0x1C
+ int32_t mh_flags; // 0x20
+ int32_t mh_pad0; // 0x24
+ Addr mh_foo[4]; // 0x28, 0x30, 0x38, 0x40
+};
+
+struct pkthdr {
+ int32_t len;
+ int32_t protocolSum;
+ Addr rcvif;
+};
+
+struct m_ext {
+ Addr ext_buf; // 0x00
+ Addr ext_free; // 0x08
+ uint32_t ext_size; // 0x10
+ uint32_t ext_pad0; // 0x14
+ Addr ext_arg; // 0x18
+ struct ext_refq {
+ Addr forw, back; // 0x20, 0x28
+ } ext_ref;
+ Addr uiomove_f; // 0x30
+ int32_t protocolSum; // 0x38
+ int32_t bytesSummed; // 0x3C
+ Addr checksum; // 0x40
+};
+
+struct mbuf {
+ struct m_hdr m_hdr;
+ union {
+ struct {
+ struct pkthdr MH_pkthdr;
+ union {
+ struct m_ext MH_ext;
+ char MH_databuf[1];
+ } MH_dat;
+ } MH;
+ char M_databuf[1];
+ } M_dat;
+};
+
+#define m_attr m_hdr.mh_attr
+#define m_next m_hdr.mh_next
+#define m_len m_hdr.mh_len
+#define m_data m_hdr.mh_data
+#define m_type m_hdr.mh_type
+#define m_flags m_hdr.mh_flags
+#define m_nextpkt m_hdr.mh_nextpkt
+#define m_act m_nextpkt
+#define m_pkthdr M_dat.MH.MH_pkthdr
+#define m_ext M_dat.MH.MH_dat.MH_ext
+#define m_pktdat M_dat.MH.MH_dat.MH_databuf
+#define m_dat M_dat.M_databuf
+
+}
+
+#endif // __MBUF_HH__
diff --git a/src/kern/tru64/printf.cc b/src/kern/tru64/printf.cc
new file mode 100644
index 000000000..319d36673
--- /dev/null
+++ b/src/kern/tru64/printf.cc
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <algorithm>
+
+#include "base/cprintf.hh"
+#include "base/trace.hh"
+#include "sim/host.hh"
+#include "arch/arguments.hh"
+#include "arch/vtophys.hh"
+
+using namespace std;
+
+namespace tru64 {
+
+void
+Printf(AlphaISA::AlphaArguments args)
+{
+ char *p = (char *)args++;
+
+ ios::fmtflags saved_flags = DebugOut().flags();
+ char old_fill = DebugOut().fill();
+ int old_precision = DebugOut().precision();
+
+ while (*p) {
+ switch (*p) {
+ case '%': {
+ bool more = true;
+ bool islong = false;
+ bool leftjustify = false;
+ bool format = false;
+ bool zero = false;
+ int width = 0;
+ while (more && *++p) {
+ switch (*p) {
+ case 'l':
+ case 'L':
+ islong = true;
+ break;
+ case '-':
+ leftjustify = true;
+ break;
+ case '#':
+ format = true;
+ break;
+ case '0':
+ if (width)
+ width *= 10;
+ else
+ zero = true;
+ break;
+ default:
+ if (*p >= '1' && *p <= '9')
+ width = 10 * width + *p - '0';
+ else
+ more = false;
+ break;
+ }
+ }
+
+ bool hexnum = false;
+ bool octal = false;
+ bool sign = false;
+ switch (*p) {
+ case 'X':
+ case 'x':
+ hexnum = true;
+ break;
+ case 'O':
+ case 'o':
+ octal = true;
+ break;
+ case 'D':
+ case 'd':
+ sign = true;
+ break;
+ case 'P':
+ format = true;
+ case 'p':
+ hexnum = true;
+ break;
+ }
+
+ switch (*p) {
+ case 'D':
+ case 'd':
+ case 'U':
+ case 'u':
+ case 'X':
+ case 'x':
+ case 'O':
+ case 'o':
+ case 'P':
+ case 'p': {
+ if (hexnum)
+ DebugOut() << hex;
+
+ if (octal)
+ DebugOut() << oct;
+
+ if (format) {
+ if (!zero)
+ DebugOut().setf(ios::showbase);
+ else {
+ if (hexnum) {
+ DebugOut() << "0x";
+ width -= 2;
+ } else if (octal) {
+ DebugOut() << "0";
+ width -= 1;
+ }
+ }
+ }
+
+ if (zero)
+ DebugOut().fill('0');
+
+ if (width > 0)
+ DebugOut().width(width);
+
+ if (leftjustify && !zero)
+ DebugOut().setf(ios::left);
+
+ if (sign) {
+ if (islong)
+ DebugOut() << (int64_t)args;
+ else
+ DebugOut() << (int32_t)args;
+ } else {
+ if (islong)
+ DebugOut() << (uint64_t)args;
+ else
+ DebugOut() << (uint32_t)args;
+ }
+
+ if (zero)
+ DebugOut().fill(' ');
+
+ if (width > 0)
+ DebugOut().width(0);
+
+ DebugOut() << dec;
+
+ ++args;
+ }
+ break;
+
+ case 's': {
+ char *s = (char *)args;
+ if (!s)
+ s = "<NULL>";
+
+ if (width > 0)
+ DebugOut().width(width);
+ if (leftjustify)
+ DebugOut().setf(ios::left);
+
+ DebugOut() << s;
+ ++args;
+ }
+ break;
+ case 'C':
+ case 'c': {
+ uint64_t mask = (*p == 'C') ? 0xffL : 0x7fL;
+ uint64_t num;
+ int width;
+
+ if (islong) {
+ num = (uint64_t)args;
+ width = sizeof(uint64_t);
+ } else {
+ num = (uint32_t)args;
+ width = sizeof(uint32_t);
+ }
+
+ while (width-- > 0) {
+ char c = (char)(num & mask);
+ if (c)
+ DebugOut() << c;
+ num >>= 8;
+ }
+
+ ++args;
+ }
+ break;
+ case 'b': {
+ uint64_t n = (uint64_t)args++;
+ char *s = (char *)args++;
+ DebugOut() << s << ": " << n;
+ }
+ break;
+ case 'n':
+ case 'N': {
+ args += 2;
+#if 0
+ uint64_t n = (uint64_t)args++;
+ struct reg_values *rv = (struct reg_values *)args++;
+#endif
+ }
+ break;
+ case 'r':
+ case 'R': {
+ args += 2;
+#if 0
+ uint64_t n = (uint64_t)args++;
+ struct reg_desc *rd = (struct reg_desc *)args++;
+#endif
+ }
+ break;
+ case '%':
+ DebugOut() << '%';
+ break;
+ }
+ ++p;
+ }
+ break;
+ case '\n':
+ DebugOut() << endl;
+ ++p;
+ break;
+ case '\r':
+ ++p;
+ if (*p != '\n')
+ DebugOut() << endl;
+ break;
+
+ default: {
+ size_t len = strcspn(p, "%\n\r\0");
+ DebugOut().write(p, len);
+ p += len;
+ }
+ }
+ }
+
+ DebugOut().flags(saved_flags);
+ DebugOut().fill(old_fill);
+ DebugOut().precision(old_precision);
+}
+
+} // namespace Tru64
diff --git a/src/kern/tru64/printf.hh b/src/kern/tru64/printf.hh
new file mode 100644
index 000000000..61236e83a
--- /dev/null
+++ b/src/kern/tru64/printf.hh
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __PRINTF_HH__
+#define __PRINTF_HH__
+
+#include "arch/arguments.hh"
+
+namespace tru64 {
+ void Printf(AlphaISA::AlphaArguments args);
+}
+
+#endif // __PRINTF_HH__
diff --git a/src/kern/tru64/tru64.hh b/src/kern/tru64/tru64.hh
new file mode 100644
index 000000000..91db5bb84
--- /dev/null
+++ b/src/kern/tru64/tru64.hh
@@ -0,0 +1,1240 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __TRU64_HH__
+#define __TRU64_HH__
+#include "config/full_system.hh"
+
+#if FULL_SYSTEM
+
+class Tru64 {};
+
+#else //!FULL_SYSTEM
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#if defined(__OpenBSD__) || defined(__APPLE__) || defined(__FreeBSD__)
+#include <sys/param.h>
+#include <sys/mount.h>
+#else
+#include <sys/statfs.h>
+#endif
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h> // for memset()
+#include <unistd.h>
+
+#include "cpu/base.hh"
+#include "sim/root.hh"
+#include "sim/syscall_emul.hh"
+
+typedef struct stat global_stat;
+typedef struct statfs global_statfs;
+typedef struct dirent global_dirent;
+
+class TranslatingPort;
+
+///
+/// This class encapsulates the types, structures, constants,
+/// functions, and syscall-number mappings specific to the Alpha Tru64
+/// syscall interface.
+///
+class Tru64 {
+
+ public:
+
+ //@{
+ /// Basic Tru64 types.
+ typedef uint64_t size_t;
+ typedef uint64_t off_t;
+ typedef uint16_t nlink_t;
+ typedef int32_t dev_t;
+ typedef uint32_t uid_t;
+ typedef uint32_t gid_t;
+ typedef uint32_t time_t;
+ typedef uint32_t mode_t;
+ typedef uint32_t ino_t;
+ typedef struct { int val[2]; } quad;
+ typedef quad fsid_t;
+ //@}
+
+ /// Stat buffer. Note that Tru64 v5.0+ use a new "F64" stat
+ /// structure, and a new set of syscall numbers for stat calls.
+ /// On some hosts (notably Linux) define st_atime, st_mtime, and
+ /// st_ctime as macros, so we append an X to get around this.
+ struct F64_stat {
+ dev_t st_dev; //!< st_dev
+ int32_t st_retired1; //!< st_retired1
+ mode_t st_mode; //!< st_mode
+ nlink_t st_nlink; //!< st_nlink
+ uint16_t st_nlink_reserved; //!< st_nlink_reserved
+ uid_t st_uid; //!< st_uid
+ gid_t st_gid; //!< st_gid
+ dev_t st_rdev; //!< st_rdev
+ dev_t st_ldev; //!< st_ldev
+ off_t st_size; //!< st_size
+ time_t st_retired2; //!< st_retired2
+ int32_t st_uatime; //!< st_uatime
+ time_t st_retired3; //!< st_retired3
+ int32_t st_umtime; //!< st_umtime
+ time_t st_retired4; //!< st_retired4
+ int32_t st_uctime; //!< st_uctime
+ int32_t st_retired5; //!< st_retired5
+ int32_t st_retired6; //!< st_retired6
+ uint32_t st_flags; //!< st_flags
+ uint32_t st_gen; //!< st_gen
+ uint64_t st_spare[4]; //!< st_spare[4]
+ ino_t st_ino; //!< st_ino
+ int32_t st_ino_reserved; //!< st_ino_reserved
+ time_t st_atimeX; //!< st_atime
+ int32_t st_atime_reserved; //!< st_atime_reserved
+ time_t st_mtimeX; //!< st_mtime
+ int32_t st_mtime_reserved; //!< st_mtime_reserved
+ time_t st_ctimeX; //!< st_ctime
+ int32_t st_ctime_reserved; //!< st_ctime_reserved
+ uint64_t st_blksize; //!< st_blksize
+ uint64_t st_blocks; //!< st_blocks
+ };
+
+
+ /// Old Tru64 v4.x stat struct.
+ /// Tru64 maintains backwards compatibility with v4.x by
+ /// implementing another set of stat functions using the old
+ /// structure definition and binding them to the old syscall
+ /// numbers.
+
+ struct pre_F64_stat {
+ dev_t st_dev;
+ ino_t st_ino;
+ mode_t st_mode;
+ nlink_t st_nlink;
+ uid_t st_uid __attribute__ ((aligned(sizeof(uid_t))));
+ gid_t st_gid;
+ dev_t st_rdev;
+ off_t st_size __attribute__ ((aligned(sizeof(off_t))));
+ time_t st_atimeX;
+ int32_t st_uatime;
+ time_t st_mtimeX;
+ int32_t st_umtime;
+ time_t st_ctimeX;
+ int32_t st_uctime;
+ uint32_t st_blksize;
+ int32_t st_blocks;
+ uint32_t st_flags;
+ uint32_t st_gen;
+ };
+
+ /// For statfs().
+ struct F64_statfs {
+ int16_t f_type;
+ int16_t f_flags;
+ int32_t f_retired1;
+ int32_t f_retired2;
+ int32_t f_retired3;
+ int32_t f_retired4;
+ int32_t f_retired5;
+ int32_t f_retired6;
+ int32_t f_retired7;
+ fsid_t f_fsid;
+ int32_t f_spare[9];
+ char f_retired8[90];
+ char f_retired9[90];
+ uint64_t dummy[10]; // was union mount_info mount_info;
+ uint64_t f_flags2;
+ int64_t f_spare2[14];
+ int64_t f_fsize;
+ int64_t f_bsize;
+ int64_t f_blocks;
+ int64_t f_bfree;
+ int64_t f_bavail;
+ int64_t f_files;
+ int64_t f_ffree;
+ char f_mntonname[1024];
+ char f_mntfromname[1024];
+ };
+
+ /// For old Tru64 v4.x statfs()
+ struct pre_F64_statfs {
+ int16_t f_type;
+ int16_t f_flags;
+ int32_t f_fsize;
+ int32_t f_bsize;
+ int32_t f_blocks;
+ int32_t f_bfree;
+ int32_t f_bavail;
+ int32_t f_files;
+ int32_t f_ffree;
+ fsid_t f_fsid;
+ int32_t f_spare[9];
+ char f_mntonname[90];
+ char f_mntfromname[90];
+ uint64_t dummy[10]; // was union mount_info mount_info;
+ };
+
+ /// For getdirentries().
+ struct dirent
+ {
+ ino_t d_ino; //!< file number of entry
+ uint16_t d_reclen; //!< length of this record
+ uint16_t d_namlen; //!< length of string in d_name
+ char d_name[256]; //!< dummy name length
+ };
+
+
+ /// Length of strings in struct utsname (plus 1 for null char).
+ static const int _SYS_NMLN = 32;
+
+ /// Interface struct for uname().
+ struct utsname {
+ char sysname[_SYS_NMLN]; //!< System name.
+ char nodename[_SYS_NMLN]; //!< Node name.
+ char release[_SYS_NMLN]; //!< OS release.
+ char version[_SYS_NMLN]; //!< OS version.
+ char machine[_SYS_NMLN]; //!< Machine type.
+ };
+
+ /// Limit struct for getrlimit/setrlimit.
+ struct rlimit {
+ uint64_t rlim_cur; //!< soft limit
+ uint64_t rlim_max; //!< hard limit
+ };
+
+
+ /// For getsysinfo() GSI_CPU_INFO option.
+ struct cpu_info {
+ uint32_t current_cpu; //!< current_cpu
+ uint32_t cpus_in_box; //!< cpus_in_box
+ uint32_t cpu_type; //!< cpu_type
+ uint32_t ncpus; //!< ncpus
+ uint64_t cpus_present; //!< cpus_present
+ uint64_t cpus_running; //!< cpus_running
+ uint64_t cpu_binding; //!< cpu_binding
+ uint64_t cpu_ex_binding; //!< cpu_ex_binding
+ uint32_t mhz; //!< mhz
+ uint32_t unused[3]; //!< future expansion
+ };
+
+ /// For gettimeofday.
+ struct timeval {
+ uint32_t tv_sec; //!< seconds
+ uint32_t tv_usec; //!< microseconds
+ };
+
+ /// For getrusage().
+ struct rusage {
+ struct timeval ru_utime; //!< user time used
+ struct timeval ru_stime; //!< system time used
+ uint64_t ru_maxrss; //!< ru_maxrss
+ uint64_t ru_ixrss; //!< integral shared memory size
+ uint64_t ru_idrss; //!< integral unshared data "
+ uint64_t ru_isrss; //!< integral unshared stack "
+ uint64_t ru_minflt; //!< page reclaims - total vmfaults
+ uint64_t ru_majflt; //!< page faults
+ uint64_t ru_nswap; //!< swaps
+ uint64_t ru_inblock; //!< block input operations
+ uint64_t ru_oublock; //!< block output operations
+ uint64_t ru_msgsnd; //!< messages sent
+ uint64_t ru_msgrcv; //!< messages received
+ uint64_t ru_nsignals; //!< signals received
+ uint64_t ru_nvcsw; //!< voluntary context switches
+ uint64_t ru_nivcsw; //!< involuntary "
+ };
+
+ /// For sigreturn().
+ struct sigcontext {
+ int64_t sc_onstack; //!< sigstack state to restore
+ int64_t sc_mask; //!< signal mask to restore
+ int64_t sc_pc; //!< pc at time of signal
+ int64_t sc_ps; //!< psl to retore
+ int64_t sc_regs[32]; //!< processor regs 0 to 31
+ int64_t sc_ownedfp; //!< fp has been used
+ int64_t sc_fpregs[32]; //!< fp regs 0 to 31
+ uint64_t sc_fpcr; //!< floating point control reg
+ uint64_t sc_fp_control; //!< software fpcr
+ int64_t sc_reserved1; //!< reserved for kernel
+ uint32_t sc_kreserved1; //!< reserved for kernel
+ uint32_t sc_kreserved2; //!< reserved for kernel
+ size_t sc_ssize; //!< stack size
+ caddr_t sc_sbase; //!< stack start
+ uint64_t sc_traparg_a0; //!< a0 argument to trap on exc
+ uint64_t sc_traparg_a1; //!< a1 argument to trap on exc
+ uint64_t sc_traparg_a2; //!< a2 argument to trap on exc
+ uint64_t sc_fp_trap_pc; //!< imprecise pc
+ uint64_t sc_fp_trigger_sum; //!< Exception summary at trigg
+ uint64_t sc_fp_trigger_inst; //!< Instruction at trigger pc
+ };
+
+
+
+ /// For table().
+ struct tbl_sysinfo {
+ uint64_t si_user; //!< User time
+ uint64_t si_nice; //!< Nice time
+ uint64_t si_sys; //!< System time
+ uint64_t si_idle; //!< Idle time
+ uint64_t si_hz; //!< hz
+ uint64_t si_phz; //!< phz
+ uint64_t si_boottime; //!< Boot time in seconds
+ uint64_t wait; //!< Wait time
+ uint32_t si_max_procs; //!< rpb->rpb_numprocs
+ uint32_t pad; //!< padding
+ };
+
+
+ /// For stack_create.
+ struct vm_stack {
+ // was void *
+ Addr address; //!< address hint
+ size_t rsize; //!< red zone size
+ size_t ysize; //!< yellow zone size
+ size_t gsize; //!< green zone size
+ size_t swap; //!< amount of swap to reserve
+ size_t incr; //!< growth increment
+ uint64_t align; //!< address alignment
+ uint64_t flags; //!< MAP_FIXED etc.
+ // was struct memalloc_attr *
+ Addr attr; //!< allocation policy
+ uint64_t reserved; //!< reserved
+ };
+
+ /// Return values for nxm calls.
+ enum {
+ KERN_NOT_RECEIVER = 7,
+ KERN_NOT_IN_SET = 12
+ };
+
+ /// For nxm_task_init.
+ static const int NXM_TASK_INIT_VP = 2; //!< initial thread is VP
+
+ /// Task attribute structure.
+ struct nxm_task_attr {
+ int64_t nxm_callback; //!< nxm_callback
+ unsigned int nxm_version; //!< nxm_version
+ unsigned short nxm_uniq_offset; //!< nxm_uniq_offset
+ unsigned short flags; //!< flags
+ int nxm_quantum; //!< nxm_quantum
+ int pad1; //!< pad1
+ int64_t pad2; //!< pad2
+ };
+
+ /// Signal set.
+ typedef uint64_t sigset_t;
+
+ /// Thread state shared between user & kernel.
+ struct ushared_state {
+ sigset_t sigmask; //!< thread signal mask
+ sigset_t sig; //!< thread pending mask
+ // struct nxm_pth_state *
+ Addr pth_id; //!< out-of-line state
+ int flags; //!< shared flags
+#define US_SIGSTACK 0x1 // thread called sigaltstack
+#define US_ONSTACK 0x2 // thread is running on altstack
+#define US_PROFILE 0x4 // thread called profil
+#define US_SYSCALL 0x8 // thread in syscall
+#define US_TRAP 0x10 // thread has trapped
+#define US_YELLOW 0x20 // thread has mellowed yellow
+#define US_YZONE 0x40 // thread has zoned out
+#define US_FP_OWNED 0x80 // thread used floating point
+
+ int cancel_state; //!< thread's cancelation state
+#define US_CANCEL 0x1 // cancel pending
+#define US_NOCANCEL 0X2 // synch cancel disabled
+#define US_SYS_NOCANCEL 0x4 // syscall cancel disabled
+#define US_ASYNC_NOCANCEL 0x8 // asynch cancel disabled
+#define US_CANCEL_BITS (US_NOCANCEL|US_SYS_NOCANCEL|US_ASYNC_NOCANCEL)
+#define US_CANCEL_MASK (US_CANCEL|US_NOCANCEL|US_SYS_NOCANCEL| \
+ US_ASYNC_NOCANCEL)
+
+ // These are semi-shared. They are always visible to
+ // the kernel but are never context-switched by the library.
+
+ int nxm_ssig; //!< scheduler's synchronous signals
+ int reserved1; //!< reserved1
+ int64_t nxm_active; //!< scheduler active
+ int64_t reserved2; //!< reserved2
+ };
+
+ struct nxm_sched_state {
+ struct ushared_state nxm_u; //!< state own by user thread
+ unsigned int nxm_bits; //!< scheduler state / slot
+ int nxm_quantum; //!< quantum count-down value
+ int nxm_set_quantum; //!< quantum reset value
+ int nxm_sysevent; //!< syscall state
+ // struct nxm_upcall *
+ Addr nxm_uc_ret; //!< stack ptr of null thread
+ // void *
+ Addr nxm_tid; //!< scheduler's thread id
+ int64_t nxm_va; //!< page fault address
+ // struct nxm_pth_state *
+ Addr nxm_pthid; //!< id of null thread
+ uint64_t nxm_bound_pcs_count; //!< bound PCS thread count
+ int64_t pad[2]; //!< pad
+ };
+
+ /// nxm_shared.
+ struct nxm_shared {
+ int64_t nxm_callback; //!< address of upcall routine
+ unsigned int nxm_version; //!< version number
+ unsigned short nxm_uniq_offset; //!< correction factor for TEB
+ unsigned short pad1; //!< pad1
+ int64_t space[2]; //!< future growth
+ struct nxm_sched_state nxm_ss[1]; //!< array of shared areas
+ };
+
+ /// nxm_slot_state_t.
+ enum nxm_slot_state_t {
+ NXM_SLOT_AVAIL,
+ NXM_SLOT_BOUND,
+ NXM_SLOT_UNBOUND,
+ NXM_SLOT_EMPTY
+ };
+
+ /// nxm_config_info
+ struct nxm_config_info {
+ int nxm_nslots_per_rad; //!< max number of VP slots per RAD
+ int nxm_nrads; //!< max number of RADs
+ // nxm_slot_state_t *
+ Addr nxm_slot_state; //!< per-VP slot state
+ // struct nxm_shared *
+ Addr nxm_rad[1]; //!< per-RAD shared areas
+ };
+
+ /// For nxm_thread_create.
+ enum nxm_thread_type {
+ NXM_TYPE_SCS = 0,
+ NXM_TYPE_VP = 1,
+ NXM_TYPE_MANAGER = 2
+ };
+
+ /// Thread attributes.
+ struct nxm_thread_attr {
+ int version; //!< version
+ int type; //!< type
+ int cancel_flags; //!< cancel_flags
+ int priority; //!< priority
+ int policy; //!< policy
+ int signal_type; //!< signal_type
+ // void *
+ Addr pthid; //!< pthid
+ sigset_t sigmask; //!< sigmask
+ /// Initial register values.
+ struct {
+ uint64_t pc; //!< pc
+ uint64_t sp; //!< sp
+ uint64_t a0; //!< a0
+ } registers;
+ uint64_t pad2[2]; //!< pad2
+ };
+
+ /// Helper function to convert a host stat buffer to a target stat
+ /// buffer. Also copies the target buffer out to the simulated
+ /// memory space. Used by stat(), fstat(), and lstat().
+ template <class T>
+ static void
+ copyOutStatBuf(TranslatingPort *mem, Addr addr, global_stat *host)
+ {
+ using namespace TheISA;
+
+ TypedBufferArg<T> tgt(addr);
+
+ tgt->st_dev = htog(host->st_dev);
+ tgt->st_ino = htog(host->st_ino);
+ tgt->st_mode = htog(host->st_mode);
+ tgt->st_nlink = htog(host->st_nlink);
+ tgt->st_uid = htog(host->st_uid);
+ tgt->st_gid = htog(host->st_gid);
+ tgt->st_rdev = htog(host->st_rdev);
+ tgt->st_size = htog(host->st_size);
+ tgt->st_atimeX = htog(host->st_atime);
+ tgt->st_mtimeX = htog(host->st_mtime);
+ tgt->st_ctimeX = htog(host->st_ctime);
+ tgt->st_blksize = htog(host->st_blksize);
+ tgt->st_blocks = htog(host->st_blocks);
+
+ tgt.copyOut(mem);
+ }
+
+ /// Helper function to convert a host statfs buffer to a target statfs
+ /// buffer. Also copies the target buffer out to the simulated
+ /// memory space. Used by statfs() and fstatfs().
+ template <class T>
+ static void
+ copyOutStatfsBuf(TranslatingPort *mem, Addr addr, global_statfs *host)
+ {
+ using namespace TheISA;
+
+ TypedBufferArg<T> tgt(addr);
+
+#if defined(__OpenBSD__) || defined(__APPLE__) || defined(__FreeBSD__)
+ tgt->f_type = 0;
+#else
+ tgt->f_type = htog(host->f_type);
+#endif
+ tgt->f_bsize = htog(host->f_bsize);
+ tgt->f_blocks = htog(host->f_blocks);
+ tgt->f_bfree = htog(host->f_bfree);
+ tgt->f_bavail = htog(host->f_bavail);
+ tgt->f_files = htog(host->f_files);
+ tgt->f_ffree = htog(host->f_ffree);
+
+ // Is this as string normally?
+ memcpy(&tgt->f_fsid, &host->f_fsid, sizeof(host->f_fsid));
+
+ tgt.copyOut(mem);
+ }
+
+ class F64 {
+ public:
+ static void copyOutStatBuf(TranslatingPort *mem, Addr addr,
+ global_stat *host)
+ {
+ Tru64::copyOutStatBuf<Tru64::F64_stat>(mem, addr, host);
+ }
+
+ static void copyOutStatfsBuf(TranslatingPort *mem, Addr addr,
+ global_statfs *host)
+ {
+ Tru64::copyOutStatfsBuf<Tru64::F64_statfs>(mem, addr, host);
+ }
+ };
+
+ class PreF64 {
+ public:
+ static void copyOutStatBuf(TranslatingPort *mem, Addr addr,
+ global_stat *host)
+ {
+ Tru64::copyOutStatBuf<Tru64::pre_F64_stat>(mem, addr, host);
+ }
+
+ static void copyOutStatfsBuf(TranslatingPort *mem, Addr addr,
+ global_statfs *host)
+ {
+ Tru64::copyOutStatfsBuf<Tru64::pre_F64_statfs>(mem, addr, host);
+ }
+ };
+
+ /// Helper function to convert a host stat buffer to an old pre-F64
+ /// (4.x) target stat buffer. Also copies the target buffer out to
+ /// the simulated memory space. Used by pre_F64_stat(),
+ /// pre_F64_fstat(), and pre_F64_lstat().
+ static void
+ copyOutPreF64StatBuf(TranslatingPort *mem, Addr addr, struct stat *host)
+ {
+ using namespace TheISA;
+
+ TypedBufferArg<Tru64::pre_F64_stat> tgt(addr);
+
+ tgt->st_dev = htog(host->st_dev);
+ tgt->st_ino = htog(host->st_ino);
+ tgt->st_mode = htog(host->st_mode);
+ tgt->st_nlink = htog(host->st_nlink);
+ tgt->st_uid = htog(host->st_uid);
+ tgt->st_gid = htog(host->st_gid);
+ tgt->st_rdev = htog(host->st_rdev);
+ tgt->st_size = htog(host->st_size);
+ tgt->st_atimeX = htog(host->st_atime);
+ tgt->st_mtimeX = htog(host->st_mtime);
+ tgt->st_ctimeX = htog(host->st_ctime);
+ tgt->st_blksize = htog(host->st_blksize);
+ tgt->st_blocks = htog(host->st_blocks);
+
+ tgt.copyOut(mem);
+ }
+
+
+ /// The target system's hostname.
+ static const char *hostname;
+
+
+ /// Target getdirentries() handler.
+ static SyscallReturn
+ getdirentriesFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+ {
+ using namespace TheISA;
+
+#ifdef __CYGWIN__
+ panic("getdirent not implemented on cygwin!");
+#else
+ int fd = process->sim_fd(xc->getSyscallArg(0));
+ Addr tgt_buf = xc->getSyscallArg(1);
+ int tgt_nbytes = xc->getSyscallArg(2);
+ Addr tgt_basep = xc->getSyscallArg(3);
+
+ char * const host_buf = new char[tgt_nbytes];
+
+ // just pass basep through uninterpreted.
+ TypedBufferArg<int64_t> basep(tgt_basep);
+ basep.copyIn(xc->getMemPort());
+ long host_basep = (off_t)htog((int64_t)*basep);
+ int host_result = getdirentries(fd, host_buf, tgt_nbytes, &host_basep);
+
+ // check for error
+ if (host_result < 0) {
+ delete [] host_buf;
+ return -errno;
+ }
+
+ // no error: copy results back to target space
+ Addr tgt_buf_ptr = tgt_buf;
+ char *host_buf_ptr = host_buf;
+ char *host_buf_end = host_buf + host_result;
+ while (host_buf_ptr < host_buf_end) {
+ global_dirent *host_dp = (global_dirent *)host_buf_ptr;
+ int namelen = strlen(host_dp->d_name);
+
+ // Actual size includes padded string rounded up for alignment.
+ // Subtract 256 for dummy char array in Tru64::dirent definition.
+ // Add 1 to namelen for terminating null char.
+ int tgt_bufsize = sizeof(Tru64::dirent) - 256 + roundUp(namelen+1, 8);
+ TypedBufferArg<Tru64::dirent> tgt_dp(tgt_buf_ptr, tgt_bufsize);
+ tgt_dp->d_ino = host_dp->d_ino;
+ tgt_dp->d_reclen = tgt_bufsize;
+ tgt_dp->d_namlen = namelen;
+ strcpy(tgt_dp->d_name, host_dp->d_name);
+ tgt_dp.copyOut(xc->getMemPort());
+
+ tgt_buf_ptr += tgt_bufsize;
+ host_buf_ptr += host_dp->d_reclen;
+ }
+
+ delete [] host_buf;
+
+ *basep = htog((int64_t)host_basep);
+ basep.copyOut(xc->getMemPort());
+
+ return tgt_buf_ptr - tgt_buf;
+#endif
+ }
+
+ /// Target sigreturn() handler.
+ static SyscallReturn
+ sigreturnFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+ {
+ using namespace TheISA;
+
+ using TheISA::RegFile;
+ TypedBufferArg<Tru64::sigcontext> sc(xc->getSyscallArg(0));
+
+ sc.copyIn(xc->getMemPort());
+
+ // Restore state from sigcontext structure.
+ // Note that we'll advance PC <- NPC before the end of the cycle,
+ // so we need to restore the desired PC into NPC.
+ // The current regs->pc will get clobbered.
+ xc->setNextPC(htog(sc->sc_pc));
+
+ for (int i = 0; i < 31; ++i) {
+ xc->setIntReg(i, htog(sc->sc_regs[i]));
+ xc->setFloatRegBits(i, htog(sc->sc_fpregs[i]));
+ }
+
+ xc->setMiscReg(TheISA::Fpcr_DepTag, htog(sc->sc_fpcr));
+
+ return 0;
+ }
+
+
+ //
+ // Mach syscalls -- identified by negated syscall numbers
+ //
+
+ /// Create a stack region for a thread.
+ static SyscallReturn
+ stack_createFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+ {
+ using namespace TheISA;
+
+ TypedBufferArg<Tru64::vm_stack> argp(xc->getSyscallArg(0));
+
+ argp.copyIn(xc->getMemPort());
+
+ // if the user chose an address, just let them have it. Otherwise
+ // pick one for them.
+ if (htog(argp->address) == 0) {
+ argp->address = htog(process->next_thread_stack_base);
+ int stack_size = (htog(argp->rsize) + htog(argp->ysize) +
+ htog(argp->gsize));
+ process->next_thread_stack_base -= stack_size;
+ argp.copyOut(xc->getMemPort());
+ }
+
+ return 0;
+ }
+
+ /// NXM library version stamp.
+ static
+ const int NXM_LIB_VERSION = 301003;
+
+ /// This call sets up the interface between the user and kernel
+ /// schedulers by creating a shared-memory region. The shared memory
+ /// region has several structs, some global, some per-RAD, some per-VP.
+ static SyscallReturn
+ nxm_task_initFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+ {
+ using namespace std;
+ using namespace TheISA;
+
+ TypedBufferArg<Tru64::nxm_task_attr> attrp(xc->getSyscallArg(0));
+ TypedBufferArg<Addr> configptr_ptr(xc->getSyscallArg(1));
+
+ attrp.copyIn(xc->getMemPort());
+
+ if (gtoh(attrp->nxm_version) != NXM_LIB_VERSION) {
+ cerr << "nxm_task_init: thread library version mismatch! "
+ << "got " << attrp->nxm_version
+ << ", expected " << NXM_LIB_VERSION << endl;
+ abort();
+ }
+
+ if (gtoh(attrp->flags) != Tru64::NXM_TASK_INIT_VP) {
+ cerr << "nxm_task_init: bad flag value " << attrp->flags
+ << " (expected " << Tru64::NXM_TASK_INIT_VP << ")" << endl;
+ abort();
+ }
+
+ const Addr base_addr = 0x12000; // was 0x3f0000000LL;
+ Addr cur_addr = base_addr; // next addresses to use
+ // first comes the config_info struct
+ Addr config_addr = cur_addr;
+ cur_addr += sizeof(Tru64::nxm_config_info);
+ // next comes the per-cpu state vector
+ Addr slot_state_addr = cur_addr;
+ int slot_state_size =
+ process->numCpus() * sizeof(Tru64::nxm_slot_state_t);
+ cur_addr += slot_state_size;
+ // now the per-RAD state struct (we only support one RAD)
+ cur_addr = 0x14000; // bump up addr for alignment
+ Addr rad_state_addr = cur_addr;
+ int rad_state_size =
+ (sizeof(Tru64::nxm_shared)
+ + (process->numCpus()-1) * sizeof(Tru64::nxm_sched_state));
+ cur_addr += rad_state_size;
+
+ // now initialize a config_info struct and copy it out to user space
+ TypedBufferArg<Tru64::nxm_config_info> config(config_addr);
+
+ config->nxm_nslots_per_rad = htog(process->numCpus());
+ config->nxm_nrads = htog(1); // only one RAD in our system!
+ config->nxm_slot_state = htog(slot_state_addr);
+ config->nxm_rad[0] = htog(rad_state_addr);
+
+ config.copyOut(xc->getMemPort());
+
+ // initialize the slot_state array and copy it out
+ TypedBufferArg<Tru64::nxm_slot_state_t> slot_state(slot_state_addr,
+ slot_state_size);
+ for (int i = 0; i < process->numCpus(); ++i) {
+ // CPU 0 is bound to the calling process; all others are available
+ // XXX this code should have an endian conversion, but I don't think
+ // it works anyway
+ slot_state[i] =
+ (i == 0) ? Tru64::NXM_SLOT_BOUND : Tru64::NXM_SLOT_AVAIL;
+ }
+
+ slot_state.copyOut(xc->getMemPort());
+
+ // same for the per-RAD "shared" struct. Note that we need to
+ // allocate extra bytes for the per-VP array which is embedded at
+ // the end.
+ TypedBufferArg<Tru64::nxm_shared> rad_state(rad_state_addr,
+ rad_state_size);
+
+ rad_state->nxm_callback = attrp->nxm_callback;
+ rad_state->nxm_version = attrp->nxm_version;
+ rad_state->nxm_uniq_offset = attrp->nxm_uniq_offset;
+ for (int i = 0; i < process->numCpus(); ++i) {
+ Tru64::nxm_sched_state *ssp = &rad_state->nxm_ss[i];
+ ssp->nxm_u.sigmask = htog(0);
+ ssp->nxm_u.sig = htog(0);
+ ssp->nxm_u.flags = htog(0);
+ ssp->nxm_u.cancel_state = htog(0);
+ ssp->nxm_u.nxm_ssig = 0;
+ ssp->nxm_bits = htog(0);
+ ssp->nxm_quantum = attrp->nxm_quantum;
+ ssp->nxm_set_quantum = attrp->nxm_quantum;
+ ssp->nxm_sysevent = htog(0);
+
+ if (i == 0) {
+ uint64_t uniq = xc->readMiscReg(TheISA::Uniq_DepTag);
+ ssp->nxm_u.pth_id = htog(uniq + gtoh(attrp->nxm_uniq_offset));
+ ssp->nxm_u.nxm_active = htog(uniq | 1);
+ }
+ else {
+ ssp->nxm_u.pth_id = htog(0);
+ ssp->nxm_u.nxm_active = htog(0);
+ }
+ }
+
+ rad_state.copyOut(xc->getMemPort());
+
+ //
+ // copy pointer to shared config area out to user
+ //
+ *configptr_ptr = htog(config_addr);
+ configptr_ptr.copyOut(xc->getMemPort());
+
+ // Register this as a valid address range with the process
+ process->nxm_start = base_addr;
+ process->nxm_end = cur_addr;
+
+ return 0;
+ }
+
+ /// Initialize execution context.
+ static void
+ init_exec_context(ExecContext *ec,
+ Tru64::nxm_thread_attr *attrp, uint64_t uniq_val)
+ {
+ using namespace TheISA;
+
+ ec->clearArchRegs();
+
+ ec->setIntReg(TheISA::ArgumentReg0, gtoh(attrp->registers.a0));
+ ec->setIntReg(27/*t12*/, gtoh(attrp->registers.pc));
+ ec->setIntReg(TheISA::StackPointerReg, gtoh(attrp->registers.sp));
+ ec->setMiscReg(TheISA::Uniq_DepTag, uniq_val);
+
+ ec->setPC(gtoh(attrp->registers.pc));
+ ec->setNextPC(gtoh(attrp->registers.pc) + sizeof(TheISA::MachInst));
+
+ ec->activate();
+ }
+
+ /// Create thread.
+ static SyscallReturn
+ nxm_thread_createFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+ {
+ using namespace std;
+ using namespace TheISA;
+
+ TypedBufferArg<Tru64::nxm_thread_attr> attrp(xc->getSyscallArg(0));
+ TypedBufferArg<uint64_t> kidp(xc->getSyscallArg(1));
+ int thread_index = xc->getSyscallArg(2);
+
+ // get attribute args
+ attrp.copyIn(xc->getMemPort());
+
+ if (gtoh(attrp->version) != NXM_LIB_VERSION) {
+ cerr << "nxm_thread_create: thread library version mismatch! "
+ << "got " << attrp->version
+ << ", expected " << NXM_LIB_VERSION << endl;
+ abort();
+ }
+
+ if (thread_index < 0 | thread_index > process->numCpus()) {
+ cerr << "nxm_thread_create: bad thread index " << thread_index
+ << endl;
+ abort();
+ }
+
+ // On a real machine, the per-RAD shared structure is in
+ // shared memory, so both the user and kernel can get at it.
+ // We don't have that luxury, so we just copy it in and then
+ // back out again.
+ int rad_state_size =
+ (sizeof(Tru64::nxm_shared) +
+ (process->numCpus()-1) * sizeof(Tru64::nxm_sched_state));
+
+ TypedBufferArg<Tru64::nxm_shared> rad_state(0x14000,
+ rad_state_size);
+ rad_state.copyIn(xc->getMemPort());
+
+ uint64_t uniq_val = gtoh(attrp->pthid) - gtoh(rad_state->nxm_uniq_offset);
+
+ if (gtoh(attrp->type) == Tru64::NXM_TYPE_MANAGER) {
+ // DEC pthreads seems to always create one of these (in
+ // addition to N application threads), but we don't use it,
+ // so don't bother creating it.
+
+ // This is supposed to be a port number. Make something up.
+ *kidp = htog(99);
+ kidp.copyOut(xc->getMemPort());
+
+ return 0;
+ } else if (gtoh(attrp->type) == Tru64::NXM_TYPE_VP) {
+ // A real "virtual processor" kernel thread. Need to fork
+ // this thread on another CPU.
+ Tru64::nxm_sched_state *ssp = &rad_state->nxm_ss[thread_index];
+
+ if (gtoh(ssp->nxm_u.nxm_active) != 0)
+ return (int) Tru64::KERN_NOT_RECEIVER;
+
+ ssp->nxm_u.pth_id = attrp->pthid;
+ ssp->nxm_u.nxm_active = htog(uniq_val | 1);
+
+ rad_state.copyOut(xc->getMemPort());
+
+ Addr slot_state_addr = 0x12000 + sizeof(Tru64::nxm_config_info);
+ int slot_state_size =
+ process->numCpus() * sizeof(Tru64::nxm_slot_state_t);
+
+ TypedBufferArg<Tru64::nxm_slot_state_t>
+ slot_state(slot_state_addr,
+ slot_state_size);
+
+ slot_state.copyIn(xc->getMemPort());
+
+ if (slot_state[thread_index] != Tru64::NXM_SLOT_AVAIL) {
+ cerr << "nxm_thread_createFunc: requested VP slot "
+ << thread_index << " not available!" << endl;
+ fatal("");
+ }
+
+ // XXX This should have an endian conversion but I think this code
+ // doesn't work anyway
+ slot_state[thread_index] = Tru64::NXM_SLOT_BOUND;
+
+ slot_state.copyOut(xc->getMemPort());
+
+ // Find a free simulator execution context.
+ for (int i = 0; i < process->numCpus(); ++i) {
+ ExecContext *xc = process->execContexts[i];
+
+ if (xc->status() == ExecContext::Unallocated) {
+ // inactive context... grab it
+ init_exec_context(xc, attrp, uniq_val);
+
+ // This is supposed to be a port number, but we'll try
+ // and get away with just sticking the thread index
+ // here.
+ *kidp = htog(thread_index);
+ kidp.copyOut(xc->getMemPort());
+
+ return 0;
+ }
+ }
+
+ // fell out of loop... no available inactive context
+ cerr << "nxm_thread_create: no idle contexts available." << endl;
+ abort();
+ } else {
+ cerr << "nxm_thread_create: can't handle thread type "
+ << attrp->type << endl;
+ abort();
+ }
+
+ return 0;
+ }
+
+ /// Thread idle call (like yield()).
+ static SyscallReturn
+ nxm_idleFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+ {
+ return 0;
+ }
+
+ /// Block thread.
+ static SyscallReturn
+ nxm_thread_blockFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+ {
+ using namespace std;
+
+ uint64_t tid = xc->getSyscallArg(0);
+ uint64_t secs = xc->getSyscallArg(1);
+ uint64_t flags = xc->getSyscallArg(2);
+ uint64_t action = xc->getSyscallArg(3);
+ uint64_t usecs = xc->getSyscallArg(4);
+
+ cout << xc->getCpuPtr()->name() << ": nxm_thread_block " << tid << " "
+ << secs << " " << flags << " " << action << " " << usecs << endl;
+
+ return 0;
+ }
+
+ /// block.
+ static SyscallReturn
+ nxm_blockFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+ {
+ using namespace std;
+
+ Addr uaddr = xc->getSyscallArg(0);
+ uint64_t val = xc->getSyscallArg(1);
+ uint64_t secs = xc->getSyscallArg(2);
+ uint64_t usecs = xc->getSyscallArg(3);
+ uint64_t flags = xc->getSyscallArg(4);
+
+ BaseCPU *cpu = xc->getCpuPtr();
+
+ cout << cpu->name() << ": nxm_block "
+ << hex << uaddr << dec << " " << val
+ << " " << secs << " " << usecs
+ << " " << flags << endl;
+
+ return 0;
+ }
+
+ /// Unblock thread.
+ static SyscallReturn
+ nxm_unblockFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+ {
+ using namespace std;
+
+ Addr uaddr = xc->getSyscallArg(0);
+
+ cout << xc->getCpuPtr()->name() << ": nxm_unblock "
+ << hex << uaddr << dec << endl;
+
+ return 0;
+ }
+
+ /// Switch thread priority.
+ static SyscallReturn
+ swtch_priFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+ {
+ // Attempts to switch to another runnable thread (if there is
+ // one). Returns false if there are no other threads to run
+ // (i.e., the thread can reasonably spin-wait) or true if there
+ // are other threads.
+ //
+ // Since we assume at most one "kernel" thread per CPU, it's
+ // always safe to return false here.
+ return 0; //false;
+ }
+
+
+ /// Activate exec context waiting on a channel. Just activate one
+ /// by default.
+ static int
+ activate_waiting_context(Addr uaddr, Process *process,
+ bool activate_all = false)
+ {
+ using namespace std;
+
+ int num_activated = 0;
+
+ list<Process::WaitRec>::iterator i = process->waitList.begin();
+ list<Process::WaitRec>::iterator end = process->waitList.end();
+
+ while (i != end && (num_activated == 0 || activate_all)) {
+ if (i->waitChan == uaddr) {
+ // found waiting process: make it active
+ ExecContext *newCtx = i->waitingContext;
+ assert(newCtx->status() == ExecContext::Suspended);
+ newCtx->activate();
+
+ // get rid of this record
+ i = process->waitList.erase(i);
+
+ ++num_activated;
+ } else {
+ ++i;
+ }
+ }
+
+ return num_activated;
+ }
+
+ /// M5 hacked-up lock acquire.
+ static void
+ m5_lock_mutex(Addr uaddr, Process *process, ExecContext *xc)
+ {
+ using namespace TheISA;
+
+ TypedBufferArg<uint64_t> lockp(uaddr);
+
+ lockp.copyIn(xc->getMemPort());
+
+ if (gtoh(*lockp) == 0) {
+ // lock is free: grab it
+ *lockp = htog(1);
+ lockp.copyOut(xc->getMemPort());
+ } else {
+ // lock is busy: disable until free
+ process->waitList.push_back(Process::WaitRec(uaddr, xc));
+ xc->suspend();
+ }
+ }
+
+ /// M5 unlock call.
+ static void
+ m5_unlock_mutex(Addr uaddr, Process *process, ExecContext *xc)
+ {
+ TypedBufferArg<uint64_t> lockp(uaddr);
+
+ lockp.copyIn(xc->getMemPort());
+ assert(*lockp != 0);
+
+ // Check for a process waiting on the lock.
+ int num_waiting = activate_waiting_context(uaddr, process);
+
+ // clear lock field if no waiting context is taking over the lock
+ if (num_waiting == 0) {
+ *lockp = 0;
+ lockp.copyOut(xc->getMemPort());
+ }
+ }
+
+ /// Lock acquire syscall handler.
+ static SyscallReturn
+ m5_mutex_lockFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+ {
+ Addr uaddr = xc->getSyscallArg(0);
+
+ m5_lock_mutex(uaddr, process, xc);
+
+ // Return 0 since we will always return to the user with the lock
+ // acquired. We will just keep the context inactive until that is
+ // true.
+ return 0;
+ }
+
+ /// Try lock (non-blocking).
+ static SyscallReturn
+ m5_mutex_trylockFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+ {
+ using namespace TheISA;
+
+ Addr uaddr = xc->getSyscallArg(0);
+ TypedBufferArg<uint64_t> lockp(uaddr);
+
+ lockp.copyIn(xc->getMemPort());
+
+ if (gtoh(*lockp) == 0) {
+ // lock is free: grab it
+ *lockp = htog(1);
+ lockp.copyOut(xc->getMemPort());
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+
+ /// Unlock syscall handler.
+ static SyscallReturn
+ m5_mutex_unlockFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+ {
+ Addr uaddr = xc->getSyscallArg(0);
+
+ m5_unlock_mutex(uaddr, process, xc);
+
+ return 0;
+ }
+
+ /// Signal ocndition.
+ static SyscallReturn
+ m5_cond_signalFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+ {
+ Addr cond_addr = xc->getSyscallArg(0);
+
+ // Wake up one process waiting on the condition variable.
+ activate_waiting_context(cond_addr, process);
+
+ return 0;
+ }
+
+ /// Wake up all processes waiting on the condition variable.
+ static SyscallReturn
+ m5_cond_broadcastFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+ {
+ Addr cond_addr = xc->getSyscallArg(0);
+
+ activate_waiting_context(cond_addr, process, true);
+
+ return 0;
+ }
+
+ /// Wait on a condition.
+ static SyscallReturn
+ m5_cond_waitFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+ {
+ using namespace TheISA;
+
+ Addr cond_addr = xc->getSyscallArg(0);
+ Addr lock_addr = xc->getSyscallArg(1);
+ TypedBufferArg<uint64_t> condp(cond_addr);
+ TypedBufferArg<uint64_t> lockp(lock_addr);
+
+ // user is supposed to acquire lock before entering
+ lockp.copyIn(xc->getMemPort());
+ assert(gtoh(*lockp) != 0);
+
+ m5_unlock_mutex(lock_addr, process, xc);
+
+ process->waitList.push_back(Process::WaitRec(cond_addr, xc));
+ xc->suspend();
+
+ return 0;
+ }
+
+ /// Thread exit.
+ static SyscallReturn
+ m5_thread_exitFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+ {
+ assert(xc->status() == ExecContext::Active);
+ xc->deallocate();
+
+ return 0;
+ }
+
+ /// Indirect syscall invocation (call #0).
+ static SyscallReturn
+ indirectSyscallFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+ {
+ int new_callnum = xc->getSyscallArg(0);
+ LiveProcess *lp = dynamic_cast<LiveProcess*>(process);
+ assert(lp);
+
+ for (int i = 0; i < 5; ++i)
+ xc->setSyscallArg(i, xc->getSyscallArg(i+1));
+
+
+ SyscallDesc *new_desc = lp->getDesc(new_callnum);
+ if (desc == NULL)
+ fatal("Syscall %d out of range", callnum);
+
+ new_desc->doSyscall(new_callnum, process, xc);
+
+ return 0;
+ }
+
+}; // class Tru64
+
+
+#endif // FULL_SYSTEM
+
+#endif // __TRU64_HH__
diff --git a/src/kern/tru64/tru64_events.cc b/src/kern/tru64/tru64_events.cc
new file mode 100644
index 000000000..69fc5c55d
--- /dev/null
+++ b/src/kern/tru64/tru64_events.cc
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "cpu/exec_context.hh"
+#include "cpu/base.hh"
+#include "kern/system_events.hh"
+#include "kern/tru64/tru64_events.hh"
+#include "kern/tru64/dump_mbuf.hh"
+#include "kern/tru64/printf.hh"
+#include "arch/alpha/ev5.hh"
+#include "arch/arguments.hh"
+#include "arch/isa_traits.hh"
+#include "sim/system.hh"
+
+using namespace TheISA;
+
+//void SkipFuncEvent::process(ExecContext *xc);
+
+void
+BadAddrEvent::process(ExecContext *xc)
+{
+ // The following gross hack is the equivalent function to the
+ // annotation for vmunix::badaddr in:
+ // simos/simulation/apps/tcl/osf/tlaser.tcl
+
+ uint64_t a0 = xc->readIntReg(ArgumentReg0);
+
+ AddrRangeList resp;
+ AddrRangeList snoop;
+ AddrRangeIter iter;
+ bool found = false;
+
+ xc->getPhysPort()->getPeerAddressRanges(resp, snoop);
+ for(iter = resp.begin(); iter != resp.end(); iter++)
+ {
+ if (*iter == (TheISA::K0Seg2Phys(a0) & EV5::PAddrImplMask))
+ found = true;
+ }
+
+ if (!TheISA::IsK0Seg(a0) || found ) {
+
+ DPRINTF(BADADDR, "badaddr arg=%#x bad\n", a0);
+ xc->setIntReg(ReturnValueReg, 0x1);
+ SkipFuncEvent::process(xc);
+ }
+ else
+ DPRINTF(BADADDR, "badaddr arg=%#x good\n", a0);
+}
+
+void
+PrintfEvent::process(ExecContext *xc)
+{
+ if (DTRACE(Printf)) {
+ DebugOut() << curTick << ": " << xc->getCpuPtr()->name() << ": ";
+
+ AlphaArguments args(xc);
+ tru64::Printf(args);
+ }
+}
+
+void
+DebugPrintfEvent::process(ExecContext *xc)
+{
+ if (DTRACE(DebugPrintf)) {
+ if (!raw)
+ DebugOut() << curTick << ": " << xc->getCpuPtr()->name() << ": ";
+
+ AlphaArguments args(xc);
+ tru64::Printf(args);
+ }
+}
+
+void
+DumpMbufEvent::process(ExecContext *xc)
+{
+ if (DTRACE(DebugPrintf)) {
+ AlphaArguments args(xc);
+ tru64::DumpMbuf(args);
+ }
+}
diff --git a/src/kern/tru64/tru64_events.hh b/src/kern/tru64/tru64_events.hh
new file mode 100644
index 000000000..9b5bcfea2
--- /dev/null
+++ b/src/kern/tru64/tru64_events.hh
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __TRU64_EVENTS_HH__
+#define __TRU64_EVENTS_HH__
+
+#include <string>
+
+#include "cpu/pc_event.hh"
+#include "kern/system_events.hh"
+
+class ExecContext;
+
+class BadAddrEvent : public SkipFuncEvent
+{
+ public:
+ BadAddrEvent(PCEventQueue *q, const std::string &desc, Addr addr)
+ : SkipFuncEvent(q, desc, addr) {}
+ virtual void process(ExecContext *xc);
+};
+
+class PrintfEvent : public PCEvent
+{
+ public:
+ PrintfEvent(PCEventQueue *q, const std::string &desc, Addr addr)
+ : PCEvent(q, desc, addr) {}
+ virtual void process(ExecContext *xc);
+};
+
+class DebugPrintfEvent : public PCEvent
+{
+ private:
+ bool raw;
+
+ public:
+ DebugPrintfEvent(PCEventQueue *q, const std::string &desc, Addr addr,
+ bool r = false)
+ : PCEvent(q, desc, addr), raw(r) {}
+ virtual void process(ExecContext *xc);
+};
+
+class DebugPrintfrEvent : public DebugPrintfEvent
+{
+ public:
+ DebugPrintfrEvent(PCEventQueue *q, const std::string &desc, Addr addr)
+ : DebugPrintfEvent(q, desc, addr, true)
+ {}
+};
+
+class DumpMbufEvent : public PCEvent
+{
+ public:
+ DumpMbufEvent(PCEventQueue *q, const std::string &desc, Addr addr)
+ : PCEvent(q, desc, addr) {}
+ virtual void process(ExecContext *xc);
+};
+
+#endif // __TRU64_EVENTS_HH__
diff --git a/src/kern/tru64/tru64_syscalls.cc b/src/kern/tru64/tru64_syscalls.cc
new file mode 100644
index 000000000..8aa57dbaa
--- /dev/null
+++ b/src/kern/tru64/tru64_syscalls.cc
@@ -0,0 +1,438 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "kern/tru64/tru64_syscalls.hh"
+
+namespace {
+ const char *
+ standard_strings[SystemCalls<Tru64>::StandardNumber] = {
+ "syscall", // 0
+ "exit", // 1
+ "fork", // 2
+ "read", // 3
+ "write", // 4
+ "old_open", // 5
+ "close", // 6
+ "wait4", // 7
+ "old_creat", // 8
+ "link", // 9
+
+ "unlink", // 10
+ "execv", // 11
+ "chdir", // 12
+ "fchdir", // 13
+ "mknod", // 14
+ "chmod", // 15
+ "chown", // 16
+ "obreak", // 17
+ "pre_F64_getfsstat", // 18
+ "lseek", // 19
+
+ "getpid", // 20
+ "mount", // 21
+ "unmount", // 22
+ "setuid", // 23
+ "getuid", // 24
+ "exec_with_loader", // 25
+ "ptrace", // 26
+ "recvmsg", // 27
+ "sendmsg", // 28
+ "recvfrom", // 29
+
+ "accept", // 30
+ "getpeername", // 31
+ "getsockname", // 32
+ "access", // 33
+ "chflags", // 34
+ "fchflags", // 35
+ "sync", // 36
+ "kill", // 37
+ "old_stat", // 38
+ "setpgid", // 39
+
+ "old_lstat", // 40
+ "dup", // 41
+ "pipe", // 42
+ "set_program_attributes", // 43
+ "profil", // 44
+ "open", // 45
+ "obsolete_osigaction", // 46
+ "getgid", // 47
+ "sigprocmask", // 48
+ "getlogin", // 49
+
+ "setlogin", // 50
+ "acct", // 51
+ "sigpending", // 52
+ "classcntl", // 53
+ "ioctl", // 54
+ "reboot", // 55
+ "revoke", // 56
+ "symlink", // 57
+ "readlink", // 58
+ "execve", // 59
+
+ "umask", // 60
+ "chroot", // 61
+ "old_fstat", // 62
+ "getpgrp", // 63
+ "getpagesize", // 64
+ "mremap", // 65
+ "vfork", // 66
+ "pre_F64_stat", // 67
+ "pre_F64_lstat", // 68
+ "sbrk", // 69
+
+ "sstk", // 70
+ "mmap", // 71
+ "ovadvise", // 72
+ "munmap", // 73
+ "mprotect", // 74
+ "madvise", // 75
+ "old_vhangup", // 76
+ "kmodcall", // 77
+ "mincore", // 78
+ "getgroups", // 79
+
+ "setgroups", // 80
+ "old_getpgrp", // 81
+ "setpgrp", // 82
+ "setitimer", // 83
+ "old_wait", // 84
+ "table", // 85
+ "getitimer", // 86
+ "gethostname", // 87
+ "sethostname", // 88
+ "getdtablesize", // 89
+
+ "dup2", // 90
+ "pre_F64_fstat", // 91
+ "fcntl", // 92
+ "select", // 93
+ "poll", // 94
+ "fsync", // 95
+ "setpriority", // 96
+ "socket", // 97
+ "connect", // 98
+ "old_accept", // 99
+
+ "getpriority", // 100
+ "old_send", // 101
+ "old_recv", // 102
+ "sigreturn", // 103
+ "bind", // 104
+ "setsockopt", // 105
+ "listen", // 106
+ "plock", // 107
+ "old_sigvec", // 108
+ "old_sigblock", // 109
+
+ "old_sigsetmask", // 110
+ "sigsuspend", // 111
+ "sigstack", // 112
+ "old_recvmsg", // 113
+ "old_sendmsg", // 114
+ "obsolete_vtrcae", // 115
+ "gettimeofday", // 116
+ "getrusage", // 117
+ "getsockopt", // 118
+ "numa_syscalls", // 119
+
+ "readv", // 120
+ "writev", // 121
+ "settimeofday", // 122
+ "fchown", // 123
+ "fchmod", // 124
+ "old_recvfrom", // 125
+ "setreuid", // 126
+ "setregid", // 127
+ "rename", // 128
+ "truncate", // 129
+
+ "ftruncate", // 130
+ "flock", // 131
+ "setgid", // 132
+ "sendto", // 133
+ "shutdown", // 134
+ "socketpair", // 135
+ "mkdir", // 136
+ "rmdir", // 137
+ "utimes", // 138
+ "obsolete_42_sigreturn", // 139
+
+ "adjtime", // 140
+ "old_getpeername", // 141
+ "gethostid", // 142
+ "sethostid", // 143
+ "getrlimit", // 144
+ "setrlimit", // 145
+ "old_killpg", // 146
+ "setsid", // 147
+ "quotactl", // 148
+ "oldquota", // 149
+
+ "old_getsockname", // 150
+ "pread", // 151
+ "pwrite", // 152
+ "pid_block", // 153
+ "pid_unblock", // 154
+ "signal_urti", // 155
+ "sigaction", // 156
+ "sigwaitprim", // 157
+ "nfssvc", // 158
+ "getdirentries", // 159
+
+ "pre_F64_statfs", // 160
+ "pre_F64_fstatfs", // 161
+ 0, // 162
+ "async_daemon", // 163
+ "getfh", // 164
+ "getdomainname", // 165
+ "setdomainname", // 166
+ 0, // 167
+ 0, // 168
+ "exportfs", // 169
+
+ 0, // 170
+ 0, // 171
+ 0, // 172
+ 0, // 173
+ 0, // 174
+ 0, // 175
+ 0, // 176
+ 0, // 177
+ 0, // 178
+ 0, // 179
+
+ 0, // 180
+ "alt_plock", // 181
+ 0, // 182
+ 0, // 183
+ "getmnt", // 184
+ 0, // 185
+ 0, // 186
+ "alt_sigpending", // 187
+ "alt_setsid", // 188
+ 0, // 189
+
+ 0, // 190
+ 0, // 191
+ 0, // 192
+ 0, // 193
+ 0, // 194
+ 0, // 195
+ 0, // 196
+ 0, // 197
+ 0, // 198
+ "swapon", // 199
+
+ "msgctl", // 200
+ "msgget", // 201
+ "msgrcv", // 202
+ "msgsnd", // 203
+ "semctl", // 204
+ "semget", // 205
+ "semop", // 206
+ "uname", // 207
+ "lchown", // 208
+ "shmat", // 209
+
+ "shmctl", // 210
+ "shmdt", // 211
+ "shmget", // 212
+ "mvalid", // 213
+ "getaddressconf", // 214
+ "msleep", // 215
+ "mwakeup", // 216
+ "msync", // 217
+ "signal", // 218
+ "utc_gettime", // 219
+
+ "utc_adjtime", // 220
+ 0, // 221
+ "security", // 222
+ "kloadcall", // 223
+ "stat", // 224
+ "lstat", // 225
+ "fstat", // 226
+ "statfs", // 227
+ "fstatfs", // 228
+ "getfsstat", // 229
+
+ "gettimeofday64", // 230
+ "settimeofday64", // 231
+ 0, // 232
+ "getpgid", // 233
+ "getsid", // 234
+ "sigaltstack", // 235
+ "waitid", // 236
+ "priocntlset", // 237
+ "sigsendset", // 238
+ "set_speculative", // 239
+
+ "msfs_syscall", // 240
+ "sysinfo", // 241
+ "uadmin", // 242
+ "fuser", // 243
+ "proplist_syscall", // 244
+ "ntp_adjtime", // 245
+ "ntp_gettime", // 246
+ "pathconf", // 247
+ "fpathconf", // 248
+ "sync2", // 249
+
+ "uswitch", // 250
+ "usleep_thread", // 251
+ "audcntl", // 252
+ "audgen", // 253
+ "sysfs", // 254
+ "subsys_info", // 255
+ "getsysinfo", // 256
+ "setsysinfo", // 257
+ "afs_syscall", // 258
+ "swapctl", // 259
+
+ "memcntl", // 260
+ "fdatasync", // 261
+ "oflock", // 262
+ "_F64_readv", // 263
+ "_F64_writev", // 264
+ "cdslxlate", // 265
+ "sendfile", // 266
+ };
+
+ const char *
+ mach_strings[SystemCalls<Tru64>::MachNumber] = {
+ 0, // 0
+ 0, // 1
+ 0, // 2
+ 0, // 3
+ 0, // 4
+ 0, // 5
+ 0, // 6
+ 0, // 7
+ 0, // 8
+ 0, // 9
+
+ "task_self", // 10
+ "thread_reply", // 11
+ "task_notify", // 12
+ "thread_self", // 13
+ 0, // 14
+ 0, // 15
+ 0, // 16
+ 0, // 17
+ 0, // 18
+ 0, // 19
+
+ "msg_send_trap", // 20
+ "msg_receive_trap", // 21
+ "msg_rpc_trap", // 22
+ 0, // 23
+ "nxm_block", // 24
+ "nxm_unblock", // 25
+ 0, // 26
+ 0, // 27
+ 0, // 28
+ "nxm_thread_destroy", // 29
+
+ "lw_wire", // 30
+ "lw_unwire", // 31
+ "nxm_thread_create", // 32
+ "nxm_task_init", // 33
+ 0, // 34
+ "nxm_idle", // 35
+ "nxm_wakeup_idle", // 36
+ "nxm_set_pthid", // 37
+ "nxm_thread_kill", // 38
+ "nxm_thread_block", // 39
+
+ "nxm_thread_wakeup", // 40
+ "init_process", // 41
+ "nxm_get_binding", // 42
+ "map_fd", // 43
+ "nxm_resched", // 44
+ "nxm_set_cancel", // 45
+ "nxm_set_binding", // 46
+ "stack_create", // 47
+ "nxm_get_state", // 48
+ "nxm_thread_suspend", // 49
+
+ "nxm_thread_resume", // 50
+ "nxm_signal_check", // 51
+ "htg_unix_syscall", // 52
+ 0, // 53
+ 0, // 54
+ "host_self", // 55
+ "host_priv_self", // 56
+ 0, // 57
+ 0, // 58
+ "swtch_pri", // 59
+
+ "swtch", // 60
+ "thread_switch", // 61
+ "semop_fast", // 62
+ "nxm_pshared_init", // 63
+ "nxm_pshared_block", // 64
+ "nxm_pshared_unblock", // 65
+ "nxm_pshared_destroy", // 66
+ "nxm_swtch_pri", // 67
+ "lw_syscall", // 68
+ 0, // 69
+
+ "mach_sctimes_0", // 70
+ "mach_sctimes_1", // 71
+ "mach_sctimes_2", // 72
+ "mach_sctimes_3", // 73
+ "mach_sctimes_4", // 74
+ "mach_sctimes_5", // 75
+ "mach_sctimes_6", // 76
+ "mach_sctimes_7", // 77
+ "mach_sctimes_8", // 78
+ "mach_sctimes_9", // 79
+
+ "mach_sctimes_10", // 80
+ "mach_sctimes_11", // 81
+ "mach_sctimes_port_alloc_dealloc", // 82
+ };
+}
+
+const char *
+SystemCalls<Tru64>::name(int num)
+{
+ if (num >= Number)
+ return 0;
+ else if (num >= StandardNumber)
+ return mach_strings[num - StandardNumber];
+ else if (num >= 0)
+ return standard_strings[num];
+ else if (num > -MachNumber)
+ return mach_strings[-num];
+ else
+ return 0;
+}
diff --git a/src/kern/tru64/tru64_syscalls.hh b/src/kern/tru64/tru64_syscalls.hh
new file mode 100644
index 000000000..69fa9101c
--- /dev/null
+++ b/src/kern/tru64/tru64_syscalls.hh
@@ -0,0 +1,359 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __KERN_TRU64_TRU64_SYSCALLS_HH__
+#define __KERN_TRU64_TRU64_SYSCALLS_HH__
+
+#include "kern/tru64/tru64.hh"
+
+template <class OS>
+class SystemCalls;
+
+template <>
+class SystemCalls<Tru64>
+{
+ public:
+ enum {
+ syscall = 0,
+ exit = 1,
+ fork = 2,
+ read = 3,
+ write = 4,
+ old_open = 5,
+ close = 6,
+ wait4 = 7,
+ old_creat = 8,
+ link = 9,
+ unlink = 10,
+ execv = 11,
+ chdir = 12,
+ fchdir = 13,
+ mknod = 14,
+ chmod = 15,
+ chown = 16,
+ obreak = 17,
+ pre_F64_getfsstat = 18,
+ lseek = 19,
+ getpid = 20,
+ mount = 21,
+ unmount = 22,
+ setuid = 23,
+ getuid = 24,
+ exec_with_loader = 25,
+ ptrace = 26,
+ recvmsg = 27,
+ sendmsg = 28,
+ recvfrom = 29,
+ accept = 30,
+ getpeername = 31,
+ getsockname = 32,
+ access = 33,
+ chflags = 34,
+ fchflags = 35,
+ sync = 36,
+ kill = 37,
+ old_stat = 38,
+ setpgid = 39,
+ old_lstat = 40,
+ dup = 41,
+ pipe = 42,
+ set_program_attributes = 43,
+ profil = 44,
+ open = 45,
+ obsolete_osigaction = 46,
+ getgid = 47,
+ sigprocmask = 48,
+ getlogin = 49,
+ setlogin = 50,
+ acct = 51,
+ sigpending = 52,
+ classcntl = 53,
+ ioctl = 54,
+ reboot = 55,
+ revoke = 56,
+ symlink = 57,
+ readlink = 58,
+ execve = 59,
+ umask = 60,
+ chroot = 61,
+ old_fstat = 62,
+ getpgrp = 63,
+ getpagesize = 64,
+ mremap = 65,
+ vfork = 66,
+ pre_F64_stat = 67,
+ pre_F64_lstat = 68,
+ sbrk = 69,
+ sstk = 70,
+ mmap = 71,
+ ovadvise = 72,
+ munmap = 73,
+ mprotect = 74,
+ madvise = 75,
+ old_vhangup = 76,
+ kmodcall = 77,
+ mincore = 78,
+ getgroups = 79,
+ setgroups = 80,
+ old_getpgrp = 81,
+ setpgrp = 82,
+ setitimer = 83,
+ old_wait = 84,
+ table = 85,
+ getitimer = 86,
+ gethostname = 87,
+ sethostname = 88,
+ getdtablesize = 89,
+ dup2 = 90,
+ pre_F64_fstat = 91,
+ fcntl = 92,
+ select = 93,
+ poll = 94,
+ fsync = 95,
+ setpriority = 96,
+ socket = 97,
+ connect = 98,
+ old_accept = 99,
+ getpriority = 100,
+ old_send = 101,
+ old_recv = 102,
+ sigreturn = 103,
+ bind = 104,
+ setsockopt = 105,
+ listen = 106,
+ plock = 107,
+ old_sigvec = 108,
+ old_sigblock = 109,
+ old_sigsetmask = 110,
+ sigsuspend = 111,
+ sigstack = 112,
+ old_recvmsg = 113,
+ old_sendmsg = 114,
+ obsolete_vtrcae = 115,
+ gettimeofday = 116,
+ getrusage = 117,
+ getsockopt = 118,
+ numa_syscalls = 119,
+ readv = 120,
+ writev = 121,
+ settimeofday = 122,
+ fchown = 123,
+ fchmod = 124,
+ old_recvfrom = 125,
+ setreuid = 126,
+ setregid = 127,
+ rename = 128,
+ truncate = 129,
+ ftruncate = 130,
+ flock = 131,
+ setgid = 132,
+ sendto = 133,
+ shutdown = 134,
+ socketpair = 135,
+ mkdir = 136,
+ rmdir = 137,
+ utimes = 138,
+ obsolete_42_sigreturn = 139,
+ adjtime = 140,
+ old_getpeername = 141,
+ gethostid = 142,
+ sethostid = 143,
+ getrlimit = 144,
+ setrlimit = 145,
+ old_killpg = 146,
+ setsid = 147,
+ quotactl = 148,
+ oldquota = 149,
+ old_getsockname = 150,
+ pread = 151,
+ pwrite = 152,
+ pid_block = 153,
+ pid_unblock = 154,
+ signal_urti = 155,
+ sigaction = 156,
+ sigwaitprim = 157,
+ nfssvc = 158,
+ getdirentries = 159,
+ pre_F64_statfs = 160,
+ pre_F64_fstatfs = 161,
+ async_daemon = 163,
+ getfh = 164,
+ getdomainname = 165,
+ setdomainname = 166,
+ exportfs = 169,
+ alt_plock = 181,
+ getmnt = 184,
+ alt_sigpending = 187,
+ alt_setsid = 188,
+ swapon = 199,
+ msgctl = 200,
+ msgget = 201,
+ msgrcv = 202,
+ msgsnd = 203,
+ semctl = 204,
+ semget = 205,
+ semop = 206,
+ uname = 207,
+ lchown = 208,
+ shmat = 209,
+ shmctl = 210,
+ shmdt = 211,
+ shmget = 212,
+ mvalid = 213,
+ getaddressconf = 214,
+ msleep = 215,
+ mwakeup = 216,
+ msync = 217,
+ signal = 218,
+ utc_gettime = 219,
+ utc_adjtime = 220,
+ security = 222,
+ kloadcall = 223,
+ stat = 224,
+ lstat = 225,
+ fstat = 226,
+ statfs = 227,
+ fstatfs = 228,
+ getfsstat = 229,
+ gettimeofday64 = 230,
+ settimeofday64 = 231,
+ getpgid = 233,
+ getsid = 234,
+ sigaltstack = 235,
+ waitid = 236,
+ priocntlset = 237,
+ sigsendset = 238,
+ set_speculative = 239,
+ msfs_syscall = 240,
+ sysinfo = 241,
+ uadmin = 242,
+ fuser = 243,
+ proplist_syscall = 244,
+ ntp_adjtime = 245,
+ ntp_gettime = 246,
+ pathconf = 247,
+ fpathconf = 248,
+ sync2 = 249,
+ uswitch = 250,
+ usleep_thread = 251,
+ audcntl = 252,
+ audgen = 253,
+ sysfs = 254,
+ subsys_info = 255,
+ getsysinfo = 256,
+ setsysinfo = 257,
+ afs_syscall = 258,
+ swapctl = 259,
+ memcntl = 260,
+ fdatasync = 261,
+ oflock = 262,
+ _F64_readv = 263,
+ _F64_writev = 264,
+ cdslxlate = 265,
+ sendfile = 266,
+ StandardNumber
+ };
+
+ enum {
+ task_self = 10,
+ thread_reply = 11,
+ task_notify = 12,
+ thread_self = 13,
+ msg_send_trap = 20,
+ msg_receive_trap = 21,
+ msg_rpc_trap = 22,
+ nxm_block = 24,
+ nxm_unblock = 25,
+ nxm_thread_destroy = 29,
+ lw_wire = 30,
+ lw_unwire = 31,
+ nxm_thread_create = 32,
+ nxm_task_init = 33,
+ nxm_idle = 35,
+ nxm_wakeup_idle = 36,
+ nxm_set_pthid = 37,
+ nxm_thread_kill = 38,
+ nxm_thread_block = 39,
+ nxm_thread_wakeup = 40,
+ init_process = 41,
+ nxm_get_binding = 42,
+ map_fd = 43,
+ nxm_resched = 44,
+ nxm_set_cancel = 45,
+ nxm_set_binding = 46,
+ stack_create = 47,
+ nxm_get_state = 48,
+ nxm_thread_suspend = 49,
+ nxm_thread_resume = 50,
+ nxm_signal_check = 51,
+ htg_unix_syscall = 52,
+ host_self = 55,
+ host_priv_self = 56,
+ swtch_pri = 59,
+ swtch = 60,
+ thread_switch = 61,
+ semop_fast = 62,
+ nxm_pshared_init = 63,
+ nxm_pshared_block = 64,
+ nxm_pshared_unblock = 65,
+ nxm_pshared_destroy = 66,
+ nxm_swtch_pri = 67,
+ lw_syscall = 68,
+ mach_sctimes_0 = 70,
+ mach_sctimes_1 = 71,
+ mach_sctimes_2 = 72,
+ mach_sctimes_3 = 73,
+ mach_sctimes_4 = 74,
+ mach_sctimes_5 = 75,
+ mach_sctimes_6 = 76,
+ mach_sctimes_7 = 77,
+ mach_sctimes_8 = 78,
+ mach_sctimes_9 = 79,
+ mach_sctimes_10 = 80,
+ mach_sctimes_11 = 81,
+ mach_sctimes_port_alloc_dealloc = 82,
+ MachNumber
+ };
+
+ static const int Number = StandardNumber + MachNumber;
+
+ static const char *name(int num);
+
+ static bool validSyscallNumber(int num) {
+ return -MachNumber < num && num < StandardNumber;
+ }
+
+ static int convert(int syscall_num) {
+ if (!validSyscallNumber(syscall_num))
+ return -1;
+
+ return syscall_num < 0 ? StandardNumber - syscall_num : syscall_num;
+ }
+};
+
+#endif // __KERN_TRU64_TRU64_SYSCALLS_HH__
diff --git a/src/mem/bridge.cc b/src/mem/bridge.cc
new file mode 100644
index 000000000..c4b137869
--- /dev/null
+++ b/src/mem/bridge.cc
@@ -0,0 +1,263 @@
+
+/*
+ * Copyright (c) 2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file Definition of a simple bus bridge without buffering.
+ */
+
+
+#include "base/trace.hh"
+#include "mem/bridge.hh"
+#include "sim/builder.hh"
+
+void
+Bridge::init()
+{
+ // Make sure that both sides are connected to.
+ if (sideA == NULL || sideB == NULL)
+ panic("Both ports of bus bridge are not connected to a bus.\n");
+}
+
+
+/** Function called by the port when the bus is recieving a Timing
+ * transaction.*/
+bool
+Bridge::recvTiming(Packet *pkt, Side id)
+{
+ if (blockedA && id == SideA)
+ return false;
+ if (blockedB && id == SideB)
+ return false;
+
+ if (delay) {
+ if (!sendEvent.scheduled())
+ sendEvent.schedule(curTick + delay);
+ if (id == SideA) {
+ inboundA.push_back(std::make_pair<Packet*, Tick>(pkt, curTick));
+ blockCheck(SideA);
+ } else {
+ inboundB.push_back(std::make_pair<Packet*, Tick>(pkt, curTick));
+ blockCheck(SideB);
+ }
+ } else {
+ if (id == SideB) {
+ sideA->sendPkt(pkt);
+ blockCheck(SideB);
+ } else {
+ sideB->sendPkt(pkt);
+ blockCheck(SideA);
+ }
+ }
+ return true;
+
+}
+
+void
+Bridge::blockCheck(Side id)
+{
+ /* Check that we still have buffer space available. */
+ if (id == SideB) {
+ if (sideA->numQueued() + inboundB.size() >= queueSizeA && !blockedB) {
+ sideB->sendStatusChange(Port::Blocked);
+ blockedB = true;
+ } else if (sideA->numQueued() + inboundB.size() < queueSizeA && blockedB) {
+ sideB->sendStatusChange(Port::Unblocked);
+ blockedB = false;
+ }
+ } else {
+ if (sideB->numQueued() + inboundA.size() >= queueSizeB && !blockedA) {
+ sideA->sendStatusChange(Port::Blocked);
+ blockedA = true;
+ } else if (sideB->numQueued() + inboundA.size() < queueSizeB && blockedA) {
+ sideA->sendStatusChange(Port::Unblocked);
+ blockedA = false;
+ }
+ }
+}
+
+void Bridge::timerEvent()
+{
+ Tick t = 0;
+
+ assert(inboundA.size() || inboundB.size());
+ if (inboundA.size()) {
+ while (inboundA.front().second <= curTick + delay){
+ sideB->sendPkt(inboundA.front());
+ inboundA.pop_front();
+ }
+ if (inboundA.size())
+ t = inboundA.front().second + delay;
+ }
+ if (inboundB.size()) {
+ while (inboundB.front().second <= curTick + delay){
+ sideB->sendPkt(inboundA.front());
+ inboundB.pop_front();
+ }
+ if (inboundB.size())
+ if (t == 0)
+ t = inboundB.front().second + delay;
+ else
+ t = std::min(t,inboundB.front().second + delay);
+ } else {
+ panic("timerEvent() called but nothing to do?");
+ }
+
+ if (t != 0)
+ sendEvent.schedule(t);
+}
+
+
+void
+Bridge::BridgePort::sendPkt(Packet *pkt)
+{
+ if (!sendTiming(pkt))
+ outbound.push_back(std::make_pair<Packet*,Tick>(pkt, curTick));
+}
+
+void
+Bridge::BridgePort::sendPkt(std::pair<Packet*, Tick> p)
+{
+ if (!sendTiming(p.first))
+ outbound.push_back(p);
+}
+
+
+Packet *
+Bridge::BridgePort::recvRetry()
+{
+ Packet *pkt;
+ assert(outbound.size() > 0);
+ assert(outbound.front().second >= curTick + bridge->delay);
+ pkt = outbound.front().first;
+ outbound.pop_front();
+ bridge->blockCheck(side);
+ return pkt;
+}
+
+/** Function called by the port when the bus is recieving a Atomic
+ * transaction.*/
+Tick
+Bridge::recvAtomic(Packet *pkt, Side id)
+{
+ pkt->time += delay;
+
+ if (id == SideA)
+ return sideB->sendAtomic(pkt);
+ else
+ return sideA->sendAtomic(pkt);
+}
+
+/** Function called by the port when the bus is recieving a Functional
+ * transaction.*/
+void
+Bridge::recvFunctional(Packet *pkt, Side id)
+{
+ pkt->time += delay;
+ std::list<std::pair<Packet*, Tick> >::iterator i;
+ bool pktContinue = true;
+
+ for(i = inboundA.begin(); i != inboundA.end(); ++i) {
+ if (pkt->intersect(i->first)) {
+ pktContinue &= fixPacket(pkt, i->first);
+ }
+ }
+
+ for(i = inboundB.begin(); i != inboundB.end(); ++i) {
+ if (pkt->intersect(i->first)) {
+ pktContinue &= fixPacket(pkt, i->first);
+ }
+ }
+
+ for(i = sideA->outbound.begin(); i != sideA->outbound.end(); ++i) {
+ if (pkt->intersect(i->first)) {
+ pktContinue &= fixPacket(pkt, i->first);
+ }
+ }
+
+ for(i = sideB->outbound.begin(); i != sideB->outbound.end(); ++i) {
+ if (pkt->intersect(i->first)) {
+ pktContinue &= fixPacket(pkt, i->first);
+ }
+ }
+
+ if (pktContinue) {
+ if (id == SideA)
+ sideB->sendFunctional(pkt);
+ else
+ sideA->sendFunctional(pkt);
+ }
+}
+
+/** Function called by the port when the bus is recieving a status change.*/
+void
+Bridge::recvStatusChange(Port::Status status, Side id)
+{
+ if (status == Port::Blocked || status == Port::Unblocked)
+ return ;
+
+ if (id == SideA)
+ sideB->sendStatusChange(status);
+ else
+ sideA->sendStatusChange(status);
+}
+
+void
+Bridge::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, Side id)
+{
+ if (id == SideA)
+ sideB->getPeerAddressRanges(resp, snoop);
+ else
+ sideA->getPeerAddressRanges(resp, snoop);
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bridge)
+
+ Param<int> queue_size_a;
+ Param<int> queue_size_b;
+ Param<Tick> delay;
+ Param<bool> write_ack;
+
+END_DECLARE_SIM_OBJECT_PARAMS(Bridge)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(Bridge)
+
+ INIT_PARAM(queue_size_a, "The size of the queue for data coming into side a"),
+ INIT_PARAM(queue_size_b, "The size of the queue for data coming into side b"),
+ INIT_PARAM(delay, "The miminum delay to cross this bridge"),
+ INIT_PARAM(write_ack, "Acknowledge any writes that are received.")
+
+END_INIT_SIM_OBJECT_PARAMS(Bridge)
+
+CREATE_SIM_OBJECT(Bridge)
+{
+ return new Bridge(getInstanceName(), queue_size_a, queue_size_b, delay,
+ write_ack);
+}
+
+REGISTER_SIM_OBJECT("Bridge", Bridge)
diff --git a/src/mem/bridge.hh b/src/mem/bridge.hh
new file mode 100644
index 000000000..5f19ded40
--- /dev/null
+++ b/src/mem/bridge.hh
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file Decleration of a simple bus bridge object with no buffering
+ */
+
+#ifndef __MEM_BRIDGE_HH__
+#define __MEM_BRIDGE_HH__
+
+#include <string>
+#include <list>
+#include <inttypes.h>
+#include <queue>
+
+
+#include "mem/mem_object.hh"
+#include "mem/packet.hh"
+#include "mem/port.hh"
+#include "sim/eventq.hh"
+
+class Bridge : public MemObject
+{
+ public:
+ enum Side
+ {
+ SideA,
+ SideB
+ };
+
+ protected:
+ /** Function called by the port when the bus is recieving a Timing
+ transaction.*/
+ bool recvTiming(Packet *pkt, Side id);
+
+ /** Function called by the port when the bus is recieving a Atomic
+ transaction.*/
+ Tick recvAtomic(Packet *pkt, Side id);
+
+ /** Function called by the port when the bus is recieving a Functional
+ transaction.*/
+ void recvFunctional(Packet *pkt, Side id);
+
+ /** Function called by the port when the bus is recieving a status change.*/
+ void recvStatusChange(Port::Status status, Side id);
+
+ /** Process address range request.
+ * @param resp addresses that we can respond to
+ * @param snoop addresses that we would like to snoop
+ * @param id ide of the busport that made the request.
+ */
+ void addressRanges(AddrRangeList &resp, AddrRangeList &snoop, Side id);
+
+
+ /** Event that the SendEvent calls when it fires. This code must reschedule
+ * the send event as required. */
+ void timerEvent();
+
+ /** Decleration of the buses port type, one will be instantiated for each
+ of the interfaces connecting to the bus. */
+ class BridgePort : public Port
+ {
+ /** A pointer to the bus to which this port belongs. */
+ Bridge *bridge;
+
+ /** A id to keep track of the intercafe ID this port is connected to. */
+ Bridge::Side side;
+
+ public:
+
+ /** Constructor for the BusPort.*/
+ BridgePort(Bridge *_bridge, Side _side)
+ : bridge(_bridge), side(_side)
+ { }
+
+ int numQueued() { return outbound.size(); }
+
+ protected:
+ /** Data this is waiting to be transmitted. */
+ std::list<std::pair<Packet*, Tick> > outbound;
+
+ void sendPkt(Packet *pkt);
+ void sendPkt(std::pair<Packet*, Tick> p);
+
+ /** When reciving a timing request from the peer port,
+ pass it to the bridge. */
+ virtual bool recvTiming(Packet *pkt)
+ { return bridge->recvTiming(pkt, side); }
+
+ /** When reciving a retry request from the peer port,
+ pass it to the bridge. */
+ virtual Packet* recvRetry();
+
+ /** When reciving a Atomic requestfrom the peer port,
+ pass it to the bridge. */
+ virtual Tick recvAtomic(Packet *pkt)
+ { return bridge->recvAtomic(pkt, side); }
+
+ /** When reciving a Functional request from the peer port,
+ pass it to the bridge. */
+ virtual void recvFunctional(Packet *pkt)
+ { bridge->recvFunctional(pkt, side); }
+
+ /** When reciving a status changefrom the peer port,
+ pass it to the bridge. */
+ virtual void recvStatusChange(Status status)
+ { bridge->recvStatusChange(status, side); }
+
+ /** When reciving a address range request the peer port,
+ pass it to the bridge. */
+ virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
+ { bridge->addressRanges(resp, snoop, side); }
+
+ friend class Bridge;
+ };
+
+ class SendEvent : public Event
+ {
+ Bridge *bridge;
+
+ SendEvent(Bridge *b)
+ : Event(&mainEventQueue), bridge(b) {}
+
+ virtual void process() { bridge->timerEvent(); }
+
+ virtual const char *description() { return "bridge delay event"; }
+ friend class Bridge;
+ };
+
+ SendEvent sendEvent;
+
+ /** Sides of the bus bridges. */
+ BridgePort* sideA;
+ BridgePort* sideB;
+
+ /** inbound queues on both sides. */
+ std::list<std::pair<Packet*, Tick> > inboundA;
+ std::list<std::pair<Packet*, Tick> > inboundB;
+
+ /** The size of the queue for data coming into side a */
+ int queueSizeA;
+ int queueSizeB;
+
+ /* if the side is blocked or not. */
+ bool blockedA;
+ bool blockedB;
+
+ /** Miminum delay though this bridge. */
+ Tick delay;
+
+ /** If this bridge should acknowledge writes. */
+ bool ackWrites;
+
+ public:
+
+ /** A function used to return the port associated with this bus object. */
+ virtual Port *getPort(const std::string &if_name)
+ {
+ if (if_name == "side_a") {
+ if (sideA != NULL)
+ panic("bridge side a already connected to.");
+ sideA = new BridgePort(this, SideA);
+ return sideA;
+ } else if (if_name == "side_b") {
+ if (sideB != NULL)
+ panic("bridge side b already connected to.");
+ sideB = new BridgePort(this, SideB);
+ return sideB;
+ } else
+ return NULL;
+ }
+
+ virtual void init();
+
+ Bridge(const std::string &n, int qsa, int qsb, Tick _delay, int write_ack)
+ : MemObject(n), sendEvent(this), sideA(NULL), sideB(NULL),
+ queueSizeA(qsa), queueSizeB(qsb), blockedA(false), blockedB(false),
+ delay(_delay), ackWrites(write_ack)
+ {}
+
+ /** Check if the port should block/unblock after recieving/sending a packet.
+ * */
+ void blockCheck(Side id);
+
+ friend class Bridge::SendEvent;
+
+};
+
+#endif //__MEM_BUS_HH__
diff --git a/src/mem/bus.cc b/src/mem/bus.cc
new file mode 100644
index 000000000..f7c2b874a
--- /dev/null
+++ b/src/mem/bus.cc
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file Definition of a bus object.
+ */
+
+
+#include "base/trace.hh"
+#include "mem/bus.hh"
+#include "sim/builder.hh"
+
+/** Get the ranges of anyone that we are connected to. */
+void
+Bus::init()
+{
+ std::vector<Port*>::iterator intIter;
+ for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++)
+ (*intIter)->sendStatusChange(Port::RangeChange);
+}
+
+
+/** Function called by the port when the bus is recieving a Timing
+ * transaction.*/
+bool
+Bus::recvTiming(Packet *pkt)
+{
+ Port *port;
+ if (pkt->dest == Packet::Broadcast) {
+ port = findPort(pkt->addr, pkt->src);
+ } else {
+ assert(pkt->dest > 0 && pkt->dest < interfaces.size());
+ port = interfaces[pkt->dest];
+ }
+ return port->sendTiming(pkt);
+}
+
+Port *
+Bus::findPort(Addr addr, int id)
+{
+ /* An interval tree would be a better way to do this. --ali. */
+ int dest_id = -1;
+ int i = 0;
+ bool found = false;
+
+ while (i < portList.size() && !found)
+ {
+ if (portList[i].range == addr) {
+ dest_id = portList[i].portId;
+ found = true;
+ DPRINTF(Bus, "Found Addr: %llx on device %d\n", addr, dest_id);
+ }
+ i++;
+ }
+ if (dest_id == -1)
+ panic("Unable to find destination for addr: %llx", addr);
+
+ // we shouldn't be sending this back to where it came from
+ assert(dest_id != id);
+
+ return interfaces[dest_id];
+}
+
+/** Function called by the port when the bus is recieving a Atomic
+ * transaction.*/
+Tick
+Bus::recvAtomic(Packet *pkt)
+{
+ assert(pkt->dest == Packet::Broadcast);
+ return findPort(pkt->addr, pkt->src)->sendAtomic(pkt);
+}
+
+/** Function called by the port when the bus is recieving a Functional
+ * transaction.*/
+void
+Bus::recvFunctional(Packet *pkt)
+{
+ assert(pkt->dest == Packet::Broadcast);
+ findPort(pkt->addr, pkt->src)->sendFunctional(pkt);
+}
+
+/** Function called by the port when the bus is recieving a status change.*/
+void
+Bus::recvStatusChange(Port::Status status, int id)
+{
+ DPRINTF(Bus, "Bus %d recieved status change from device id %d\n",
+ busId, id);
+ assert(status == Port::RangeChange &&
+ "The other statuses need to be implemented.");
+
+ assert(id < interfaces.size() && id >= 0);
+ int x;
+ Port *port = interfaces[id];
+ AddrRangeList ranges;
+ AddrRangeList snoops;
+ AddrRangeIter iter;
+ std::vector<DevMap>::iterator portIter;
+
+ // Clean out any previously existent ids
+ for (portIter = portList.begin(); portIter != portList.end(); ) {
+ if (portIter->portId == id)
+ portIter = portList.erase(portIter);
+ else
+ portIter++;
+ }
+
+ port->getPeerAddressRanges(ranges, snoops);
+
+ // not dealing with snooping yet either
+ assert(snoops.size() == 0);
+ for(iter = ranges.begin(); iter != ranges.end(); iter++) {
+ DevMap dm;
+ dm.portId = id;
+ dm.range = *iter;
+
+ DPRINTF(MMU, "Adding range %llx - %llx for id %d\n", dm.range.start,
+ dm.range.end, id);
+ portList.push_back(dm);
+ }
+ DPRINTF(MMU, "port list has %d entries\n", portList.size());
+
+ // tell all our peers that our address range has changed.
+ // Don't tell the device that caused this change, it already knows
+ for (x = 0; x < interfaces.size(); x++)
+ if (x != id)
+ interfaces[x]->sendStatusChange(Port::RangeChange);
+}
+
+void
+Bus::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id)
+{
+ std::vector<DevMap>::iterator portIter;
+
+ resp.clear();
+ snoop.clear();
+
+ DPRINTF(Bus, "Bus id %d recieved address range request returning\n",
+ busId);
+ for (portIter = portList.begin(); portIter != portList.end(); portIter++) {
+ if (portIter->portId != id) {
+ resp.push_back(portIter->range);
+ DPRINTF(Bus, "-- %#llX : %#llX\n", portIter->range.start,
+ portIter->range.end);
+ }
+ }
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bus)
+
+ Param<int> bus_id;
+
+END_DECLARE_SIM_OBJECT_PARAMS(Bus)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(Bus)
+ INIT_PARAM(bus_id, "a globally unique bus id")
+END_INIT_SIM_OBJECT_PARAMS(Bus)
+
+CREATE_SIM_OBJECT(Bus)
+{
+ return new Bus(getInstanceName(), bus_id);
+}
+
+REGISTER_SIM_OBJECT("Bus", Bus)
diff --git a/src/mem/bus.hh b/src/mem/bus.hh
new file mode 100644
index 000000000..38573e514
--- /dev/null
+++ b/src/mem/bus.hh
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file Decleration of a bus object.
+ */
+
+#ifndef __MEM_BUS_HH__
+#define __MEM_BUS_HH__
+
+#include <string>
+#include <list>
+#include <inttypes.h>
+
+#include "base/range.hh"
+#include "mem/mem_object.hh"
+#include "mem/packet.hh"
+#include "mem/port.hh"
+#include "mem/request.hh"
+
+class Bus : public MemObject
+{
+ /** a globally unique id for this bus. */
+ int busId;
+
+ struct DevMap {
+ int portId;
+ Range<Addr> range;
+ };
+ std::vector<DevMap> portList;
+
+
+ /** Function called by the port when the bus is recieving a Timing
+ transaction.*/
+ bool recvTiming(Packet *pkt);
+
+ /** Function called by the port when the bus is recieving a Atomic
+ transaction.*/
+ Tick recvAtomic(Packet *pkt);
+
+ /** Function called by the port when the bus is recieving a Functional
+ transaction.*/
+ void recvFunctional(Packet *pkt);
+
+ /** Function called by the port when the bus is recieving a status change.*/
+ void recvStatusChange(Port::Status status, int id);
+
+ /** Find which port connected to this bus (if any) should be given a packet
+ * with this address.
+ * @param addr Address to find port for.
+ * @param id Id of the port this packet was received from (to prevent
+ * loops)
+ * @return pointer to port that the packet should be sent out of.
+ */
+ Port *findPort(Addr addr, int id);
+
+ /** Process address range request.
+ * @param resp addresses that we can respond to
+ * @param snoop addresses that we would like to snoop
+ * @param id ide of the busport that made the request.
+ */
+ void addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id);
+
+
+ /** Decleration of the buses port type, one will be instantiated for each
+ of the interfaces connecting to the bus. */
+ class BusPort : public Port
+ {
+ /** A pointer to the bus to which this port belongs. */
+ Bus *bus;
+
+ /** A id to keep track of the intercafe ID this port is connected to. */
+ int id;
+
+ public:
+
+ /** Constructor for the BusPort.*/
+ BusPort(Bus *_bus, int _id)
+ : bus(_bus), id(_id)
+ { }
+
+ protected:
+
+ /** When reciving a timing request from the peer port (at id),
+ pass it to the bus. */
+ virtual bool recvTiming(Packet *pkt)
+ { pkt->src = id; return bus->recvTiming(pkt); }
+
+ /** When reciving a Atomic requestfrom the peer port (at id),
+ pass it to the bus. */
+ virtual Tick recvAtomic(Packet *pkt)
+ { pkt->src = id; return bus->recvAtomic(pkt); }
+
+ /** When reciving a Functional requestfrom the peer port (at id),
+ pass it to the bus. */
+ virtual void recvFunctional(Packet *pkt)
+ { pkt->src = id; bus->recvFunctional(pkt); }
+
+ /** When reciving a status changefrom the peer port (at id),
+ pass it to the bus. */
+ virtual void recvStatusChange(Status status)
+ { bus->recvStatusChange(status, id); }
+
+ // This should return all the 'owned' addresses that are
+ // downstream from this bus, yes? That is, the union of all
+ // the 'owned' address ranges of all the other interfaces on
+ // this bus...
+ virtual void getDeviceAddressRanges(AddrRangeList &resp,
+ AddrRangeList &snoop)
+ { bus->addressRanges(resp, snoop, id); }
+
+ // Hack to make translating port work without changes
+ virtual int deviceBlockSize() { return 32; }
+
+ };
+
+ /** An array of pointers to the peer port interfaces
+ connected to this bus.*/
+ std::vector<Port*> interfaces;
+
+ public:
+
+ /** A function used to return the port associated with this bus object. */
+ virtual Port *getPort(const std::string &if_name)
+ {
+ // if_name ignored? forced to be empty?
+ int id = interfaces.size();
+ interfaces.push_back(new BusPort(this, id));
+ return interfaces.back();
+ }
+
+ virtual void init();
+
+ Bus(const std::string &n, int bus_id)
+ : MemObject(n), busId(bus_id) {}
+
+};
+
+#endif //__MEM_BUS_HH__
diff --git a/src/mem/cache/prefetch/tagged_prefetcher_impl.hh b/src/mem/cache/prefetch/tagged_prefetcher_impl.hh
new file mode 100644
index 000000000..6c27256a9
--- /dev/null
+++ b/src/mem/cache/prefetch/tagged_prefetcher_impl.hh
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * Describes a tagged prefetcher based on template policies.
+ */
+
+#include "mem/cache/prefetch/tagged_prefetcher.hh"
+
+template <class TagStore, class Buffering>
+TaggedPrefetcher<TagStore, Buffering>::
+TaggedPrefetcher(int size, bool pageStop, bool serialSquash,
+ bool cacheCheckPush, bool onlyData,
+ Tick latency, int degree)
+ :Prefetcher<TagStore, Buffering>(size, pageStop, serialSquash,
+ cacheCheckPush, onlyData),
+ latency(latency), degree(degree)
+{
+}
+
+template <class TagStore, class Buffering>
+void
+TaggedPrefetcher<TagStore, Buffering>::
+calculatePrefetch(MemReqPtr &req, std::list<Addr> &addresses,
+ std::list<Tick> &delays)
+{
+ Addr blkAddr = req->paddr & ~(Addr)(this->blkSize-1);
+
+ for (int d=1; d <= degree; d++) {
+ Addr newAddr = blkAddr + d*(this->blkSize);
+ if (this->pageStop &&
+ (blkAddr & ~(TheISA::VMPageSize - 1)) !=
+ (newAddr & ~(TheISA::VMPageSize - 1)))
+ {
+ //Spanned the page, so now stop
+ this->pfSpanPage += degree - d + 1;
+ return;
+ }
+ else
+ {
+ addresses.push_back(newAddr);
+ delays.push_back(latency);
+ }
+ }
+}
+
+
diff --git a/src/mem/config/prefetch.hh b/src/mem/config/prefetch.hh
new file mode 100644
index 000000000..03eb570f0
--- /dev/null
+++ b/src/mem/config/prefetch.hh
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * Central location to configure which prefetch types we want to build
+ * into the simulator. In the future, this should probably be
+ * autogenerated by some sort of configuration script.
+ */
+#define USE_TAGGED 1 //Be sure not to turn this off, it is also used for no
+ //prefetching case unless you always want to use a
+ //different prefetcher
+//#define USE_STRIDED 1
+//#define USE_GHB 1
diff --git a/src/mem/mem_object.cc b/src/mem/mem_object.cc
new file mode 100644
index 000000000..f579a0727
--- /dev/null
+++ b/src/mem/mem_object.cc
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "mem/mem_object.hh"
+#include "sim/param.hh"
+
+MemObject::MemObject(const std::string &name)
+ : SimObject(name)
+{
+}
+
+DEFINE_SIM_OBJECT_CLASS_NAME("MemObject", MemObject)
diff --git a/src/mem/mem_object.hh b/src/mem/mem_object.hh
new file mode 100644
index 000000000..58930eccc
--- /dev/null
+++ b/src/mem/mem_object.hh
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * Base Memory Object decleration.
+ */
+
+#ifndef __MEM_MEM_OBJECT_HH__
+#define __MEM_MEM_OBJECT_HH__
+
+#include "sim/sim_object.hh"
+#include "mem/port.hh"
+
+/**
+ * The base MemoryObject class, allows for an accesor function to a
+ * simobj that returns the Port.
+ */
+class MemObject : public SimObject
+{
+ public:
+ MemObject(const std::string &name);
+
+ public:
+ /** Additional function to return the Port of a memory object. */
+ virtual Port *getPort(const std::string &if_name) = 0;
+};
+
+#endif //__MEM_MEM_OBJECT_HH__
diff --git a/src/mem/packet.cc b/src/mem/packet.cc
new file mode 100644
index 000000000..a9be7ac51
--- /dev/null
+++ b/src/mem/packet.cc
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * Definition of the Packet Class, a packet is a transaction occuring
+ * between a single level of the memory heirarchy (ie L1->L2).
+ */
+#include "base/misc.hh"
+#include "mem/packet.hh"
+
+
+/** delete the data pointed to in the data pointer. Ok to call to matter how
+ * data was allocted. */
+void
+Packet::deleteData() {
+ assert(staticData || dynamicData);
+ if (staticData)
+ return;
+
+ if (arrayData)
+ delete [] data;
+ else
+ delete data;
+}
+
+/** If there isn't data in the packet, allocate some. */
+void
+Packet::allocate() {
+ if (data)
+ return;
+ assert(!staticData);
+ dynamicData = true;
+ arrayData = true;
+ data = new uint8_t[size];
+}
+
+/** Do the packet modify the same addresses. */
+bool
+Packet::intersect(Packet *p) {
+ Addr s1 = addr;
+ Addr e1 = addr + size;
+ Addr s2 = p->addr;
+ Addr e2 = p->addr + p->size;
+
+ if (s1 >= s2 && s1 < e2)
+ return true;
+ if (e1 >= s2 && e1 < e2)
+ return true;
+ return false;
+}
+
+/** Minimally reset a packet so something like simple cpu can reuse it. */
+void
+Packet::reset() {
+ result = Unknown;
+ if (dynamicData) {
+ deleteData();
+ dynamicData = false;
+ arrayData = false;
+ time = curTick;
+ }
+}
+
+
+
+
+bool fixPacket(Packet *func, Packet *timing)
+{ panic("Need to implement!"); }
diff --git a/src/mem/packet.hh b/src/mem/packet.hh
new file mode 100644
index 000000000..e8a7b0c73
--- /dev/null
+++ b/src/mem/packet.hh
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * Declaration of the Packet Class, a packet is a transaction occuring
+ * between a single level of the memory heirarchy (ie L1->L2).
+ */
+
+#ifndef __MEM_PACKET_HH__
+#define __MEM_PACKET_HH__
+
+#include "mem/request.hh"
+#include "arch/isa_traits.hh"
+#include "sim/root.hh"
+
+struct Packet;
+typedef Packet* PacketPtr;
+typedef uint8_t* PacketDataPtr;
+
+/** List of all commands associated with a packet. */
+enum Command
+{
+ Read,
+ Write
+};
+
+/** The result of a particular pakets request. */
+enum PacketResult
+{
+ Success,
+ BadAddress,
+ Unknown
+};
+
+class SenderState{};
+class Coherence{};
+
+/**
+ * A Packet is the structure to handle requests between two levels
+ * of the memory system. The Request is a global object that trancends
+ * all of the memory heirarchy, but at each levels interface a packet
+ * is created to transfer data/requests. For example, a request would
+ * be used to initiate a request to go to memory/IOdevices, as the request
+ * passes through the memory system several packets will be created. One
+ * will be created to go between the L1 and L2 caches and another to go to
+ * the next level and so forth.
+ *
+ * Packets are assumed to be returned in the case of a single response. If
+ * the transaction has no response, then the consumer will delete the packet.
+ */
+struct Packet
+{
+ private:
+ /** A pointer to the data being transfered. It can be differnt sizes
+ at each level of the heirarchy so it belongs in the packet,
+ not request. This may or may not be populated when a responder recieves
+ the packet. If not populated it memory should be allocated.
+ */
+ PacketDataPtr data;
+
+ /** Is the data pointer set to a value that shouldn't be freed when the
+ * packet is destroyed? */
+ bool staticData;
+ /** The data pointer points to a value that should be freed when the packet
+ * is destroyed. */
+ bool dynamicData;
+ /** the data pointer points to an array (thus delete [] ) needs to be called
+ * on it rather than simply delete.*/
+ bool arrayData;
+
+
+ public:
+ /** The address of the request, could be virtual or physical (depending on
+ cache configurations). */
+ Addr addr;
+
+ /** Flag structure to hold flags for this particular packet */
+ uint64_t flags;
+
+ /** A pointer to the overall request. */
+ RequestPtr req;
+
+ /** A virtual base opaque structure used to hold
+ coherence status messages. */
+ Coherence *coherence; // virtual base opaque,
+ // assert(dynamic_cast<Foo>) etc.
+
+ /** A virtual base opaque structure used to hold the senders state. */
+ void *senderState; // virtual base opaque,
+ // assert(dynamic_cast<Foo>) etc.
+
+ /** Indicates the size of the request. */
+ int size;
+
+ /** A index of the source of the transaction. */
+ short src;
+
+ static const short Broadcast = -1;
+
+ /** A index to the destination of the transaction. */
+ short dest;
+
+ /** The command of the transaction. */
+ Command cmd;
+
+ /** The time this request was responded to. Used to calculate latencies. */
+ Tick time;
+
+ /** The result of the packet transaction. */
+ PacketResult result;
+
+ /** Accessor function that returns the source index of the packet. */
+ short getSrc() const { return src; }
+
+ /** Accessor function that returns the destination index of
+ the packet. */
+ short getDest() const { return dest; }
+
+ Packet()
+ : data(NULL), staticData(false), dynamicData(false), arrayData(false),
+ time(curTick), result(Unknown)
+ {}
+
+ ~Packet()
+ { deleteData(); }
+
+
+ /** Minimally reset a packet so something like simple cpu can reuse it. */
+ void reset();
+
+ /** Set the data pointer to the following value that should not be freed. */
+ template <typename T>
+ void dataStatic(T *p);
+
+ /** Set the data pointer to a value that should have delete [] called on it.
+ */
+ template <typename T>
+ void dataDynamicArray(T *p);
+
+ /** set the data pointer to a value that should have delete called on it. */
+ template <typename T>
+ void dataDynamic(T *p);
+
+ /** return the value of what is pointed to in the packet. */
+ template <typename T>
+ T get();
+
+ /** get a pointer to the data ptr. */
+ template <typename T>
+ T* getPtr();
+
+ /** set the value in the data pointer to v. */
+ template <typename T>
+ void set(T v);
+
+ /** delete the data pointed to in the data pointer. Ok to call to matter how
+ * data was allocted. */
+ void deleteData();
+
+ /** If there isn't data in the packet, allocate some. */
+ void allocate();
+
+ /** Do the packet modify the same addresses. */
+ bool intersect(Packet *p);
+};
+
+bool fixPacket(Packet *func, Packet *timing);
+#endif //__MEM_PACKET_HH
diff --git a/src/mem/page_table.cc b/src/mem/page_table.cc
new file mode 100644
index 000000000..c4e1ea193
--- /dev/null
+++ b/src/mem/page_table.cc
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2003 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * Definitions of page table.
+ */
+#include <string>
+#include <map>
+#include <fstream>
+
+#include "arch/faults.hh"
+#include "base/bitfield.hh"
+#include "base/intmath.hh"
+#include "base/trace.hh"
+#include "mem/page_table.hh"
+#include "sim/builder.hh"
+#include "sim/sim_object.hh"
+#include "sim/system.hh"
+
+using namespace std;
+using namespace TheISA;
+
+PageTable::PageTable(System *_system, Addr _pageSize)
+ : pageSize(_pageSize), offsetMask(mask(floorLog2(_pageSize))),
+ system(_system)
+{
+ assert(isPowerOf2(pageSize));
+}
+
+PageTable::~PageTable()
+{
+}
+
+Fault
+PageTable::page_check(Addr addr, int size) const
+{
+ if (size < sizeof(uint64_t)) {
+ if (!isPowerOf2(size)) {
+ panic("Invalid request size!\n");
+ return genMachineCheckFault();
+ }
+
+ if ((size - 1) & addr)
+ return genAlignmentFault();
+ }
+ else {
+ if ((addr & (VMPageSize - 1)) + size > VMPageSize) {
+ panic("Invalid request size!\n");
+ return genMachineCheckFault();
+ }
+
+ if ((sizeof(uint64_t) - 1) & addr)
+ return genAlignmentFault();
+ }
+
+ return NoFault;
+}
+
+
+
+
+void
+PageTable::allocate(Addr vaddr, int size)
+{
+ // starting address must be page aligned
+ assert(pageOffset(vaddr) == 0);
+
+ for (; size > 0; size -= pageSize, vaddr += pageSize) {
+ std::map<Addr,Addr>::iterator iter = pTable.find(vaddr);
+
+ if (iter != pTable.end()) {
+ // already mapped
+ fatal("PageTable::allocate: address 0x%x already mapped", vaddr);
+ }
+
+ pTable[vaddr] = system->new_page();
+ }
+}
+
+
+
+bool
+PageTable::translate(Addr vaddr, Addr &paddr)
+{
+ Addr page_addr = pageAlign(vaddr);
+ std::map<Addr,Addr>::iterator iter = pTable.find(page_addr);
+
+ if (iter == pTable.end()) {
+ return false;
+ }
+
+ paddr = iter->second + pageOffset(vaddr);
+ return true;
+}
+
+
+Fault
+PageTable::translate(RequestPtr &req)
+{
+ Addr paddr;
+ assert(pageAlign(req->getVaddr() + req->getSize() - 1)
+ == pageAlign(req->getVaddr()));
+ if (!translate(req->getVaddr(), paddr)) {
+ return genMachineCheckFault();
+ }
+ req->setPaddr(paddr);
+ return page_check(req->getPaddr(), req->getSize());
+}
diff --git a/src/mem/page_table.hh b/src/mem/page_table.hh
new file mode 100644
index 000000000..26248261a
--- /dev/null
+++ b/src/mem/page_table.hh
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2003 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * Declaration of a non-full system Page Table.
+ */
+
+#ifndef __PAGE_TABLE__
+#define __PAGE_TABLE__
+
+#include <string>
+#include <map>
+
+#include "arch/isa_traits.hh"
+#include "base/trace.hh"
+#include "mem/request.hh"
+#include "mem/packet.hh"
+#include "sim/sim_object.hh"
+
+class System;
+
+/**
+ * Page Table Decleration.
+ */
+class PageTable
+{
+ protected:
+ std::map<Addr,Addr> pTable;
+
+ const Addr pageSize;
+ const Addr offsetMask;
+
+ System *system;
+
+ public:
+
+ PageTable(System *_system, Addr _pageSize = TheISA::VMPageSize);
+
+ ~PageTable();
+
+ Addr pageAlign(Addr a) { return (a & ~offsetMask); }
+ Addr pageOffset(Addr a) { return (a & offsetMask); }
+
+ Fault page_check(Addr addr, int size) const;
+
+ void allocate(Addr vaddr, int size);
+
+ /**
+ * Translate function
+ * @param vaddr The virtual address.
+ * @return Physical address from translation.
+ */
+ bool translate(Addr vaddr, Addr &paddr);
+
+ /**
+ * Perform a translation on the memory request, fills in paddr
+ * field of mem_req.
+ * @param req The memory request.
+ */
+ Fault translate(RequestPtr &req);
+
+};
+
+#endif
diff --git a/src/mem/physical.cc b/src/mem/physical.cc
new file mode 100644
index 000000000..bc2500678
--- /dev/null
+++ b/src/mem/physical.cc
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <zlib.h>
+
+#include <iostream>
+#include <string>
+
+
+#include "base/misc.hh"
+#include "config/full_system.hh"
+#include "mem/packet_impl.hh"
+#include "mem/physical.hh"
+#include "sim/host.hh"
+#include "sim/builder.hh"
+#include "sim/eventq.hh"
+#include "arch/isa_traits.hh"
+
+
+using namespace std;
+using namespace TheISA;
+
+PhysicalMemory::MemResponseEvent::MemResponseEvent(Packet *pkt, MemoryPort* _m)
+ : Event(&mainEventQueue, CPU_Tick_Pri), pkt(pkt), memoryPort(_m)
+{
+
+ this->setFlags(AutoDelete);
+}
+
+void
+PhysicalMemory::MemResponseEvent::process()
+{
+ memoryPort->sendTiming(pkt);
+}
+
+const char *
+PhysicalMemory::MemResponseEvent::description()
+{
+ return "Physical Memory Timing Access respnse event";
+}
+
+PhysicalMemory::PhysicalMemory(const string &n, Tick latency)
+ : MemObject(n),base_addr(0), pmem_addr(NULL), port(NULL), lat(latency)
+{
+ // Hardcoded to 128 MB for now.
+ pmem_size = 1 << 27;
+
+ if (pmem_size % TheISA::PageBytes != 0)
+ panic("Memory Size not divisible by page size\n");
+
+ int map_flags = MAP_ANON | MAP_PRIVATE;
+ pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
+ map_flags, -1, 0);
+
+ if (pmem_addr == (void *)MAP_FAILED) {
+ perror("mmap");
+ fatal("Could not mmap!\n");
+ }
+
+ page_ptr = 0;
+}
+
+void
+PhysicalMemory::init()
+{
+ if (!port)
+ panic("PhysicalMemory not connected to anything!");
+ port->sendStatusChange(Port::RangeChange);
+}
+
+PhysicalMemory::~PhysicalMemory()
+{
+ if (pmem_addr)
+ munmap(pmem_addr, pmem_size);
+ //Remove memPorts?
+}
+
+Addr
+PhysicalMemory::new_page()
+{
+ Addr return_addr = page_ptr << LogVMPageSize;
+ return_addr += base_addr;
+
+ ++page_ptr;
+ return return_addr;
+}
+
+int
+PhysicalMemory::deviceBlockSize()
+{
+ //Can accept anysize request
+ return 0;
+}
+
+bool
+PhysicalMemory::doTimingAccess (Packet *pkt, MemoryPort* memoryPort)
+{
+ doFunctionalAccess(pkt);
+
+ pkt->dest = pkt->src;
+ MemResponseEvent* response = new MemResponseEvent(pkt, memoryPort);
+ response->schedule(curTick + lat);
+
+ return true;
+}
+
+Tick
+PhysicalMemory::doAtomicAccess(Packet *pkt)
+{
+ doFunctionalAccess(pkt);
+ pkt->time = curTick + lat;
+ return curTick + lat;
+}
+
+void
+PhysicalMemory::doFunctionalAccess(Packet *pkt)
+{
+ assert(pkt->addr + pkt->size < pmem_size);
+
+ switch (pkt->cmd) {
+ case Read:
+ memcpy(pkt->getPtr<uint8_t>(), pmem_addr + pkt->addr - base_addr,
+ pkt->size);
+ break;
+ case Write:
+ memcpy(pmem_addr + pkt->addr - base_addr, pkt->getPtr<uint8_t>(),
+ pkt->size);
+ // temporary hack: will need to add real LL/SC implementation
+ // for cacheless systems later.
+ if (pkt->req->getFlags() & LOCKED) {
+ pkt->req->setScResult(1);
+ }
+ break;
+ default:
+ panic("unimplemented");
+ }
+
+ pkt->result = Success;
+}
+
+Port *
+PhysicalMemory::getPort(const std::string &if_name)
+{
+ if (if_name == "") {
+ if (port != NULL)
+ panic("PhysicalMemory::getPort: additional port requested to memory!");
+ port = new MemoryPort(this);
+ return port;
+ } else if (if_name == "functional") {
+ /* special port for functional writes at startup. */
+ return new MemoryPort(this);
+ } else {
+ panic("PhysicalMemory::getPort: unknown port %s requested", if_name);
+ }
+}
+
+void
+PhysicalMemory::recvStatusChange(Port::Status status)
+{
+}
+
+PhysicalMemory::MemoryPort::MemoryPort(PhysicalMemory *_memory)
+ : memory(_memory)
+{ }
+
+void
+PhysicalMemory::MemoryPort::recvStatusChange(Port::Status status)
+{
+ memory->recvStatusChange(status);
+}
+
+void
+PhysicalMemory::MemoryPort::getDeviceAddressRanges(AddrRangeList &resp,
+ AddrRangeList &snoop)
+{
+ memory->getAddressRanges(resp, snoop);
+}
+
+void
+PhysicalMemory::getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
+{
+ snoop.clear();
+ resp.clear();
+ resp.push_back(RangeSize(base_addr, pmem_size));
+}
+
+int
+PhysicalMemory::MemoryPort::deviceBlockSize()
+{
+ return memory->deviceBlockSize();
+}
+
+bool
+PhysicalMemory::MemoryPort::recvTiming(Packet *pkt)
+{
+ return memory->doTimingAccess(pkt, this);
+}
+
+Tick
+PhysicalMemory::MemoryPort::recvAtomic(Packet *pkt)
+{
+ return memory->doAtomicAccess(pkt);
+}
+
+void
+PhysicalMemory::MemoryPort::recvFunctional(Packet *pkt)
+{
+ memory->doFunctionalAccess(pkt);
+}
+
+
+
+void
+PhysicalMemory::serialize(ostream &os)
+{
+ gzFile compressedMem;
+ string filename = name() + ".physmem";
+
+ SERIALIZE_SCALAR(pmem_size);
+ SERIALIZE_SCALAR(filename);
+
+ // write memory file
+ string thefile = Checkpoint::dir() + "/" + filename.c_str();
+ int fd = creat(thefile.c_str(), 0664);
+ if (fd < 0) {
+ perror("creat");
+ fatal("Can't open physical memory checkpoint file '%s'\n", filename);
+ }
+
+ compressedMem = gzdopen(fd, "wb");
+ if (compressedMem == NULL)
+ fatal("Insufficient memory to allocate compression state for %s\n",
+ filename);
+
+ if (gzwrite(compressedMem, pmem_addr, pmem_size) != pmem_size) {
+ fatal("Write failed on physical memory checkpoint file '%s'\n",
+ filename);
+ }
+
+ if (gzclose(compressedMem))
+ fatal("Close failed on physical memory checkpoint file '%s'\n",
+ filename);
+}
+
+void
+PhysicalMemory::unserialize(Checkpoint *cp, const string &section)
+{
+ gzFile compressedMem;
+ long *tempPage;
+ long *pmem_current;
+ uint64_t curSize;
+ uint32_t bytesRead;
+ const int chunkSize = 16384;
+
+
+ // unmap file that was mmaped in the constructor
+ munmap(pmem_addr, pmem_size);
+
+ string filename;
+
+ UNSERIALIZE_SCALAR(pmem_size);
+ UNSERIALIZE_SCALAR(filename);
+
+ filename = cp->cptDir + "/" + filename;
+
+ // mmap memoryfile
+ int fd = open(filename.c_str(), O_RDONLY);
+ if (fd < 0) {
+ perror("open");
+ fatal("Can't open physical memory checkpoint file '%s'", filename);
+ }
+
+ compressedMem = gzdopen(fd, "rb");
+ if (compressedMem == NULL)
+ fatal("Insufficient memory to allocate compression state for %s\n",
+ filename);
+
+
+ pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
+ MAP_ANON | MAP_PRIVATE, -1, 0);
+
+ if (pmem_addr == (void *)MAP_FAILED) {
+ perror("mmap");
+ fatal("Could not mmap physical memory!\n");
+ }
+
+ curSize = 0;
+ tempPage = (long*)malloc(chunkSize);
+ if (tempPage == NULL)
+ fatal("Unable to malloc memory to read file %s\n", filename);
+
+ /* Only copy bytes that are non-zero, so we don't give the VM system hell */
+ while (curSize < pmem_size) {
+ bytesRead = gzread(compressedMem, tempPage, chunkSize);
+ if (bytesRead != chunkSize && bytesRead != pmem_size - curSize)
+ fatal("Read failed on physical memory checkpoint file '%s'"
+ " got %d bytes, expected %d or %d bytes\n",
+ filename, bytesRead, chunkSize, pmem_size-curSize);
+
+ assert(bytesRead % sizeof(long) == 0);
+
+ for (int x = 0; x < bytesRead/sizeof(long); x++)
+ {
+ if (*(tempPage+x) != 0) {
+ pmem_current = (long*)(pmem_addr + curSize + x * sizeof(long));
+ *pmem_current = *(tempPage+x);
+ }
+ }
+ curSize += bytesRead;
+ }
+
+ free(tempPage);
+
+ if (gzclose(compressedMem))
+ fatal("Close failed on physical memory checkpoint file '%s'\n",
+ filename);
+
+}
+
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
+
+ Param<string> file;
+ Param<Range<Addr> > range;
+ Param<Tick> latency;
+
+END_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
+
+ INIT_PARAM_DFLT(file, "memory mapped file", ""),
+ INIT_PARAM(range, "Device Address Range"),
+ INIT_PARAM(latency, "Memory access latency")
+
+END_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
+
+CREATE_SIM_OBJECT(PhysicalMemory)
+{
+
+ return new PhysicalMemory(getInstanceName(), latency);
+}
+
+REGISTER_SIM_OBJECT("PhysicalMemory", PhysicalMemory)
diff --git a/src/mem/physical.hh b/src/mem/physical.hh
new file mode 100644
index 000000000..1cf5444ab
--- /dev/null
+++ b/src/mem/physical.hh
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* @file
+ */
+
+#ifndef __PHYSICAL_MEMORY_HH__
+#define __PHYSICAL_MEMORY_HH__
+
+#include "base/range.hh"
+#include "mem/mem_object.hh"
+#include "mem/packet.hh"
+#include "mem/port.hh"
+#include "sim/eventq.hh"
+#include <map>
+#include <string>
+
+//
+// Functional model for a contiguous block of physical memory. (i.e. RAM)
+//
+class PhysicalMemory : public MemObject
+{
+ class MemoryPort : public Port
+ {
+ PhysicalMemory *memory;
+
+ public:
+
+ MemoryPort(PhysicalMemory *_memory);
+
+ protected:
+
+ virtual bool recvTiming(Packet *pkt);
+
+ virtual Tick recvAtomic(Packet *pkt);
+
+ virtual void recvFunctional(Packet *pkt);
+
+ virtual void recvStatusChange(Status status);
+
+ virtual void getDeviceAddressRanges(AddrRangeList &resp,
+ AddrRangeList &snoop);
+
+ virtual int deviceBlockSize();
+ };
+
+ int numPorts;
+
+
+ struct MemResponseEvent : public Event
+ {
+ Packet *pkt;
+ MemoryPort *memoryPort;
+
+ MemResponseEvent(Packet *pkt, MemoryPort *memoryPort);
+ void process();
+ const char *description();
+ };
+
+ private:
+ // prevent copying of a MainMemory object
+ PhysicalMemory(const PhysicalMemory &specmem);
+ const PhysicalMemory &operator=(const PhysicalMemory &specmem);
+
+ protected:
+ Addr base_addr;
+ Addr pmem_size;
+ uint8_t *pmem_addr;
+ MemoryPort *port;
+ int page_ptr;
+ Tick lat;
+
+ public:
+ Addr new_page();
+ uint64_t size() { return pmem_size; }
+
+ public:
+ PhysicalMemory(const std::string &n, Tick latency);
+ virtual ~PhysicalMemory();
+
+ public:
+ int deviceBlockSize();
+ void getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop);
+ virtual Port *getPort(const std::string &if_name);
+ void virtual init();
+
+ // fast back-door memory access for vtophys(), remote gdb, etc.
+ // uint64_t phys_read_qword(Addr addr) const;
+ private:
+ bool doTimingAccess(Packet *pkt, MemoryPort *memoryPort);
+ Tick doAtomicAccess(Packet *pkt);
+ void doFunctionalAccess(Packet *pkt);
+
+ void recvStatusChange(Port::Status status);
+
+ public:
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+
+};
+
+#endif //__PHYSICAL_MEMORY_HH__
diff --git a/src/mem/port.cc b/src/mem/port.cc
new file mode 100644
index 000000000..fb3103ed1
--- /dev/null
+++ b/src/mem/port.cc
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file Port object definitions.
+ */
+
+#include "base/chunk_generator.hh"
+#include "mem/packet_impl.hh"
+#include "mem/port.hh"
+
+void
+Port::blobHelper(Addr addr, uint8_t *p, int size, Command cmd)
+{
+ Request req(false);
+ Packet pkt;
+ pkt.req = &req;
+ pkt.cmd = cmd;
+ pkt.dest = Packet::Broadcast;
+
+ for (ChunkGenerator gen(addr, size, peerBlockSize());
+ !gen.done(); gen.next()) {
+ req.setPaddr(pkt.addr = gen.addr());
+ req.setSize(pkt.size = gen.size());
+ pkt.dataStatic(p);
+ sendFunctional(&pkt);
+ p += gen.size();
+ }
+}
+
+void
+Port::writeBlob(Addr addr, uint8_t *p, int size)
+{
+ blobHelper(addr, p, size, Write);
+}
+
+void
+Port::readBlob(Addr addr, uint8_t *p, int size)
+{
+ blobHelper(addr, p, size, Read);
+}
+
+void
+Port::memsetBlob(Addr addr, uint8_t val, int size)
+{
+ // quick and dirty...
+ uint8_t *buf = new uint8_t[size];
+
+ memset(buf, val, size);
+ blobHelper(addr, buf, size, Write);
+
+ delete [] buf;
+}
diff --git a/src/mem/port.hh b/src/mem/port.hh
new file mode 100644
index 000000000..1b1920c03
--- /dev/null
+++ b/src/mem/port.hh
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * Port Object Decleration. Ports are used to interface memory objects to
+ * each other. They will always come in pairs, and we refer to the other
+ * port object as the peer. These are used to make the design more
+ * modular so that a specific interface between every type of objcet doesn't
+ * have to be created.
+ */
+
+#ifndef __MEM_PORT_HH__
+#define __MEM_PORT_HH__
+
+#include <list>
+#include <inttypes.h>
+
+#include "base/misc.hh"
+#include "base/range.hh"
+#include "mem/packet.hh"
+#include "mem/request.hh"
+
+/** This typedef is used to clean up the parameter list of
+ * getDeviceAddressRanges() and getPeerAddressRanges(). It's declared
+ * outside the Port object since it's also used by some mem objects.
+ * Eventually we should move this typedef to wherever Addr is
+ * defined.
+ */
+
+typedef std::list<Range<Addr> > AddrRangeList;
+typedef std::list<Range<Addr> >::iterator AddrRangeIter;
+
+/**
+ * Ports are used to interface memory objects to
+ * each other. They will always come in pairs, and we refer to the other
+ * port object as the peer. These are used to make the design more
+ * modular so that a specific interface between every type of objcet doesn't
+ * have to be created.
+ *
+ * Recv accesor functions are being called from the peer interface.
+ * Send accessor functions are being called from the device the port is
+ * associated with, and it will call the peer recv. accessor function.
+ */
+class Port
+{
+ public:
+
+ virtual ~Port() {};
+ // mey be better to use subclasses & RTTI?
+ /** Holds the ports status. Keeps track if it is blocked, or has
+ calculated a range change. */
+ enum Status {
+ Blocked,
+ Unblocked,
+ RangeChange
+ };
+
+ private:
+
+ /** A pointer to the peer port. Ports always come in pairs, that way they
+ can use a standardized interface to communicate between different
+ memory objects. */
+ Port *peer;
+
+ public:
+
+ /** Function to set the pointer for the peer port.
+ @todo should be called by the configuration stuff (python).
+ */
+ void setPeer(Port *port) { peer = port; }
+
+ /** Function to set the pointer for the peer port.
+ @todo should be called by the configuration stuff (python).
+ */
+ Port *getPeer() { return peer; }
+
+ protected:
+
+ /** These functions are protected because they should only be
+ * called by a peer port, never directly by any outside object. */
+
+ /** Called to recive a timing call from the peer port. */
+ virtual bool recvTiming(Packet *pkt) = 0;
+
+ /** Called to recive a atomic call from the peer port. */
+ virtual Tick recvAtomic(Packet *pkt) = 0;
+
+ /** Called to recive a functional call from the peer port. */
+ virtual void recvFunctional(Packet *pkt) = 0;
+
+ /** Called to recieve a status change from the peer port. */
+ virtual void recvStatusChange(Status status) = 0;
+
+ /** Called by a peer port if the send was unsuccesful, and had to
+ wait. This shouldn't be valid for response paths (IO Devices).
+ so it is set to panic if it isn't already defined.
+ */
+ virtual Packet *recvRetry() { panic("??"); }
+
+ /** Called by a peer port in order to determine the block size of the
+ device connected to this port. It sometimes doesn't make sense for
+ this function to be called, a DMA interface doesn't really have a
+ block size, so it is defaulted to a panic.
+ */
+ virtual int deviceBlockSize() { panic("??"); }
+
+ /** The peer port is requesting us to reply with a list of the ranges we
+ are responsible for.
+ @param resp is a list of ranges responded to
+ @param snoop is a list of ranges snooped
+ */
+ virtual void getDeviceAddressRanges(AddrRangeList &resp,
+ AddrRangeList &snoop)
+ { panic("??"); }
+
+ public:
+
+ /** Function called by associated memory device (cache, memory, iodevice)
+ in order to send a timing request to the port. Simply calls the peer
+ port receive function.
+ @return This function returns if the send was succesful in it's
+ recieve. If it was a failure, then the port will wait for a recvRetry
+ at which point it can issue a successful sendTiming. This is used in
+ case a cache has a higher priority request come in while waiting for
+ the bus to arbitrate.
+ */
+ bool sendTiming(Packet *pkt) { return peer->recvTiming(pkt); }
+
+ /** Function called by the associated device to send an atomic access,
+ an access in which the data is moved and the state is updated in one
+ cycle, without interleaving with other memory accesses.
+ */
+ Tick sendAtomic(Packet *pkt)
+ { return peer->recvAtomic(pkt); }
+
+ /** Function called by the associated device to send a functional access,
+ an access in which the data is instantly updated everywhere in the
+ memory system, without affecting the current state of any block or
+ moving the block.
+ */
+ void sendFunctional(Packet *pkt)
+ { return peer->recvFunctional(pkt); }
+
+ /** Called by the associated device to send a status change to the device
+ connected to the peer interface.
+ */
+ void sendStatusChange(Status status) {peer->recvStatusChange(status); }
+
+ /** When a timing access doesn't return a success, some time later the
+ Retry will be sent.
+ */
+ Packet *sendRetry() { return peer->recvRetry(); }
+
+ /** Called by the associated device if it wishes to find out the blocksize
+ of the device on attached to the peer port.
+ */
+ int peerBlockSize() { return peer->deviceBlockSize(); }
+
+ /** Called by the associated device if it wishes to find out the address
+ ranges connected to the peer ports devices.
+ */
+ void getPeerAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
+ { peer->getDeviceAddressRanges(resp, snoop); }
+
+ /** This function is a wrapper around sendFunctional()
+ that breaks a larger, arbitrarily aligned access into
+ appropriate chunks. The default implementation can use
+ getBlockSize() to determine the block size and go from there.
+ */
+ virtual void readBlob(Addr addr, uint8_t *p, int size);
+
+ /** This function is a wrapper around sendFunctional()
+ that breaks a larger, arbitrarily aligned access into
+ appropriate chunks. The default implementation can use
+ getBlockSize() to determine the block size and go from there.
+ */
+ virtual void writeBlob(Addr addr, uint8_t *p, int size);
+
+ /** Fill size bytes starting at addr with byte value val. This
+ should not need to be virtual, since it can be implemented in
+ terms of writeBlob(). However, it shouldn't be
+ performance-critical either, so it could be if we wanted to.
+ */
+ virtual void memsetBlob(Addr addr, uint8_t val, int size);
+
+ private:
+
+ /** Internal helper function for read/writeBlob().
+ */
+ void blobHelper(Addr addr, uint8_t *p, int size, Command cmd);
+};
+
+/** A simple functional port that is only meant for one way communication to
+ * physical memory. It is only meant to be used to load data into memory before
+ * the simulation begins.
+ */
+
+class FunctionalPort : public Port
+{
+ public:
+ virtual bool recvTiming(Packet *pkt) { panic("FuncPort is UniDir"); }
+ virtual Tick recvAtomic(Packet *pkt) { panic("FuncPort is UniDir"); }
+ virtual void recvFunctional(Packet *pkt) { panic("FuncPort is UniDir"); }
+ virtual void recvStatusChange(Status status) {}
+
+ template <typename T>
+ inline void write(Addr addr, T d)
+ {
+ writeBlob(addr, (uint8_t*)&d, sizeof(T));
+ }
+
+ template <typename T>
+ inline T read(Addr addr)
+ {
+ T d;
+ readBlob(addr, (uint8_t*)&d, sizeof(T));
+ return d;
+ }
+};
+
+#endif //__MEM_PORT_HH__
diff --git a/src/mem/request.hh b/src/mem/request.hh
new file mode 100644
index 000000000..2db7b7779
--- /dev/null
+++ b/src/mem/request.hh
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file Decleration of a request, the overall memory request consisting of
+ the parts of the request that are persistent throughout the transaction.
+ */
+
+#ifndef __MEM_REQUEST_HH__
+#define __MEM_REQUEST_HH__
+
+#include "arch/isa_traits.hh"
+
+class Request;
+
+typedef Request* RequestPtr;
+
+/** The request is a Load locked/store conditional. */
+const unsigned LOCKED = 0x001;
+/** The virtual address is also the physical address. */
+const unsigned PHYSICAL = 0x002;
+/** The request is an ALPHA VPTE pal access (hw_ld). */
+const unsigned VPTE = 0x004;
+/** Use the alternate mode bits in ALPHA. */
+const unsigned ALTMODE = 0x008;
+/** The request is to an uncacheable address. */
+const unsigned UNCACHEABLE = 0x010;
+/** The request should not cause a page fault. */
+const unsigned NO_FAULT = 0x020;
+/** The request should be prefetched into the exclusive state. */
+const unsigned PF_EXCLUSIVE = 0x100;
+/** The request should be marked as LRU. */
+const unsigned EVICT_NEXT = 0x200;
+/** The request should ignore unaligned access faults */
+const unsigned NO_ALIGN_FAULT = 0x400;
+
+class Request
+{
+ //@todo Make Accesor functions, make these private.
+ public:
+ /** Constructor, needs a bool to signify if it is/isn't Cpu Request. */
+ Request(bool isCpu);
+
+ /** reset the request to it's initial state so it can be reused.*/
+ void resetAll(bool isCpu);
+
+ /** reset the request's addrs times, etc, so but not everything to same
+ * time. */
+ void resetMin();
+
+//First non-cpu request fields
+ private:
+ /** The physical address of the request. */
+ Addr paddr;
+ /** Wether or not paddr is valid (has been written yet). */
+ bool validPaddr;
+
+ /** The size of the request. */
+ int size;
+ /** Wether or not size is valid (has been written yet). */
+ bool validSize;
+
+ /** The time this request was started. Used to calculate latencies. */
+ Tick time;
+ /** Wether or not time is valid (has been written yet). */
+ bool validTime;
+
+ /** Destination address if this is a block copy. */
+ Addr copyDest;
+ /** Wether or not copyDest is valid (has been written yet). */
+ bool validCopyDest;
+
+ /** Flag structure for the request. */
+ uint32_t flags;
+
+//Accsesors for non-cpu request fields
+ public:
+ /** Accesor for paddr. */
+ Addr getPaddr();
+ /** Accesor for paddr. */
+ void setPaddr(Addr _paddr);
+
+ /** Accesor for size. */
+ int getSize();
+ /** Accesor for size. */
+ void setSize(int _size);
+
+ /** Accesor for time. */
+ Tick getTime();
+ /** Accesor for time. */
+ void setTime(Tick _time);
+
+ /** Accesor for copy dest. */
+ Addr getCopyDest();
+ /** Accesor for copy dest. */
+ void setCopyDest(Addr _copyDest);
+
+ /** Accesor for flags. */
+ uint32_t getFlags();
+ /** Accesor for paddr. */
+ void setFlags(uint32_t _flags);
+
+//Now cpu-request fields
+ private:
+ /** Bool to signify if this is a cpuRequest. */
+ bool cpuReq;
+
+ /** The virtual address of the request. */
+ Addr vaddr;
+ /** Wether or not the vaddr is valid. */
+ bool validVaddr;
+
+ /** The address space ID. */
+ int asid;
+ /** Wether or not the asid is valid. */
+ bool validAsid;
+
+ /** The return value of store conditional. */
+ uint64_t scResult;
+ /** Wether or not the sc result is valid. */
+ bool validScResult;
+
+ /** The cpu number for statistics. */
+ int cpuNum;
+ /** Wether or not the cpu number is valid. */
+ bool validCpuNum;
+
+ /** The requesting thread id. */
+ int threadNum;
+ /** Wether or not the thread id is valid. */
+ bool validThreadNum;
+
+ /** program counter of initiating access; for tracing/debugging */
+ Addr pc;
+ /** Wether or not the pc is valid. */
+ bool validPC;
+
+//Accessor Functions for cpu request fields
+ public:
+ /** Accesor function to determine if this is a cpu request or not.*/
+ bool isCpuRequest();
+
+ /** Accesor function for vaddr.*/
+ Addr getVaddr();
+ /** Accesor function for vaddr.*/
+ void setVaddr(Addr _vaddr);
+
+ /** Accesor function for asid.*/
+ int getAsid();
+ /** Accesor function for asid.*/
+ void setAsid(int _asid);
+
+ /** Accesor function for store conditional return value.*/
+ uint64_t getScResult();
+ /** Accesor function for store conditional return value.*/
+ void setScResult(uint64_t _scResult);
+
+ /** Accesor function for cpu number.*/
+ int getCpuNum();
+ /** Accesor function for cpu number.*/
+ void setCpuNum(int _cpuNum);
+
+ /** Accesor function for thread number.*/
+ int getThreadNum();
+ /** Accesor function for thread number.*/
+ void setThreadNum(int _threadNum);
+
+ /** Accesor function for pc.*/
+ Addr getPC();
+ /** Accesor function for pc.*/
+ void setPC(Addr _pc);
+
+};
+
+#endif // __MEM_REQUEST_HH__
diff --git a/src/mem/translating_port.cc b/src/mem/translating_port.cc
new file mode 100644
index 000000000..5dfeaff31
--- /dev/null
+++ b/src/mem/translating_port.cc
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string>
+#include "base/chunk_generator.hh"
+#include "mem/port.hh"
+#include "mem/translating_port.hh"
+#include "mem/page_table.hh"
+
+using namespace TheISA;
+
+TranslatingPort::TranslatingPort(PageTable *p_table, bool alloc)
+ : pTable(p_table), allocating(alloc)
+{ }
+
+TranslatingPort::~TranslatingPort()
+{ }
+
+bool
+TranslatingPort::tryReadBlob(Addr addr, uint8_t *p, int size)
+{
+ Addr paddr;
+ int prevSize = 0;
+
+ for (ChunkGenerator gen(addr, size, VMPageSize); !gen.done(); gen.next()) {
+
+ if (!pTable->translate(gen.addr(),paddr))
+ return false;
+
+ Port::readBlob(paddr, p + prevSize, gen.size());
+ prevSize += gen.size();
+ }
+
+ return true;
+}
+
+void
+TranslatingPort::readBlob(Addr addr, uint8_t *p, int size)
+{
+ if (!tryReadBlob(addr, p, size))
+ fatal("readBlob(0x%x, ...) failed", addr);
+}
+
+
+bool
+TranslatingPort::tryWriteBlob(Addr addr, uint8_t *p, int size)
+{
+
+ Addr paddr;
+ int prevSize = 0;
+
+ for (ChunkGenerator gen(addr, size, VMPageSize); !gen.done(); gen.next()) {
+
+ if (!pTable->translate(gen.addr(), paddr)) {
+ if (allocating) {
+ pTable->allocate(roundDown(gen.addr(), VMPageSize),
+ VMPageSize);
+ pTable->translate(gen.addr(), paddr);
+ } else {
+ return false;
+ }
+ }
+
+ Port::writeBlob(paddr, p + prevSize, gen.size());
+ prevSize += gen.size();
+ }
+
+ return true;
+}
+
+
+void
+TranslatingPort::writeBlob(Addr addr, uint8_t *p, int size)
+{
+ if (!tryWriteBlob(addr, p, size))
+ fatal("writeBlob(0x%x, ...) failed", addr);
+}
+
+bool
+TranslatingPort::tryMemsetBlob(Addr addr, uint8_t val, int size)
+{
+ Addr paddr;
+
+ for (ChunkGenerator gen(addr, size, VMPageSize); !gen.done(); gen.next()) {
+
+ if (!pTable->translate(gen.addr(), paddr)) {
+ if (allocating) {
+ pTable->allocate(roundDown(gen.addr(), VMPageSize),
+ VMPageSize);
+ pTable->translate(gen.addr(), paddr);
+ } else {
+ return false;
+ }
+ }
+
+ Port::memsetBlob(paddr, val, gen.size());
+ }
+
+ return true;
+}
+
+void
+TranslatingPort::memsetBlob(Addr addr, uint8_t val, int size)
+{
+ if (!tryMemsetBlob(addr, val, size))
+ fatal("memsetBlob(0x%x, ...) failed", addr);
+}
+
+
+bool
+TranslatingPort::tryWriteString(Addr addr, const char *str)
+{
+ Addr paddr,vaddr;
+ uint8_t c;
+
+ vaddr = addr;
+
+ do {
+ c = *str++;
+ if (!pTable->translate(vaddr++,paddr))
+ return false;
+
+ Port::writeBlob(paddr, &c, 1);
+ } while (c);
+
+ return true;
+}
+
+void
+TranslatingPort::writeString(Addr addr, const char *str)
+{
+ if (!tryWriteString(addr, str))
+ fatal("writeString(0x%x, ...) failed", addr);
+}
+
+bool
+TranslatingPort::tryReadString(std::string &str, Addr addr)
+{
+ Addr paddr,vaddr;
+ uint8_t c;
+
+ vaddr = addr;
+
+ do {
+ if (!pTable->translate(vaddr++,paddr))
+ return false;
+
+ Port::readBlob(paddr, &c, 1);
+ str += c;
+ } while (c);
+
+ return true;
+}
+
+void
+TranslatingPort::readString(std::string &str, Addr addr)
+{
+ if (!tryReadString(str, addr))
+ fatal("readString(0x%x, ...) failed", addr);
+}
+
diff --git a/src/mem/translating_port.hh b/src/mem/translating_port.hh
new file mode 100644
index 000000000..7611ac3c7
--- /dev/null
+++ b/src/mem/translating_port.hh
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MEM_TRANSLATING_PROT_HH__
+#define __MEM_TRANSLATING_PROT_HH__
+
+#include "mem/port.hh"
+
+class PageTable;
+
+class TranslatingPort : public FunctionalPort
+{
+ private:
+ PageTable *pTable;
+ bool allocating;
+
+ TranslatingPort(const TranslatingPort &specmem);
+ const TranslatingPort &operator=(const TranslatingPort &specmem);
+
+ public:
+ TranslatingPort(PageTable *p_table, bool alloc = false);
+ virtual ~TranslatingPort();
+
+ public:
+ bool tryReadBlob(Addr addr, uint8_t *p, int size);
+ bool tryWriteBlob(Addr addr, uint8_t *p, int size);
+ bool tryMemsetBlob(Addr addr, uint8_t val, int size);
+ bool tryWriteString(Addr addr, const char *str);
+ bool tryReadString(std::string &str, Addr addr);
+
+ virtual void readBlob(Addr addr, uint8_t *p, int size);
+ virtual void writeBlob(Addr addr, uint8_t *p, int size);
+ virtual void memsetBlob(Addr addr, uint8_t val, int size);
+ void writeString(Addr addr, const char *str);
+ void readString(std::string &str, Addr addr);
+
+};
+
+#endif
diff --git a/src/mem/vport.cc b/src/mem/vport.cc
new file mode 100644
index 000000000..cc569acf3
--- /dev/null
+++ b/src/mem/vport.cc
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file Port object definitions.
+ */
+
+#include "base/chunk_generator.hh"
+#include "mem/vport.hh"
+
+void
+VirtualPort::readBlob(Addr addr, uint8_t *p, int size)
+{
+ Addr paddr;
+ for (ChunkGenerator gen(addr, size, TheISA::PageBytes); !gen.done();
+ gen.next())
+ {
+ if (xc)
+ paddr = TheISA::vtophys(xc,gen.addr());
+ else
+ paddr = TheISA::vtophys(gen.addr());
+
+ FunctionalPort::readBlob(paddr, p, gen.size());
+ p += gen.size();
+ }
+}
+
+void
+VirtualPort::writeBlob(Addr addr, uint8_t *p, int size)
+{
+ Addr paddr;
+ for (ChunkGenerator gen(addr, size, TheISA::PageBytes); !gen.done();
+ gen.next())
+ {
+ if (xc)
+ paddr = TheISA::vtophys(xc,gen.addr());
+ else
+ paddr = TheISA::vtophys(gen.addr());
+
+ FunctionalPort::writeBlob(paddr, p, gen.size());
+ p += gen.size();
+ }
+}
+
diff --git a/src/mem/vport.hh b/src/mem/vport.hh
new file mode 100644
index 000000000..fbc230ba3
--- /dev/null
+++ b/src/mem/vport.hh
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * Virtual Port Object Decleration. These ports incorporate some translation
+ * into their access methods. Thus you can use one to read and write data
+ * to/from virtual addresses.
+ */
+
+#ifndef __MEM_VPORT_HH__
+#define __MEM_VPORT_HH__
+
+#include "mem/port.hh"
+#include "config/full_system.hh"
+#include "arch/vtophys.hh"
+
+
+/** A class that translates a virtual address to a physical address and then
+ * calls the above read/write functions. If an execution context is provided the
+ * address can alway be translated, If not it can only be translated if it is a
+ * simple address masking operation (such as alpha super page accesses).
+ */
+
+class VirtualPort : public FunctionalPort
+{
+ private:
+ ExecContext *xc;
+
+ public:
+ VirtualPort(ExecContext *_xc = NULL)
+ : xc(_xc)
+ {}
+
+ /** Return true if we have an exec context. This is used to prevent someone
+ * from accidently deleting the cpus statically allocated vport.
+ * @return true if an execution context isn't valid
+ */
+ bool nullExecContext() { return xc != NULL; }
+
+ /** Version of readblob that translates virt->phys and deals
+ * with page boundries. */
+ virtual void readBlob(Addr addr, uint8_t *p, int size);
+
+ /** Version of writeBlob that translates virt->phys and deals
+ * with page boundries. */
+ virtual void writeBlob(Addr addr, uint8_t *p, int size);
+};
+
+#endif //__MEM_VPORT_HH__
+
diff --git a/src/python/SConscript b/src/python/SConscript
new file mode 100644
index 000000000..4407e403d
--- /dev/null
+++ b/src/python/SConscript
@@ -0,0 +1,207 @@
+# -*- mode:python -*-
+
+# Copyright (c) 2004-2005 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import os, os.path, re, sys
+
+Import('env')
+
+import scons_helper
+
+def WriteEmbeddedPyFile(target, source, path, name, ext, filename):
+ if isinstance(source, str):
+ source = file(source, 'r')
+
+ if isinstance(target, str):
+ target = file(target, 'w')
+
+ print >>target, "AddModule(%s, %s, %s, %s, '''\\" % \
+ (`path`, `name`, `ext`, `filename`)
+
+ for line in source:
+ line = line
+ # escape existing backslashes
+ line = line.replace('\\', '\\\\')
+ # escape existing triple quotes
+ line = line.replace("'''", r"\'\'\'")
+
+ print >>target, line,
+
+ print >>target, "''')"
+ print >>target
+
+def WriteCFile(target, source, name):
+ if isinstance(source, str):
+ source = file(source, 'r')
+
+ if isinstance(target, str):
+ target = file(target, 'w')
+
+ print >>target, 'const char %s_string[] = {' % name
+
+ count = 0
+ from array import array
+ try:
+ while True:
+ foo = array('B')
+ foo.fromfile(source, 10000)
+ l = [ str(i) for i in foo.tolist() ]
+ count += len(l)
+ for i in xrange(0,9999,20):
+ print >>target, ','.join(l[i:i+20]) + ','
+ except EOFError:
+ l = [ str(i) for i in foo.tolist() ]
+ count += len(l)
+ for i in xrange(0,len(l),20):
+ print >>target, ','.join(l[i:i+20]) + ','
+ print >>target, ','.join(l[i:]) + ','
+
+ print >>target, '};'
+ print >>target, 'const int %s_length = %d;' % (name, count)
+ print >>target
+
+def splitpath(path):
+ dir,file = os.path.split(path)
+ path = []
+ assert(file)
+ while dir:
+ dir,base = os.path.split(dir)
+ path.insert(0, base)
+ return path, file
+
+def MakeEmbeddedPyFile(target, source, env):
+ target = file(str(target[0]), 'w')
+
+ tree = {}
+ for src in source:
+ src = str(src)
+ path,pyfile = splitpath(src)
+ node = tree
+ for dir in path:
+ if not node.has_key(dir):
+ node[dir] = { }
+ node = node[dir]
+
+ name,ext = pyfile.split('.')
+ if name == '__init__':
+ node['.hasinit'] = True
+ node[pyfile] = (src,name,ext,src)
+
+ done = False
+ while not done:
+ done = True
+ for name,entry in tree.items():
+ if not isinstance(entry, dict): continue
+ if entry.has_key('.hasinit'): continue
+
+ done = False
+ del tree[name]
+ for key,val in entry.iteritems():
+ if tree.has_key(key):
+ raise NameError, \
+ "dir already has %s can't add it again" % key
+ tree[key] = val
+
+ files = []
+ def populate(node, path = []):
+ names = node.keys()
+ names.sort()
+ for name in names:
+ if name == '.hasinit':
+ continue
+
+ entry = node[name]
+ if isinstance(entry, dict):
+ if not entry.has_key('.hasinit'):
+ raise NameError, 'package directory missing __init__.py'
+ populate(entry, path + [ name ])
+ else:
+ pyfile,name,ext,filename = entry
+ files.append((pyfile, path, name, ext, filename))
+ populate(tree)
+
+ for pyfile, path, name, ext, filename in files:
+ WriteEmbeddedPyFile(target, pyfile, path, name, ext, filename)
+
+def MakeDefinesPyFile(target, source, env):
+ f = file(str(target[0]), 'w')
+ print >>f, "import __main__"
+ print >>f, "__main__.m5_build_env = ",
+ print >>f, source[0]
+ f.close()
+
+CFileCounter = 0
+def MakePythonCFile(target, source, env):
+ global CFileCounter
+ target = file(str(target[0]), 'w')
+
+ print >>target, '''\
+#include "base/embedfile.hh"
+
+namespace {
+'''
+ for src in source:
+ src = str(src)
+ fname = os.path.basename(src)
+ name = 'embedded_file%d' % CFileCounter
+ CFileCounter += 1
+ WriteCFile(target, src, name)
+ print >>target, '''\
+EmbedMap %(name)s("%(fname)s",
+ %(name)s_string, %(name)s_length);
+
+''' % locals()
+ print >>target, '''\
+
+/* namespace */ }
+'''
+
+# base list of .py files to embed
+embedded_py_files = [ os.path.join(env['ROOT'], 'util/pbs/jobfile.py') ]
+# add all .py files in python/m5
+objpath = os.path.join(env['SRCDIR'], 'python', 'm5')
+for root, dirs, files in os.walk(objpath, topdown=True):
+ for i,dir in enumerate(dirs):
+ if dir == 'SCCS':
+ del dirs[i]
+ break
+
+ assert(root.startswith(objpath))
+ for f in files:
+ if f.endswith('.py'):
+ embedded_py_files.append(os.path.join(root, f))
+
+embedfile_hh = os.path.join(env['SRCDIR'], 'base/embedfile.hh')
+
+optionDict = dict([(opt, env[opt]) for opt in env.ExportOptions])
+env.Command('defines.py', Value(optionDict), MakeDefinesPyFile)
+
+env.Command('embedded_py.py', embedded_py_files, MakeEmbeddedPyFile)
+env.Depends('embedded_py.cc', embedfile_hh)
+env.Command('embedded_py.cc',
+ ['string_importer.py', 'defines.py', 'embedded_py.py'],
+ MakePythonCFile)
diff --git a/src/python/m5/__init__.py b/src/python/m5/__init__.py
new file mode 100644
index 000000000..9bb68a090
--- /dev/null
+++ b/src/python/m5/__init__.py
@@ -0,0 +1,74 @@
+# Copyright (c) 2005 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import sys, os
+
+# define this here so we can use it right away if necessary
+def panic(string):
+ print >>sys.stderr, 'panic:', string
+ sys.exit(1)
+
+def m5execfile(f, global_dict):
+ # copy current sys.path
+ oldpath = sys.path[:]
+ # push file's directory onto front of path
+ sys.path.insert(0, os.path.abspath(os.path.dirname(f)))
+ execfile(f, global_dict)
+ # restore original path
+ sys.path = oldpath
+
+# Prepend given directory to system module search path.
+def AddToPath(path):
+ # if it's a relative path and we know what directory the current
+ # python script is in, make the path relative to that directory.
+ if not os.path.isabs(path) and sys.path[0]:
+ path = os.path.join(sys.path[0], path)
+ path = os.path.realpath(path)
+ # sys.path[0] should always refer to the current script's directory,
+ # so place the new dir right after that.
+ sys.path.insert(1, path)
+
+# find the m5 compile options: must be specified as a dict in
+# __main__.m5_build_env.
+import __main__
+if not hasattr(__main__, 'm5_build_env'):
+ panic("__main__ must define m5_build_env")
+
+# make a SmartDict out of the build options for our local use
+import smartdict
+build_env = smartdict.SmartDict()
+build_env.update(__main__.m5_build_env)
+
+# make a SmartDict out of the OS environment too
+env = smartdict.SmartDict()
+env.update(os.environ)
+
+# import the main m5 config code
+from config import *
+
+# import the built-in object definitions
+from objects import *
+
diff --git a/src/python/m5/config.py b/src/python/m5/config.py
new file mode 100644
index 000000000..1e25e0d09
--- /dev/null
+++ b/src/python/m5/config.py
@@ -0,0 +1,1323 @@
+# Copyright (c) 2004-2005 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from __future__ import generators
+import os, re, sys, types, inspect
+
+import m5
+panic = m5.panic
+from convert import *
+from multidict import multidict
+
+noDot = False
+try:
+ import pydot
+except:
+ noDot = True
+
+class Singleton(type):
+ def __call__(cls, *args, **kwargs):
+ if hasattr(cls, '_instance'):
+ return cls._instance
+
+ cls._instance = super(Singleton, cls).__call__(*args, **kwargs)
+ return cls._instance
+
+#####################################################################
+#
+# M5 Python Configuration Utility
+#
+# The basic idea is to write simple Python programs that build Python
+# objects corresponding to M5 SimObjects for the desired simulation
+# configuration. For now, the Python emits a .ini file that can be
+# parsed by M5. In the future, some tighter integration between M5
+# and the Python interpreter may allow bypassing the .ini file.
+#
+# Each SimObject class in M5 is represented by a Python class with the
+# same name. The Python inheritance tree mirrors the M5 C++ tree
+# (e.g., SimpleCPU derives from BaseCPU in both cases, and all
+# SimObjects inherit from a single SimObject base class). To specify
+# an instance of an M5 SimObject in a configuration, the user simply
+# instantiates the corresponding Python object. The parameters for
+# that SimObject are given by assigning to attributes of the Python
+# object, either using keyword assignment in the constructor or in
+# separate assignment statements. For example:
+#
+# cache = BaseCache(size='64KB')
+# cache.hit_latency = 3
+# cache.assoc = 8
+#
+# The magic lies in the mapping of the Python attributes for SimObject
+# classes to the actual SimObject parameter specifications. This
+# allows parameter validity checking in the Python code. Continuing
+# the example above, the statements "cache.blurfl=3" or
+# "cache.assoc='hello'" would both result in runtime errors in Python,
+# since the BaseCache object has no 'blurfl' parameter and the 'assoc'
+# parameter requires an integer, respectively. This magic is done
+# primarily by overriding the special __setattr__ method that controls
+# assignment to object attributes.
+#
+# Once a set of Python objects have been instantiated in a hierarchy,
+# calling 'instantiate(obj)' (where obj is the root of the hierarchy)
+# will generate a .ini file. See simple-4cpu.py for an example
+# (corresponding to m5-test/simple-4cpu.ini).
+#
+#####################################################################
+
+#####################################################################
+#
+# ConfigNode/SimObject classes
+#
+# The Python class hierarchy rooted by ConfigNode (which is the base
+# class of SimObject, which in turn is the base class of all other M5
+# SimObject classes) has special attribute behavior. In general, an
+# object in this hierarchy has three categories of attribute-like
+# things:
+#
+# 1. Regular Python methods and variables. These must start with an
+# underscore to be treated normally.
+#
+# 2. SimObject parameters. These values are stored as normal Python
+# attributes, but all assignments to these attributes are checked
+# against the pre-defined set of parameters stored in the class's
+# _params dictionary. Assignments to attributes that do not
+# correspond to predefined parameters, or that are not of the correct
+# type, incur runtime errors.
+#
+# 3. Hierarchy children. The child nodes of a ConfigNode are stored
+# in the node's _children dictionary, but can be accessed using the
+# Python attribute dot-notation (just as they are printed out by the
+# simulator). Children cannot be created using attribute assigment;
+# they must be added by specifying the parent node in the child's
+# constructor or using the '+=' operator.
+
+# The SimObject parameters are the most complex, for a few reasons.
+# First, both parameter descriptions and parameter values are
+# inherited. Thus parameter description lookup must go up the
+# inheritance chain like normal attribute lookup, but this behavior
+# must be explicitly coded since the lookup occurs in each class's
+# _params attribute. Second, because parameter values can be set
+# on SimObject classes (to implement default values), the parameter
+# checking behavior must be enforced on class attribute assignments as
+# well as instance attribute assignments. Finally, because we allow
+# class specialization via inheritance (e.g., see the L1Cache class in
+# the simple-4cpu.py example), we must do parameter checking even on
+# class instantiation. To provide all these features, we use a
+# metaclass to define most of the SimObject parameter behavior for
+# this class hierarchy.
+#
+#####################################################################
+
+def isSimObject(value):
+ return isinstance(value, SimObject)
+
+def isSimObjSequence(value):
+ if not isinstance(value, (list, tuple)):
+ return False
+
+ for val in value:
+ if not isNullPointer(val) and not isSimObject(val):
+ return False
+
+ return True
+
+def isNullPointer(value):
+ return isinstance(value, NullSimObject)
+
+# The metaclass for ConfigNode (and thus for everything that derives
+# from ConfigNode, including SimObject). This class controls how new
+# classes that derive from ConfigNode are instantiated, and provides
+# inherited class behavior (just like a class controls how instances
+# of that class are instantiated, and provides inherited instance
+# behavior).
+class MetaSimObject(type):
+ # Attributes that can be set only at initialization time
+ init_keywords = { 'abstract' : types.BooleanType,
+ 'type' : types.StringType }
+ # Attributes that can be set any time
+ keywords = { 'check' : types.FunctionType,
+ 'children' : types.ListType }
+
+ # __new__ is called before __init__, and is where the statements
+ # in the body of the class definition get loaded into the class's
+ # __dict__. We intercept this to filter out parameter assignments
+ # and only allow "private" attributes to be passed to the base
+ # __new__ (starting with underscore).
+ def __new__(mcls, name, bases, dict):
+ # Copy "private" attributes (including special methods such as __new__)
+ # to the official dict. Everything else goes in _init_dict to be
+ # filtered in __init__.
+ cls_dict = {}
+ for key,val in dict.items():
+ if key.startswith('_'):
+ cls_dict[key] = val
+ del dict[key]
+ cls_dict['_init_dict'] = dict
+ return super(MetaSimObject, mcls).__new__(mcls, name, bases, cls_dict)
+
+ # initialization
+ def __init__(cls, name, bases, dict):
+ super(MetaSimObject, cls).__init__(name, bases, dict)
+
+ # initialize required attributes
+ cls._params = multidict()
+ cls._values = multidict()
+ cls._anon_subclass_counter = 0
+
+ # We don't support multiple inheritance. If you want to, you
+ # must fix multidict to deal with it properly.
+ if len(bases) > 1:
+ raise TypeError, "SimObjects do not support multiple inheritance"
+
+ base = bases[0]
+
+ if isinstance(base, MetaSimObject):
+ cls._params.parent = base._params
+ cls._values.parent = base._values
+
+ # If your parent has a value in it that's a config node, clone
+ # it. Do this now so if we update any of the values'
+ # attributes we are updating the clone and not the original.
+ for key,val in base._values.iteritems():
+
+ # don't clone if (1) we're about to overwrite it with
+ # a local setting or (2) we've already cloned a copy
+ # from an earlier (more derived) base
+ if cls._init_dict.has_key(key) or cls._values.has_key(key):
+ continue
+
+ if isSimObject(val):
+ cls._values[key] = val()
+ elif isSimObjSequence(val) and len(val):
+ cls._values[key] = [ v() for v in val ]
+
+ # now process remaining _init_dict items
+ for key,val in cls._init_dict.items():
+ if isinstance(val, (types.FunctionType, types.TypeType)):
+ type.__setattr__(cls, key, val)
+
+ # param descriptions
+ elif isinstance(val, ParamDesc):
+ cls._new_param(key, val)
+
+ # init-time-only keywords
+ elif cls.init_keywords.has_key(key):
+ cls._set_keyword(key, val, cls.init_keywords[key])
+
+ # default: use normal path (ends up in __setattr__)
+ else:
+ setattr(cls, key, val)
+
+ def _set_keyword(cls, keyword, val, kwtype):
+ if not isinstance(val, kwtype):
+ raise TypeError, 'keyword %s has bad type %s (expecting %s)' % \
+ (keyword, type(val), kwtype)
+ if isinstance(val, types.FunctionType):
+ val = classmethod(val)
+ type.__setattr__(cls, keyword, val)
+
+ def _new_param(cls, name, value):
+ cls._params[name] = value
+ if hasattr(value, 'default'):
+ setattr(cls, name, value.default)
+
+ # Set attribute (called on foo.attr = value when foo is an
+ # instance of class cls).
+ def __setattr__(cls, attr, value):
+ # normal processing for private attributes
+ if attr.startswith('_'):
+ type.__setattr__(cls, attr, value)
+ return
+
+ if cls.keywords.has_key(attr):
+ cls._set_keyword(attr, value, cls.keywords[attr])
+ return
+
+ # must be SimObject param
+ param = cls._params.get(attr, None)
+ if param:
+ # It's ok: set attribute by delegating to 'object' class.
+ try:
+ cls._values[attr] = param.convert(value)
+ except Exception, e:
+ msg = "%s\nError setting param %s.%s to %s\n" % \
+ (e, cls.__name__, attr, value)
+ e.args = (msg, )
+ raise
+ # I would love to get rid of this
+ elif isSimObject(value) or isSimObjSequence(value):
+ cls._values[attr] = value
+ else:
+ raise AttributeError, \
+ "Class %s has no parameter %s" % (cls.__name__, attr)
+
+ def __getattr__(cls, attr):
+ if cls._values.has_key(attr):
+ return cls._values[attr]
+
+ raise AttributeError, \
+ "object '%s' has no attribute '%s'" % (cls.__name__, attr)
+
+# The ConfigNode class is the root of the special hierarchy. Most of
+# the code in this class deals with the configuration hierarchy itself
+# (parent/child node relationships).
+class SimObject(object):
+ # Specify metaclass. Any class inheriting from SimObject will
+ # get this metaclass.
+ __metaclass__ = MetaSimObject
+
+ def __init__(self, _value_parent = None, **kwargs):
+ self._children = {}
+ if _value_parent and type(_value_parent) != type(self):
+ # this was called as a type conversion rather than a clone
+ raise TypeError, "Cannot convert %s to %s" % \
+ (_value_parent.__class__.__name__, self.__class__.__name__)
+ if not _value_parent:
+ _value_parent = self.__class__
+ # clone values
+ self._values = multidict(_value_parent._values)
+ for key,val in _value_parent._values.iteritems():
+ if isSimObject(val):
+ setattr(self, key, val())
+ elif isSimObjSequence(val) and len(val):
+ setattr(self, key, [ v() for v in val ])
+ # apply attribute assignments from keyword args, if any
+ for key,val in kwargs.iteritems():
+ setattr(self, key, val)
+
+ def __call__(self, **kwargs):
+ return self.__class__(_value_parent = self, **kwargs)
+
+ def __getattr__(self, attr):
+ if self._values.has_key(attr):
+ return self._values[attr]
+
+ raise AttributeError, "object '%s' has no attribute '%s'" \
+ % (self.__class__.__name__, attr)
+
+ # Set attribute (called on foo.attr = value when foo is an
+ # instance of class cls).
+ def __setattr__(self, attr, value):
+ # normal processing for private attributes
+ if attr.startswith('_'):
+ object.__setattr__(self, attr, value)
+ return
+
+ # must be SimObject param
+ param = self._params.get(attr, None)
+ if param:
+ # It's ok: set attribute by delegating to 'object' class.
+ try:
+ value = param.convert(value)
+ except Exception, e:
+ msg = "%s\nError setting param %s.%s to %s\n" % \
+ (e, self.__class__.__name__, attr, value)
+ e.args = (msg, )
+ raise
+ # I would love to get rid of this
+ elif isSimObject(value) or isSimObjSequence(value):
+ pass
+ else:
+ raise AttributeError, "Class %s has no parameter %s" \
+ % (self.__class__.__name__, attr)
+
+ # clear out old child with this name, if any
+ self.clear_child(attr)
+
+ if isSimObject(value):
+ value.set_path(self, attr)
+ elif isSimObjSequence(value):
+ value = SimObjVector(value)
+ [v.set_path(self, "%s%d" % (attr, i)) for i,v in enumerate(value)]
+
+ self._values[attr] = value
+
+ # this hack allows tacking a '[0]' onto parameters that may or may
+ # not be vectors, and always getting the first element (e.g. cpus)
+ def __getitem__(self, key):
+ if key == 0:
+ return self
+ raise TypeError, "Non-zero index '%s' to SimObject" % key
+
+ # clear out children with given name, even if it's a vector
+ def clear_child(self, name):
+ if not self._children.has_key(name):
+ return
+ child = self._children[name]
+ if isinstance(child, SimObjVector):
+ for i in xrange(len(child)):
+ del self._children["s%d" % (name, i)]
+ del self._children[name]
+
+ def add_child(self, name, value):
+ self._children[name] = value
+
+ def set_path(self, parent, name):
+ if not hasattr(self, '_parent'):
+ self._parent = parent
+ self._name = name
+ parent.add_child(name, self)
+
+ def path(self):
+ if not hasattr(self, '_parent'):
+ return 'root'
+ ppath = self._parent.path()
+ if ppath == 'root':
+ return self._name
+ return ppath + "." + self._name
+
+ def __str__(self):
+ return self.path()
+
+ def ini_str(self):
+ return self.path()
+
+ def find_any(self, ptype):
+ if isinstance(self, ptype):
+ return self, True
+
+ found_obj = None
+ for child in self._children.itervalues():
+ if isinstance(child, ptype):
+ if found_obj != None and child != found_obj:
+ raise AttributeError, \
+ 'parent.any matched more than one: %s %s' % \
+ (found_obj.path, child.path)
+ found_obj = child
+ # search param space
+ for pname,pdesc in self._params.iteritems():
+ if issubclass(pdesc.ptype, ptype):
+ match_obj = self._values[pname]
+ if found_obj != None and found_obj != match_obj:
+ raise AttributeError, \
+ 'parent.any matched more than one: %s' % obj.path
+ found_obj = match_obj
+ return found_obj, found_obj != None
+
+ def unproxy(self, base):
+ return self
+
+ def print_ini(self):
+ print '[' + self.path() + ']' # .ini section header
+
+ if hasattr(self, 'type') and not isinstance(self, ParamContext):
+ print 'type=%s' % self.type
+
+ child_names = self._children.keys()
+ child_names.sort()
+ np_child_names = [c for c in child_names \
+ if not isinstance(self._children[c], ParamContext)]
+ if len(np_child_names):
+ print 'children=%s' % ' '.join(np_child_names)
+
+ param_names = self._params.keys()
+ param_names.sort()
+ for param in param_names:
+ value = self._values.get(param, None)
+ if value != None:
+ if isproxy(value):
+ try:
+ value = value.unproxy(self)
+ except:
+ print >> sys.stderr, \
+ "Error in unproxying param '%s' of %s" % \
+ (param, self.path())
+ raise
+ setattr(self, param, value)
+ print '%s=%s' % (param, self._values[param].ini_str())
+
+ print # blank line between objects
+
+ for child in child_names:
+ self._children[child].print_ini()
+
+ # generate output file for 'dot' to display as a pretty graph.
+ # this code is currently broken.
+ def outputDot(self, dot):
+ label = "{%s|" % self.path
+ if isSimObject(self.realtype):
+ label += '%s|' % self.type
+
+ if self.children:
+ # instantiate children in same order they were added for
+ # backward compatibility (else we can end up with cpu1
+ # before cpu0).
+ for c in self.children:
+ dot.add_edge(pydot.Edge(self.path,c.path, style="bold"))
+
+ simobjs = []
+ for param in self.params:
+ try:
+ if param.value is None:
+ raise AttributeError, 'Parameter with no value'
+
+ value = param.value
+ string = param.string(value)
+ except Exception, e:
+ msg = 'exception in %s:%s\n%s' % (self.name, param.name, e)
+ e.args = (msg, )
+ raise
+
+ if isSimObject(param.ptype) and string != "Null":
+ simobjs.append(string)
+ else:
+ label += '%s = %s\\n' % (param.name, string)
+
+ for so in simobjs:
+ label += "|<%s> %s" % (so, so)
+ dot.add_edge(pydot.Edge("%s:%s" % (self.path, so), so,
+ tailport="w"))
+ label += '}'
+ dot.add_node(pydot.Node(self.path,shape="Mrecord",label=label))
+
+ # recursively dump out children
+ for c in self.children:
+ c.outputDot(dot)
+
+class ParamContext(SimObject):
+ pass
+
+#####################################################################
+#
+# Proxy object support.
+#
+#####################################################################
+
+class BaseProxy(object):
+ def __init__(self, search_self, search_up):
+ self._search_self = search_self
+ self._search_up = search_up
+ self._multiplier = None
+
+ def __setattr__(self, attr, value):
+ if not attr.startswith('_'):
+ raise AttributeError, 'cannot set attribute on proxy object'
+ super(BaseProxy, self).__setattr__(attr, value)
+
+ # support multiplying proxies by constants
+ def __mul__(self, other):
+ if not isinstance(other, (int, long, float)):
+ raise TypeError, "Proxy multiplier must be integer"
+ if self._multiplier == None:
+ self._multiplier = other
+ else:
+ # support chained multipliers
+ self._multiplier *= other
+ return self
+
+ __rmul__ = __mul__
+
+ def _mulcheck(self, result):
+ if self._multiplier == None:
+ return result
+ return result * self._multiplier
+
+ def unproxy(self, base):
+ obj = base
+ done = False
+
+ if self._search_self:
+ result, done = self.find(obj)
+
+ if self._search_up:
+ while not done:
+ try: obj = obj._parent
+ except: break
+
+ result, done = self.find(obj)
+
+ if not done:
+ raise AttributeError, "Can't resolve proxy '%s' from '%s'" % \
+ (self.path(), base.path())
+
+ if isinstance(result, BaseProxy):
+ if result == self:
+ raise RuntimeError, "Cycle in unproxy"
+ result = result.unproxy(obj)
+
+ return self._mulcheck(result)
+
+ def getindex(obj, index):
+ if index == None:
+ return obj
+ try:
+ obj = obj[index]
+ except TypeError:
+ if index != 0:
+ raise
+ # if index is 0 and item is not subscriptable, just
+ # use item itself (so cpu[0] works on uniprocessors)
+ return obj
+ getindex = staticmethod(getindex)
+
+ def set_param_desc(self, pdesc):
+ self._pdesc = pdesc
+
+class AttrProxy(BaseProxy):
+ def __init__(self, search_self, search_up, attr):
+ super(AttrProxy, self).__init__(search_self, search_up)
+ self._attr = attr
+ self._modifiers = []
+
+ def __getattr__(self, attr):
+ # python uses __bases__ internally for inheritance
+ if attr.startswith('_'):
+ return super(AttrProxy, self).__getattr__(self, attr)
+ if hasattr(self, '_pdesc'):
+ raise AttributeError, "Attribute reference on bound proxy"
+ self._modifiers.append(attr)
+ return self
+
+ # support indexing on proxies (e.g., Self.cpu[0])
+ def __getitem__(self, key):
+ if not isinstance(key, int):
+ raise TypeError, "Proxy object requires integer index"
+ self._modifiers.append(key)
+ return self
+
+ def find(self, obj):
+ try:
+ val = getattr(obj, self._attr)
+ except:
+ return None, False
+ while isproxy(val):
+ val = val.unproxy(obj)
+ for m in self._modifiers:
+ if isinstance(m, str):
+ val = getattr(val, m)
+ elif isinstance(m, int):
+ val = val[m]
+ else:
+ assert("Item must be string or integer")
+ while isproxy(val):
+ val = val.unproxy(obj)
+ return val, True
+
+ def path(self):
+ p = self._attr
+ for m in self._modifiers:
+ if isinstance(m, str):
+ p += '.%s' % m
+ elif isinstance(m, int):
+ p += '[%d]' % m
+ else:
+ assert("Item must be string or integer")
+ return p
+
+class AnyProxy(BaseProxy):
+ def find(self, obj):
+ return obj.find_any(self._pdesc.ptype)
+
+ def path(self):
+ return 'any'
+
+def isproxy(obj):
+ if isinstance(obj, (BaseProxy, EthernetAddr)):
+ return True
+ elif isinstance(obj, (list, tuple)):
+ for v in obj:
+ if isproxy(v):
+ return True
+ return False
+
+class ProxyFactory(object):
+ def __init__(self, search_self, search_up):
+ self.search_self = search_self
+ self.search_up = search_up
+
+ def __getattr__(self, attr):
+ if attr == 'any':
+ return AnyProxy(self.search_self, self.search_up)
+ else:
+ return AttrProxy(self.search_self, self.search_up, attr)
+
+# global objects for handling proxies
+Parent = ProxyFactory(search_self = False, search_up = True)
+Self = ProxyFactory(search_self = True, search_up = False)
+
+#####################################################################
+#
+# Parameter description classes
+#
+# The _params dictionary in each class maps parameter names to
+# either a Param or a VectorParam object. These objects contain the
+# parameter description string, the parameter type, and the default
+# value (loaded from the PARAM section of the .odesc files). The
+# _convert() method on these objects is used to force whatever value
+# is assigned to the parameter to the appropriate type.
+#
+# Note that the default values are loaded into the class's attribute
+# space when the parameter dictionary is initialized (in
+# MetaConfigNode._setparams()); after that point they aren't used.
+#
+#####################################################################
+
+# Dummy base class to identify types that are legitimate for SimObject
+# parameters.
+class ParamValue(object):
+
+ # default for printing to .ini file is regular string conversion.
+ # will be overridden in some cases
+ def ini_str(self):
+ return str(self)
+
+ # allows us to blithely call unproxy() on things without checking
+ # if they're really proxies or not
+ def unproxy(self, base):
+ return self
+
+# Regular parameter description.
+class ParamDesc(object):
+ def __init__(self, ptype_str, ptype, *args, **kwargs):
+ self.ptype_str = ptype_str
+ # remember ptype only if it is provided
+ if ptype != None:
+ self.ptype = ptype
+
+ if args:
+ if len(args) == 1:
+ self.desc = args[0]
+ elif len(args) == 2:
+ self.default = args[0]
+ self.desc = args[1]
+ else:
+ raise TypeError, 'too many arguments'
+
+ if kwargs.has_key('desc'):
+ assert(not hasattr(self, 'desc'))
+ self.desc = kwargs['desc']
+ del kwargs['desc']
+
+ if kwargs.has_key('default'):
+ assert(not hasattr(self, 'default'))
+ self.default = kwargs['default']
+ del kwargs['default']
+
+ if kwargs:
+ raise TypeError, 'extra unknown kwargs %s' % kwargs
+
+ if not hasattr(self, 'desc'):
+ raise TypeError, 'desc attribute missing'
+
+ def __getattr__(self, attr):
+ if attr == 'ptype':
+ try:
+ ptype = eval(self.ptype_str, m5.__dict__)
+ if not isinstance(ptype, type):
+ panic("Param qualifier is not a type: %s" % self.ptype)
+ self.ptype = ptype
+ return ptype
+ except NameError:
+ pass
+ raise AttributeError, "'%s' object has no attribute '%s'" % \
+ (type(self).__name__, attr)
+
+ def convert(self, value):
+ if isinstance(value, BaseProxy):
+ value.set_param_desc(self)
+ return value
+ if not hasattr(self, 'ptype') and isNullPointer(value):
+ # deferred evaluation of SimObject; continue to defer if
+ # we're just assigning a null pointer
+ return value
+ if isinstance(value, self.ptype):
+ return value
+ if isNullPointer(value) and issubclass(self.ptype, SimObject):
+ return value
+ return self.ptype(value)
+
+# Vector-valued parameter description. Just like ParamDesc, except
+# that the value is a vector (list) of the specified type instead of a
+# single value.
+
+class VectorParamValue(list):
+ def ini_str(self):
+ return ' '.join([v.ini_str() for v in self])
+
+ def unproxy(self, base):
+ return [v.unproxy(base) for v in self]
+
+class SimObjVector(VectorParamValue):
+ def print_ini(self):
+ for v in self:
+ v.print_ini()
+
+class VectorParamDesc(ParamDesc):
+ # Convert assigned value to appropriate type. If the RHS is not a
+ # list or tuple, it generates a single-element list.
+ def convert(self, value):
+ if isinstance(value, (list, tuple)):
+ # list: coerce each element into new list
+ tmp_list = [ ParamDesc.convert(self, v) for v in value ]
+ if isSimObjSequence(tmp_list):
+ return SimObjVector(tmp_list)
+ else:
+ return VectorParamValue(tmp_list)
+ else:
+ # singleton: leave it be (could coerce to a single-element
+ # list here, but for some historical reason we don't...
+ return ParamDesc.convert(self, value)
+
+
+class ParamFactory(object):
+ def __init__(self, param_desc_class, ptype_str = None):
+ self.param_desc_class = param_desc_class
+ self.ptype_str = ptype_str
+
+ def __getattr__(self, attr):
+ if self.ptype_str:
+ attr = self.ptype_str + '.' + attr
+ return ParamFactory(self.param_desc_class, attr)
+
+ # E.g., Param.Int(5, "number of widgets")
+ def __call__(self, *args, **kwargs):
+ caller_frame = inspect.stack()[1][0]
+ ptype = None
+ try:
+ ptype = eval(self.ptype_str,
+ caller_frame.f_globals, caller_frame.f_locals)
+ if not isinstance(ptype, type):
+ raise TypeError, \
+ "Param qualifier is not a type: %s" % ptype
+ except NameError:
+ # if name isn't defined yet, assume it's a SimObject, and
+ # try to resolve it later
+ pass
+ return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs)
+
+Param = ParamFactory(ParamDesc)
+VectorParam = ParamFactory(VectorParamDesc)
+
+#####################################################################
+#
+# Parameter Types
+#
+# Though native Python types could be used to specify parameter types
+# (the 'ptype' field of the Param and VectorParam classes), it's more
+# flexible to define our own set of types. This gives us more control
+# over how Python expressions are converted to values (via the
+# __init__() constructor) and how these values are printed out (via
+# the __str__() conversion method). Eventually we'll need these types
+# to correspond to distinct C++ types as well.
+#
+#####################################################################
+
+# superclass for "numeric" parameter values, to emulate math
+# operations in a type-safe way. e.g., a Latency times an int returns
+# a new Latency object.
+class NumericParamValue(ParamValue):
+ def __str__(self):
+ return str(self.value)
+
+ def __float__(self):
+ return float(self.value)
+
+ # hook for bounds checking
+ def _check(self):
+ return
+
+ def __mul__(self, other):
+ newobj = self.__class__(self)
+ newobj.value *= other
+ newobj._check()
+ return newobj
+
+ __rmul__ = __mul__
+
+ def __div__(self, other):
+ newobj = self.__class__(self)
+ newobj.value /= other
+ newobj._check()
+ return newobj
+
+ def __sub__(self, other):
+ newobj = self.__class__(self)
+ newobj.value -= other
+ newobj._check()
+ return newobj
+
+class Range(ParamValue):
+ type = int # default; can be overridden in subclasses
+ def __init__(self, *args, **kwargs):
+
+ def handle_kwargs(self, kwargs):
+ if 'end' in kwargs:
+ self.second = self.type(kwargs.pop('end'))
+ elif 'size' in kwargs:
+ self.second = self.first + self.type(kwargs.pop('size')) - 1
+ else:
+ raise TypeError, "Either end or size must be specified"
+
+ if len(args) == 0:
+ self.first = self.type(kwargs.pop('start'))
+ handle_kwargs(self, kwargs)
+
+ elif len(args) == 1:
+ if kwargs:
+ self.first = self.type(args[0])
+ handle_kwargs(self, kwargs)
+ elif isinstance(args[0], Range):
+ self.first = self.type(args[0].first)
+ self.second = self.type(args[0].second)
+ else:
+ self.first = self.type(0)
+ self.second = self.type(args[0]) - 1
+
+ elif len(args) == 2:
+ self.first = self.type(args[0])
+ self.second = self.type(args[1])
+ else:
+ raise TypeError, "Too many arguments specified"
+
+ if kwargs:
+ raise TypeError, "too many keywords: %s" % kwargs.keys()
+
+ def __str__(self):
+ return '%s:%s' % (self.first, self.second)
+
+# Metaclass for bounds-checked integer parameters. See CheckedInt.
+class CheckedIntType(type):
+ def __init__(cls, name, bases, dict):
+ super(CheckedIntType, cls).__init__(name, bases, dict)
+
+ # CheckedInt is an abstract base class, so we actually don't
+ # want to do any processing on it... the rest of this code is
+ # just for classes that derive from CheckedInt.
+ if name == 'CheckedInt':
+ return
+
+ if not (hasattr(cls, 'min') and hasattr(cls, 'max')):
+ if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')):
+ panic("CheckedInt subclass %s must define either\n" \
+ " 'min' and 'max' or 'size' and 'unsigned'\n" \
+ % name);
+ if cls.unsigned:
+ cls.min = 0
+ cls.max = 2 ** cls.size - 1
+ else:
+ cls.min = -(2 ** (cls.size - 1))
+ cls.max = (2 ** (cls.size - 1)) - 1
+
+# Abstract superclass for bounds-checked integer parameters. This
+# class is subclassed to generate parameter classes with specific
+# bounds. Initialization of the min and max bounds is done in the
+# metaclass CheckedIntType.__init__.
+class CheckedInt(NumericParamValue):
+ __metaclass__ = CheckedIntType
+
+ def _check(self):
+ if not self.min <= self.value <= self.max:
+ raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
+ (self.min, self.value, self.max)
+
+ def __init__(self, value):
+ if isinstance(value, str):
+ self.value = toInteger(value)
+ elif isinstance(value, (int, long, float)):
+ self.value = long(value)
+ self._check()
+
+class Int(CheckedInt): size = 32; unsigned = False
+class Unsigned(CheckedInt): size = 32; unsigned = True
+
+class Int8(CheckedInt): size = 8; unsigned = False
+class UInt8(CheckedInt): size = 8; unsigned = True
+class Int16(CheckedInt): size = 16; unsigned = False
+class UInt16(CheckedInt): size = 16; unsigned = True
+class Int32(CheckedInt): size = 32; unsigned = False
+class UInt32(CheckedInt): size = 32; unsigned = True
+class Int64(CheckedInt): size = 64; unsigned = False
+class UInt64(CheckedInt): size = 64; unsigned = True
+
+class Counter(CheckedInt): size = 64; unsigned = True
+class Tick(CheckedInt): size = 64; unsigned = True
+class TcpPort(CheckedInt): size = 16; unsigned = True
+class UdpPort(CheckedInt): size = 16; unsigned = True
+
+class Percent(CheckedInt): min = 0; max = 100
+
+class Float(ParamValue, float):
+ pass
+
+class MemorySize(CheckedInt):
+ size = 64
+ unsigned = True
+ def __init__(self, value):
+ if isinstance(value, MemorySize):
+ self.value = value.value
+ else:
+ self.value = toMemorySize(value)
+ self._check()
+
+class MemorySize32(CheckedInt):
+ size = 32
+ unsigned = True
+ def __init__(self, value):
+ if isinstance(value, MemorySize):
+ self.value = value.value
+ else:
+ self.value = toMemorySize(value)
+ self._check()
+
+class Addr(CheckedInt):
+ size = 64
+ unsigned = True
+ def __init__(self, value):
+ if isinstance(value, Addr):
+ self.value = value.value
+ else:
+ try:
+ self.value = toMemorySize(value)
+ except TypeError:
+ self.value = long(value)
+ self._check()
+
+class AddrRange(Range):
+ type = Addr
+
+# String-valued parameter. Just mixin the ParamValue class
+# with the built-in str class.
+class String(ParamValue,str):
+ pass
+
+# Boolean parameter type. Python doesn't let you subclass bool, since
+# it doesn't want to let you create multiple instances of True and
+# False. Thus this is a little more complicated than String.
+class Bool(ParamValue):
+ def __init__(self, value):
+ try:
+ self.value = toBool(value)
+ except TypeError:
+ self.value = bool(value)
+
+ def __str__(self):
+ return str(self.value)
+
+ def ini_str(self):
+ if self.value:
+ return 'true'
+ return 'false'
+
+def IncEthernetAddr(addr, val = 1):
+ bytes = map(lambda x: int(x, 16), addr.split(':'))
+ bytes[5] += val
+ for i in (5, 4, 3, 2, 1):
+ val,rem = divmod(bytes[i], 256)
+ bytes[i] = rem
+ if val == 0:
+ break
+ bytes[i - 1] += val
+ assert(bytes[0] <= 255)
+ return ':'.join(map(lambda x: '%02x' % x, bytes))
+
+class NextEthernetAddr(object):
+ addr = "00:90:00:00:00:01"
+
+ def __init__(self, inc = 1):
+ self.value = NextEthernetAddr.addr
+ NextEthernetAddr.addr = IncEthernetAddr(NextEthernetAddr.addr, inc)
+
+class EthernetAddr(ParamValue):
+ def __init__(self, value):
+ if value == NextEthernetAddr:
+ self.value = value
+ return
+
+ if not isinstance(value, str):
+ raise TypeError, "expected an ethernet address and didn't get one"
+
+ bytes = value.split(':')
+ if len(bytes) != 6:
+ raise TypeError, 'invalid ethernet address %s' % value
+
+ for byte in bytes:
+ if not 0 <= int(byte) <= 256:
+ raise TypeError, 'invalid ethernet address %s' % value
+
+ self.value = value
+
+ def unproxy(self, base):
+ if self.value == NextEthernetAddr:
+ self.addr = self.value().value
+ return self
+
+ def __str__(self):
+ if self.value == NextEthernetAddr:
+ return self.addr
+ else:
+ return self.value
+
+# Special class for NULL pointers. Note the special check in
+# make_param_value() above that lets these be assigned where a
+# SimObject is required.
+# only one copy of a particular node
+class NullSimObject(object):
+ __metaclass__ = Singleton
+
+ def __call__(cls):
+ return cls
+
+ def _instantiate(self, parent = None, path = ''):
+ pass
+
+ def ini_str(self):
+ return 'Null'
+
+ def unproxy(self, base):
+ return self
+
+ def set_path(self, parent, name):
+ pass
+ def __str__(self):
+ return 'Null'
+
+# The only instance you'll ever need...
+Null = NULL = NullSimObject()
+
+# Enumerated types are a little more complex. The user specifies the
+# type as Enum(foo) where foo is either a list or dictionary of
+# alternatives (typically strings, but not necessarily so). (In the
+# long run, the integer value of the parameter will be the list index
+# or the corresponding dictionary value. For now, since we only check
+# that the alternative is valid and then spit it into a .ini file,
+# there's not much point in using the dictionary.)
+
+# What Enum() must do is generate a new type encapsulating the
+# provided list/dictionary so that specific values of the parameter
+# can be instances of that type. We define two hidden internal
+# classes (_ListEnum and _DictEnum) to serve as base classes, then
+# derive the new type from the appropriate base class on the fly.
+
+
+# Metaclass for Enum types
+class MetaEnum(type):
+ def __init__(cls, name, bases, init_dict):
+ if init_dict.has_key('map'):
+ if not isinstance(cls.map, dict):
+ raise TypeError, "Enum-derived class attribute 'map' " \
+ "must be of type dict"
+ # build list of value strings from map
+ cls.vals = cls.map.keys()
+ cls.vals.sort()
+ elif init_dict.has_key('vals'):
+ if not isinstance(cls.vals, list):
+ raise TypeError, "Enum-derived class attribute 'vals' " \
+ "must be of type list"
+ # build string->value map from vals sequence
+ cls.map = {}
+ for idx,val in enumerate(cls.vals):
+ cls.map[val] = idx
+ else:
+ raise TypeError, "Enum-derived class must define "\
+ "attribute 'map' or 'vals'"
+
+ super(MetaEnum, cls).__init__(name, bases, init_dict)
+
+ def cpp_declare(cls):
+ s = 'enum %s {\n ' % cls.__name__
+ s += ',\n '.join(['%s = %d' % (v,cls.map[v]) for v in cls.vals])
+ s += '\n};\n'
+ return s
+
+# Base class for enum types.
+class Enum(ParamValue):
+ __metaclass__ = MetaEnum
+ vals = []
+
+ def __init__(self, value):
+ if value not in self.map:
+ raise TypeError, "Enum param got bad value '%s' (not in %s)" \
+ % (value, self.vals)
+ self.value = value
+
+ def __str__(self):
+ return self.value
+
+ticks_per_sec = None
+
+# how big does a rounding error need to be before we warn about it?
+frequency_tolerance = 0.001 # 0.1%
+
+# convert a floting-point # of ticks to integer, and warn if rounding
+# discards too much precision
+def tick_check(float_ticks):
+ if float_ticks == 0:
+ return 0
+ int_ticks = int(round(float_ticks))
+ err = (float_ticks - int_ticks) / float_ticks
+ if err > frequency_tolerance:
+ print >> sys.stderr, "Warning: rounding error > tolerance"
+ print >> sys.stderr, " %f rounded to %d" % (float_ticks, int_ticks)
+ #raise ValueError
+ return int_ticks
+
+def getLatency(value):
+ if isinstance(value, Latency) or isinstance(value, Clock):
+ return value.value
+ elif isinstance(value, Frequency) or isinstance(value, RootClock):
+ return 1 / value.value
+ elif isinstance(value, str):
+ try:
+ return toLatency(value)
+ except ValueError:
+ try:
+ return 1 / toFrequency(value)
+ except ValueError:
+ pass # fall through
+ raise ValueError, "Invalid Frequency/Latency value '%s'" % value
+
+
+class Latency(NumericParamValue):
+ def __init__(self, value):
+ self.value = getLatency(value)
+
+ def __getattr__(self, attr):
+ if attr in ('latency', 'period'):
+ return self
+ if attr == 'frequency':
+ return Frequency(self)
+ raise AttributeError, "Latency object has no attribute '%s'" % attr
+
+ # convert latency to ticks
+ def ini_str(self):
+ return str(tick_check(self.value * ticks_per_sec))
+
+class Frequency(NumericParamValue):
+ def __init__(self, value):
+ self.value = 1 / getLatency(value)
+
+ def __getattr__(self, attr):
+ if attr == 'frequency':
+ return self
+ if attr in ('latency', 'period'):
+ return Latency(self)
+ raise AttributeError, "Frequency object has no attribute '%s'" % attr
+
+ # convert frequency to ticks per period
+ def ini_str(self):
+ return self.period.ini_str()
+
+# Just like Frequency, except ini_str() is absolute # of ticks per sec (Hz).
+# We can't inherit from Frequency because we don't want it to be directly
+# assignable to a regular Frequency parameter.
+class RootClock(ParamValue):
+ def __init__(self, value):
+ self.value = 1 / getLatency(value)
+
+ def __getattr__(self, attr):
+ if attr == 'frequency':
+ return Frequency(self)
+ if attr in ('latency', 'period'):
+ return Latency(self)
+ raise AttributeError, "Frequency object has no attribute '%s'" % attr
+
+ def ini_str(self):
+ return str(tick_check(self.value))
+
+# A generic frequency and/or Latency value. Value is stored as a latency,
+# but to avoid ambiguity this object does not support numeric ops (* or /).
+# An explicit conversion to a Latency or Frequency must be made first.
+class Clock(ParamValue):
+ def __init__(self, value):
+ self.value = getLatency(value)
+
+ def __getattr__(self, attr):
+ if attr == 'frequency':
+ return Frequency(self)
+ if attr in ('latency', 'period'):
+ return Latency(self)
+ raise AttributeError, "Frequency object has no attribute '%s'" % attr
+
+ def ini_str(self):
+ return self.period.ini_str()
+
+class NetworkBandwidth(float,ParamValue):
+ def __new__(cls, value):
+ val = toNetworkBandwidth(value) / 8.0
+ return super(cls, NetworkBandwidth).__new__(cls, val)
+
+ def __str__(self):
+ return str(self.val)
+
+ def ini_str(self):
+ return '%f' % (ticks_per_sec / float(self))
+
+class MemoryBandwidth(float,ParamValue):
+ def __new__(self, value):
+ val = toMemoryBandwidth(value)
+ return super(cls, MemoryBandwidth).__new__(cls, val)
+
+ def __str__(self):
+ return str(self.val)
+
+ def ini_str(self):
+ return '%f' % (ticks_per_sec / float(self))
+
+#
+# "Constants"... handy aliases for various values.
+#
+
+# Some memory range specifications use this as a default upper bound.
+MaxAddr = Addr.max
+MaxTick = Tick.max
+AllMemory = AddrRange(0, MaxAddr)
+
+#####################################################################
+
+# The final hook to generate .ini files. Called from configuration
+# script once config is built.
+def instantiate(root):
+ global ticks_per_sec
+ ticks_per_sec = float(root.clock.frequency)
+ root.print_ini()
+ noDot = True # temporary until we fix dot
+ if not noDot:
+ dot = pydot.Dot()
+ instance.outputDot(dot)
+ dot.orientation = "portrait"
+ dot.size = "8.5,11"
+ dot.ranksep="equally"
+ dot.rank="samerank"
+ dot.write("config.dot")
+ dot.write_ps("config.ps")
+
+# __all__ defines the list of symbols that get exported when
+# 'from config import *' is invoked. Try to keep this reasonably
+# short to avoid polluting other namespaces.
+__all__ = ['SimObject', 'ParamContext', 'Param', 'VectorParam',
+ 'Parent', 'Self',
+ 'Enum', 'Bool', 'String', 'Float',
+ 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
+ 'Int32', 'UInt32', 'Int64', 'UInt64',
+ 'Counter', 'Addr', 'Tick', 'Percent',
+ 'TcpPort', 'UdpPort', 'EthernetAddr',
+ 'MemorySize', 'MemorySize32',
+ 'Latency', 'Frequency', 'RootClock', 'Clock',
+ 'NetworkBandwidth', 'MemoryBandwidth',
+ 'Range', 'AddrRange', 'MaxAddr', 'MaxTick', 'AllMemory',
+ 'Null', 'NULL',
+ 'NextEthernetAddr', 'instantiate']
+
diff --git a/src/python/m5/convert.py b/src/python/m5/convert.py
new file mode 100644
index 000000000..73181e985
--- /dev/null
+++ b/src/python/m5/convert.py
@@ -0,0 +1,227 @@
+# Copyright (c) 2005 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# metric prefixes
+exa = 1.0e18
+peta = 1.0e15
+tera = 1.0e12
+giga = 1.0e9
+mega = 1.0e6
+kilo = 1.0e3
+
+milli = 1.0e-3
+micro = 1.0e-6
+nano = 1.0e-9
+pico = 1.0e-12
+femto = 1.0e-15
+atto = 1.0e-18
+
+# power of 2 prefixes
+kibi = 1024
+mebi = kibi * 1024
+gibi = mebi * 1024
+tebi = gibi * 1024
+pebi = tebi * 1024
+exbi = pebi * 1024
+
+# memory size configuration stuff
+def toFloat(value):
+ if not isinstance(value, str):
+ raise TypeError, "wrong type '%s' should be str" % type(value)
+
+ if value.endswith('Ei'):
+ return float(value[:-2]) * exbi
+ elif value.endswith('Pi'):
+ return float(value[:-2]) * pebi
+ elif value.endswith('Ti'):
+ return float(value[:-2]) * tebi
+ elif value.endswith('Gi'):
+ return float(value[:-2]) * gibi
+ elif value.endswith('Mi'):
+ return float(value[:-2]) * mebi
+ elif value.endswith('ki'):
+ return float(value[:-2]) * kibi
+ elif value.endswith('E'):
+ return float(value[:-1]) * exa
+ elif value.endswith('P'):
+ return float(value[:-1]) * peta
+ elif value.endswith('T'):
+ return float(value[:-1]) * tera
+ elif value.endswith('G'):
+ return float(value[:-1]) * giga
+ elif value.endswith('M'):
+ return float(value[:-1]) * mega
+ elif value.endswith('k'):
+ return float(value[:-1]) * kilo
+ elif value.endswith('m'):
+ return float(value[:-1]) * milli
+ elif value.endswith('u'):
+ return float(value[:-1]) * micro
+ elif value.endswith('n'):
+ return float(value[:-1]) * nano
+ elif value.endswith('p'):
+ return float(value[:-1]) * pico
+ elif value.endswith('f'):
+ return float(value[:-1]) * femto
+ else:
+ return float(value)
+
+def toInteger(value):
+ value = toFloat(value)
+ result = long(value)
+ if value != result:
+ raise ValueError, "cannot convert '%s' to integer" % value
+
+ return result
+
+_bool_dict = {
+ 'true' : True, 't' : True, 'yes' : True, 'y' : True, '1' : True,
+ 'false' : False, 'f' : False, 'no' : False, 'n' : False, '0' : False
+ }
+
+def toBool(value):
+ if not isinstance(value, str):
+ raise TypeError, "wrong type '%s' should be str" % type(value)
+
+ value = value.lower()
+ result = _bool_dict.get(value, None)
+ if result == None:
+ raise ValueError, "cannot convert '%s' to bool" % value
+ return result
+
+def toFrequency(value):
+ if not isinstance(value, str):
+ raise TypeError, "wrong type '%s' should be str" % type(value)
+
+ if value.endswith('THz'):
+ return float(value[:-3]) * tera
+ elif value.endswith('GHz'):
+ return float(value[:-3]) * giga
+ elif value.endswith('MHz'):
+ return float(value[:-3]) * mega
+ elif value.endswith('kHz'):
+ return float(value[:-3]) * kilo
+ elif value.endswith('Hz'):
+ return float(value[:-2])
+
+ raise ValueError, "cannot convert '%s' to frequency" % value
+
+def toLatency(value):
+ if not isinstance(value, str):
+ raise TypeError, "wrong type '%s' should be str" % type(value)
+
+ if value.endswith('ps'):
+ return float(value[:-2]) * pico
+ elif value.endswith('ns'):
+ return float(value[:-2]) * nano
+ elif value.endswith('us'):
+ return float(value[:-2]) * micro
+ elif value.endswith('ms'):
+ return float(value[:-2]) * milli
+ elif value.endswith('s'):
+ return float(value[:-1])
+
+ raise ValueError, "cannot convert '%s' to latency" % value
+
+def toClockPeriod(value):
+ """result is a clock period"""
+
+ if not isinstance(value, str):
+ raise TypeError, "wrong type '%s' should be str" % type(value)
+
+ try:
+ val = toFrequency(value)
+ if val != 0:
+ val = 1 / val
+ return val
+ except ValueError:
+ pass
+
+ try:
+ val = toLatency(value)
+ return val
+ except ValueError:
+ pass
+
+ raise ValueError, "cannot convert '%s' to clock period" % value
+
+
+def toNetworkBandwidth(value):
+ if not isinstance(value, str):
+ raise TypeError, "wrong type '%s' should be str" % type(value)
+
+ if value.endswith('Tbps'):
+ return float(value[:-4]) * tera
+ elif value.endswith('Gbps'):
+ return float(value[:-4]) * giga
+ elif value.endswith('Mbps'):
+ return float(value[:-4]) * mega
+ elif value.endswith('kbps'):
+ return float(value[:-4]) * kilo
+ elif value.endswith('bps'):
+ return float(value[:-3])
+ else:
+ return float(value)
+
+ raise ValueError, "cannot convert '%s' to network bandwidth" % value
+
+def toMemoryBandwidth(value):
+ if not isinstance(value, str):
+ raise TypeError, "wrong type '%s' should be str" % type(value)
+
+ if value.endswith('PB/s'):
+ return float(value[:-4]) * pebi
+ elif value.endswith('TB/s'):
+ return float(value[:-4]) * tebi
+ elif value.endswith('GB/s'):
+ return float(value[:-4]) * gibi
+ elif value.endswith('MB/s'):
+ return float(value[:-4]) * mebi
+ elif value.endswith('kB/s'):
+ return float(value[:-4]) * kibi
+ elif value.endswith('B/s'):
+ return float(value[:-3])
+
+ raise ValueError, "cannot convert '%s' to memory bandwidth" % value
+
+def toMemorySize(value):
+ if not isinstance(value, str):
+ raise TypeError, "wrong type '%s' should be str" % type(value)
+
+ if value.endswith('PB'):
+ return long(value[:-2]) * pebi
+ elif value.endswith('TB'):
+ return long(value[:-2]) * tebi
+ elif value.endswith('GB'):
+ return long(value[:-2]) * gibi
+ elif value.endswith('MB'):
+ return long(value[:-2]) * mebi
+ elif value.endswith('kB'):
+ return long(value[:-2]) * kibi
+ elif value.endswith('B'):
+ return long(value[:-1])
+
+ raise ValueError, "cannot convert '%s' to memory size" % value
diff --git a/src/python/m5/multidict.py b/src/python/m5/multidict.py
new file mode 100644
index 000000000..fd40ebbbd
--- /dev/null
+++ b/src/python/m5/multidict.py
@@ -0,0 +1,184 @@
+# Copyright (c) 2005 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+__all__ = [ 'multidict' ]
+
+class multidict(object):
+ __nodefault = object()
+ def __init__(self, parent = {}, **kwargs):
+ self.dict = dict(**kwargs)
+ self.parent = parent
+ self.deleted = {}
+
+ def __str__(self):
+ return str(dict(self.items()))
+
+ def __repr__(self):
+ return `dict(self.items())`
+
+ def __contains__(self, key):
+ return self.dict.has_key(key) or self.parent.has_key(key)
+
+ def __delitem__(self, key):
+ try:
+ del self.dict[key]
+ except KeyError, e:
+ if key in self.parent:
+ self.deleted[key] = True
+ else:
+ raise KeyError, e
+
+ def __setitem__(self, key, value):
+ self.deleted.pop(key, False)
+ self.dict[key] = value
+
+ def __getitem__(self, key):
+ try:
+ return self.dict[key]
+ except KeyError, e:
+ if not self.deleted.get(key, False) and key in self.parent:
+ return self.parent[key]
+ else:
+ raise KeyError, e
+
+ def __len__(self):
+ return len(self.dict) + len(self.parent)
+
+ def next(self):
+ for key,value in self.dict.items():
+ yield key,value
+
+ if self.parent:
+ for key,value in self.parent.next():
+ if key not in self.dict and key not in self.deleted:
+ yield key,value
+
+ def has_key(self, key):
+ return key in self
+
+ def iteritems(self):
+ for item in self.next():
+ yield item
+
+ def items(self):
+ return [ item for item in self.next() ]
+
+ def iterkeys(self):
+ for key,value in self.next():
+ yield key
+
+ def keys(self):
+ return [ key for key,value in self.next() ]
+
+ def itervalues(self):
+ for key,value in self.next():
+ yield value
+
+ def values(self):
+ return [ value for key,value in self.next() ]
+
+ def get(self, key, default=__nodefault):
+ try:
+ return self[key]
+ except KeyError, e:
+ if default != self.__nodefault:
+ return default
+ else:
+ raise KeyError, e
+
+ def setdefault(self, key, default):
+ try:
+ return self[key]
+ except KeyError:
+ self.deleted.pop(key, False)
+ self.dict[key] = default
+ return default
+
+ def _dump(self):
+ print 'multidict dump'
+ node = self
+ while isinstance(node, multidict):
+ print ' ', node.dict
+ node = node.parent
+
+ def _dumpkey(self, key):
+ values = []
+ node = self
+ while isinstance(node, multidict):
+ if key in node.dict:
+ values.append(node.dict[key])
+ node = node.parent
+ print key, values
+
+if __name__ == '__main__':
+ test1 = multidict()
+ test2 = multidict(test1)
+ test3 = multidict(test2)
+ test4 = multidict(test3)
+
+ test1['a'] = 'test1_a'
+ test1['b'] = 'test1_b'
+ test1['c'] = 'test1_c'
+ test1['d'] = 'test1_d'
+ test1['e'] = 'test1_e'
+
+ test2['a'] = 'test2_a'
+ del test2['b']
+ test2['c'] = 'test2_c'
+ del test1['a']
+
+ test2.setdefault('f', multidict)
+
+ print 'test1>', test1.items()
+ print 'test2>', test2.items()
+ #print test1['a']
+ print test1['b']
+ print test1['c']
+ print test1['d']
+ print test1['e']
+
+ print test2['a']
+ #print test2['b']
+ print test2['c']
+ print test2['d']
+ print test2['e']
+
+ for key in test2.iterkeys():
+ print key
+
+ test2.get('g', 'foo')
+ #test2.get('b')
+ test2.get('b', 'bar')
+ test2.setdefault('b', 'blah')
+ print test1
+ print test2
+ print `test2`
+
+ print len(test2)
+
+ test3['a'] = [ 0, 1, 2, 3 ]
+
+ print test4
diff --git a/src/python/m5/objects/AlphaConsole.py b/src/python/m5/objects/AlphaConsole.py
new file mode 100644
index 000000000..68e6089ab
--- /dev/null
+++ b/src/python/m5/objects/AlphaConsole.py
@@ -0,0 +1,9 @@
+from m5 import *
+from Device import BasicPioDevice
+
+class AlphaConsole(BasicPioDevice):
+ type = 'AlphaConsole'
+ cpu = Param.BaseCPU(Parent.any, "Processor")
+ disk = Param.SimpleDisk("Simple Disk")
+ sim_console = Param.SimConsole(Parent.any, "The Simulator Console")
+ system = Param.AlphaSystem(Parent.any, "system object")
diff --git a/src/python/m5/objects/AlphaFullCPU.py b/src/python/m5/objects/AlphaFullCPU.py
new file mode 100644
index 000000000..48989d057
--- /dev/null
+++ b/src/python/m5/objects/AlphaFullCPU.py
@@ -0,0 +1,80 @@
+from m5 import *
+from BaseCPU import BaseCPU
+
+class DerivAlphaFullCPU(BaseCPU):
+ type = 'DerivAlphaFullCPU'
+
+ numThreads = Param.Unsigned("number of HW thread contexts")
+
+ if not build_env['FULL_SYSTEM']:
+ mem = Param.FunctionalMemory(NULL, "memory")
+
+ decodeToFetchDelay = Param.Unsigned("Decode to fetch delay")
+ renameToFetchDelay = Param.Unsigned("Rename to fetch delay")
+ iewToFetchDelay = Param.Unsigned("Issue/Execute/Writeback to fetch "
+ "delay")
+ commitToFetchDelay = Param.Unsigned("Commit to fetch delay")
+ fetchWidth = Param.Unsigned("Fetch width")
+
+ renameToDecodeDelay = Param.Unsigned("Rename to decode delay")
+ iewToDecodeDelay = Param.Unsigned("Issue/Execute/Writeback to decode "
+ "delay")
+ commitToDecodeDelay = Param.Unsigned("Commit to decode delay")
+ fetchToDecodeDelay = Param.Unsigned("Fetch to decode delay")
+ decodeWidth = Param.Unsigned("Decode width")
+
+ iewToRenameDelay = Param.Unsigned("Issue/Execute/Writeback to rename "
+ "delay")
+ commitToRenameDelay = Param.Unsigned("Commit to rename delay")
+ decodeToRenameDelay = Param.Unsigned("Decode to rename delay")
+ renameWidth = Param.Unsigned("Rename width")
+
+ commitToIEWDelay = Param.Unsigned("Commit to "
+ "Issue/Execute/Writeback delay")
+ renameToIEWDelay = Param.Unsigned("Rename to "
+ "Issue/Execute/Writeback delay")
+ issueToExecuteDelay = Param.Unsigned("Issue to execute delay (internal "
+ "to the IEW stage)")
+ issueWidth = Param.Unsigned("Issue width")
+ executeWidth = Param.Unsigned("Execute width")
+ executeIntWidth = Param.Unsigned("Integer execute width")
+ executeFloatWidth = Param.Unsigned("Floating point execute width")
+ executeBranchWidth = Param.Unsigned("Branch execute width")
+ executeMemoryWidth = Param.Unsigned("Memory execute width")
+
+ iewToCommitDelay = Param.Unsigned("Issue/Execute/Writeback to commit "
+ "delay")
+ renameToROBDelay = Param.Unsigned("Rename to reorder buffer delay")
+ commitWidth = Param.Unsigned("Commit width")
+ squashWidth = Param.Unsigned("Squash width")
+
+ local_predictor_size = Param.Unsigned("Size of local predictor")
+ local_ctr_bits = Param.Unsigned("Bits per counter")
+ local_history_table_size = Param.Unsigned("Size of local history table")
+ local_history_bits = Param.Unsigned("Bits for the local history")
+ global_predictor_size = Param.Unsigned("Size of global predictor")
+ global_ctr_bits = Param.Unsigned("Bits per counter")
+ global_history_bits = Param.Unsigned("Bits of history")
+ choice_predictor_size = Param.Unsigned("Size of choice predictor")
+ choice_ctr_bits = Param.Unsigned("Bits of choice counters")
+
+ BTBEntries = Param.Unsigned("Number of BTB entries")
+ BTBTagSize = Param.Unsigned("Size of the BTB tags, in bits")
+
+ RASSize = Param.Unsigned("RAS size")
+
+ LQEntries = Param.Unsigned("Number of load queue entries")
+ SQEntries = Param.Unsigned("Number of store queue entries")
+ LFSTSize = Param.Unsigned("Last fetched store table size")
+ SSITSize = Param.Unsigned("Store set ID table size")
+
+ numPhysIntRegs = Param.Unsigned("Number of physical integer registers")
+ numPhysFloatRegs = Param.Unsigned("Number of physical floating point "
+ "registers")
+ numIQEntries = Param.Unsigned("Number of instruction queue entries")
+ numROBEntries = Param.Unsigned("Number of reorder buffer entries")
+
+ instShiftAmt = Param.Unsigned("Number of bits to shift instructions by")
+
+ function_trace = Param.Bool(False, "Enable function trace")
+ function_trace_start = Param.Tick(0, "Cycle to start function trace")
diff --git a/src/python/m5/objects/AlphaTLB.py b/src/python/m5/objects/AlphaTLB.py
new file mode 100644
index 000000000..5edf8e13d
--- /dev/null
+++ b/src/python/m5/objects/AlphaTLB.py
@@ -0,0 +1,13 @@
+from m5 import *
+class AlphaTLB(SimObject):
+ type = 'AlphaTLB'
+ abstract = True
+ size = Param.Int("TLB size")
+
+class AlphaDTB(AlphaTLB):
+ type = 'AlphaDTB'
+ size = 64
+
+class AlphaITB(AlphaTLB):
+ type = 'AlphaITB'
+ size = 48
diff --git a/src/python/m5/objects/BadDevice.py b/src/python/m5/objects/BadDevice.py
new file mode 100644
index 000000000..9cb9a8f03
--- /dev/null
+++ b/src/python/m5/objects/BadDevice.py
@@ -0,0 +1,6 @@
+from m5 import *
+from Device import BasicPioDevice
+
+class BadDevice(BasicPioDevice):
+ type = 'BadDevice'
+ devicename = Param.String("Name of device to error on")
diff --git a/src/python/m5/objects/BaseCPU.py b/src/python/m5/objects/BaseCPU.py
new file mode 100644
index 000000000..49cb2a8f3
--- /dev/null
+++ b/src/python/m5/objects/BaseCPU.py
@@ -0,0 +1,27 @@
+from m5 import *
+class BaseCPU(SimObject):
+ type = 'BaseCPU'
+ abstract = True
+ mem = Param.MemObject("memory")
+
+ if build_env['FULL_SYSTEM']:
+ dtb = Param.AlphaDTB("Data TLB")
+ itb = Param.AlphaITB("Instruction TLB")
+ system = Param.System(Parent.any, "system object")
+ cpu_id = Param.Int(-1, "CPU identifier")
+ else:
+ workload = VectorParam.Process("processes to run")
+
+ max_insts_all_threads = Param.Counter(0,
+ "terminate when all threads have reached this inst count")
+ max_insts_any_thread = Param.Counter(0,
+ "terminate when any thread reaches this inst count")
+ max_loads_all_threads = Param.Counter(0,
+ "terminate when all threads have reached this load count")
+ max_loads_any_thread = Param.Counter(0,
+ "terminate when any thread reaches this load count")
+
+ defer_registration = Param.Bool(False,
+ "defer registration with system (for sampling)")
+
+ clock = Param.Clock(Parent.clock, "clock speed")
diff --git a/src/python/m5/objects/BaseCache.py b/src/python/m5/objects/BaseCache.py
new file mode 100644
index 000000000..79d21572a
--- /dev/null
+++ b/src/python/m5/objects/BaseCache.py
@@ -0,0 +1,65 @@
+from m5 import *
+from BaseMem import BaseMem
+
+class Prefetch(Enum): vals = ['none', 'tagged', 'stride', 'ghb']
+
+class BaseCache(BaseMem):
+ type = 'BaseCache'
+ adaptive_compression = Param.Bool(False,
+ "Use an adaptive compression scheme")
+ assoc = Param.Int("associativity")
+ block_size = Param.Int("block size in bytes")
+ compressed_bus = Param.Bool(False,
+ "This cache connects to a compressed memory")
+ compression_latency = Param.Latency('0ns',
+ "Latency in cycles of compression algorithm")
+ do_copy = Param.Bool(False, "perform fast copies in the cache")
+ hash_delay = Param.Int(1, "time in cycles of hash access")
+ in_bus = Param.Bus(NULL, "incoming bus object")
+ lifo = Param.Bool(False,
+ "whether this NIC partition should use LIFO repl. policy")
+ max_miss_count = Param.Counter(0,
+ "number of misses to handle before calling exit")
+ mem_trace = Param.MemTraceWriter(NULL,
+ "memory trace writer to record accesses")
+ mshrs = Param.Int("number of MSHRs (max outstanding requests)")
+ out_bus = Param.Bus("outgoing bus object")
+ prioritizeRequests = Param.Bool(False,
+ "always service demand misses first")
+ protocol = Param.CoherenceProtocol(NULL, "coherence protocol to use")
+ repl = Param.Repl(NULL, "replacement policy")
+ size = Param.MemorySize("capacity in bytes")
+ split = Param.Bool(False, "whether or not this cache is split")
+ split_size = Param.Int(0,
+ "How many ways of the cache belong to CPU/LRU partition")
+ store_compressed = Param.Bool(False,
+ "Store compressed data in the cache")
+ subblock_size = Param.Int(0,
+ "Size of subblock in IIC used for compression")
+ tgts_per_mshr = Param.Int("max number of accesses per MSHR")
+ trace_addr = Param.Addr(0, "address to trace")
+ two_queue = Param.Bool(False,
+ "whether the lifo should have two queue replacement")
+ write_buffers = Param.Int(8, "number of write buffers")
+ prefetch_miss = Param.Bool(False,
+ "wheter you are using the hardware prefetcher from Miss stream")
+ prefetch_access = Param.Bool(False,
+ "wheter you are using the hardware prefetcher from Access stream")
+ prefetcher_size = Param.Int(100,
+ "Number of entries in the harware prefetch queue")
+ prefetch_past_page = Param.Bool(False,
+ "Allow prefetches to cross virtual page boundaries")
+ prefetch_serial_squash = Param.Bool(False,
+ "Squash prefetches with a later time on a subsequent miss")
+ prefetch_degree = Param.Int(1,
+ "Degree of the prefetch depth")
+ prefetch_latency = Param.Tick(10,
+ "Latency of the prefetcher")
+ prefetch_policy = Param.Prefetch('none',
+ "Type of prefetcher to use")
+ prefetch_cache_check_push = Param.Bool(True,
+ "Check if in cash on push or pop of prefetch queue")
+ prefetch_use_cpu_id = Param.Bool(True,
+ "Use the CPU ID to seperate calculations of prefetches")
+ prefetch_data_accesses_only = Param.Bool(False,
+ "Only prefetch on data not on instruction accesses")
diff --git a/src/python/m5/objects/Bridge.py b/src/python/m5/objects/Bridge.py
new file mode 100644
index 000000000..ada715ce9
--- /dev/null
+++ b/src/python/m5/objects/Bridge.py
@@ -0,0 +1,9 @@
+from m5 import *
+from MemObject import MemObject
+
+class Bridge(MemObject):
+ type = 'Bridge'
+ queue_size_a = Param.Int(16, "The number of requests to buffer")
+ queue_size_b = Param.Int(16, "The number of requests to buffer")
+ delay = Param.Latency('0ns', "The latency of this bridge")
+ write_ack = Param.Bool(False, "Should this bridge ack writes")
diff --git a/src/python/m5/objects/Bus.py b/src/python/m5/objects/Bus.py
new file mode 100644
index 000000000..8c5397281
--- /dev/null
+++ b/src/python/m5/objects/Bus.py
@@ -0,0 +1,6 @@
+from m5 import *
+from MemObject import MemObject
+
+class Bus(MemObject):
+ type = 'Bus'
+ bus_id = Param.Int(0, "blah")
diff --git a/src/python/m5/objects/CoherenceProtocol.py b/src/python/m5/objects/CoherenceProtocol.py
new file mode 100644
index 000000000..7013000d6
--- /dev/null
+++ b/src/python/m5/objects/CoherenceProtocol.py
@@ -0,0 +1,7 @@
+from m5 import *
+class Coherence(Enum): vals = ['uni', 'msi', 'mesi', 'mosi', 'moesi']
+
+class CoherenceProtocol(SimObject):
+ type = 'CoherenceProtocol'
+ do_upgrades = Param.Bool(True, "use upgrade transactions?")
+ protocol = Param.Coherence("name of coherence protocol")
diff --git a/src/python/m5/objects/Device.py b/src/python/m5/objects/Device.py
new file mode 100644
index 000000000..2a71bbc65
--- /dev/null
+++ b/src/python/m5/objects/Device.py
@@ -0,0 +1,18 @@
+from m5 import *
+from MemObject import MemObject
+
+class PioDevice(MemObject):
+ type = 'PioDevice'
+ abstract = True
+ platform = Param.Platform(Parent.any, "Platform this device is part of")
+ system = Param.System(Parent.any, "System this device is part of")
+
+class BasicPioDevice(PioDevice):
+ type = 'BasicPioDevice'
+ abstract = True
+ pio_addr = Param.Addr("Device Address")
+ pio_latency = Param.Tick(1, "Programmed IO latency in simticks")
+
+class DmaDevice(PioDevice):
+ type = 'DmaDevice'
+ abstract = True
diff --git a/src/python/m5/objects/DiskImage.py b/src/python/m5/objects/DiskImage.py
new file mode 100644
index 000000000..0d55e9329
--- /dev/null
+++ b/src/python/m5/objects/DiskImage.py
@@ -0,0 +1,15 @@
+from m5 import *
+class DiskImage(SimObject):
+ type = 'DiskImage'
+ abstract = True
+ image_file = Param.String("disk image file")
+ read_only = Param.Bool(False, "read only image")
+
+class RawDiskImage(DiskImage):
+ type = 'RawDiskImage'
+
+class CowDiskImage(DiskImage):
+ type = 'CowDiskImage'
+ child = Param.DiskImage("child image")
+ table_size = Param.Int(65536, "initial table size")
+ image_file = ''
diff --git a/src/python/m5/objects/Ethernet.py b/src/python/m5/objects/Ethernet.py
new file mode 100644
index 000000000..4286c71c8
--- /dev/null
+++ b/src/python/m5/objects/Ethernet.py
@@ -0,0 +1,115 @@
+from m5 import *
+from Device import DmaDevice
+from Pci import PciDevice
+
+class EtherInt(SimObject):
+ type = 'EtherInt'
+ abstract = True
+ peer = Param.EtherInt(NULL, "peer interface")
+
+class EtherLink(SimObject):
+ type = 'EtherLink'
+ int1 = Param.EtherInt("interface 1")
+ int2 = Param.EtherInt("interface 2")
+ delay = Param.Latency('0us', "packet transmit delay")
+ delay_var = Param.Latency('0ns', "packet transmit delay variability")
+ speed = Param.NetworkBandwidth('1Gbps', "link speed")
+ dump = Param.EtherDump(NULL, "dump object")
+
+class EtherBus(SimObject):
+ type = 'EtherBus'
+ loopback = Param.Bool(True, "send packet back to the sending interface")
+ dump = Param.EtherDump(NULL, "dump object")
+ speed = Param.NetworkBandwidth('100Mbps', "bus speed in bits per second")
+
+class EtherTap(EtherInt):
+ type = 'EtherTap'
+ bufsz = Param.Int(10000, "tap buffer size")
+ dump = Param.EtherDump(NULL, "dump object")
+ port = Param.UInt16(3500, "tap port")
+
+class EtherDump(SimObject):
+ type = 'EtherDump'
+ file = Param.String("dump file")
+ maxlen = Param.Int(96, "max portion of packet data to dump")
+
+if build_env['ALPHA_TLASER']:
+
+ class EtherDev(DmaDevice):
+ type = 'EtherDev'
+ hardware_address = Param.EthernetAddr(NextEthernetAddr,
+ "Ethernet Hardware Address")
+
+ dma_data_free = Param.Bool(False, "DMA of Data is free")
+ dma_desc_free = Param.Bool(False, "DMA of Descriptors is free")
+ dma_read_delay = Param.Latency('0us', "fixed delay for dma reads")
+ dma_read_factor = Param.Latency('0us', "multiplier for dma reads")
+ dma_write_delay = Param.Latency('0us', "fixed delay for dma writes")
+ dma_write_factor = Param.Latency('0us', "multiplier for dma writes")
+ dma_no_allocate = Param.Bool(True, "Should we allocate cache on read")
+
+ rx_filter = Param.Bool(True, "Enable Receive Filter")
+ rx_delay = Param.Latency('1us', "Receive Delay")
+ tx_delay = Param.Latency('1us', "Transmit Delay")
+
+ intr_delay = Param.Latency('0us', "Interrupt Delay")
+ payload_bus = Param.Bus(NULL, "The IO Bus to attach to for payload")
+ physmem = Param.PhysicalMemory(Parent.any, "Physical Memory")
+ tlaser = Param.Turbolaser(Parent.any, "Turbolaser")
+
+ class EtherDevInt(EtherInt):
+ type = 'EtherDevInt'
+ device = Param.EtherDev("Ethernet device of this interface")
+
+class EtherDevBase(PciDevice):
+ hardware_address = Param.EthernetAddr(NextEthernetAddr,
+ "Ethernet Hardware Address")
+
+ clock = Param.Clock('0ns', "State machine processor frequency")
+
+ dma_read_delay = Param.Latency('0us', "fixed delay for dma reads")
+ dma_read_factor = Param.Latency('0us', "multiplier for dma reads")
+ dma_write_delay = Param.Latency('0us', "fixed delay for dma writes")
+ dma_write_factor = Param.Latency('0us', "multiplier for dma writes")
+
+ rx_delay = Param.Latency('1us', "Receive Delay")
+ tx_delay = Param.Latency('1us', "Transmit Delay")
+ rx_fifo_size = Param.MemorySize('512kB', "max size of rx fifo")
+ tx_fifo_size = Param.MemorySize('512kB', "max size of tx fifo")
+
+ rx_filter = Param.Bool(True, "Enable Receive Filter")
+ intr_delay = Param.Latency('10us', "Interrupt propagation delay")
+ rx_thread = Param.Bool(False, "dedicated kernel thread for transmit")
+ tx_thread = Param.Bool(False, "dedicated kernel threads for receive")
+ rss = Param.Bool(False, "Receive Side Scaling")
+
+class NSGigE(EtherDevBase):
+ type = 'NSGigE'
+
+ dma_data_free = Param.Bool(False, "DMA of Data is free")
+ dma_desc_free = Param.Bool(False, "DMA of Descriptors is free")
+ dma_no_allocate = Param.Bool(True, "Should we allocate cache on read")
+
+
+class NSGigEInt(EtherInt):
+ type = 'NSGigEInt'
+ device = Param.NSGigE("Ethernet device of this interface")
+
+class Sinic(EtherDevBase):
+ type = 'Sinic'
+
+ rx_max_copy = Param.MemorySize('1514B', "rx max copy")
+ tx_max_copy = Param.MemorySize('16kB', "tx max copy")
+ rx_max_intr = Param.UInt32(10, "max rx packets per interrupt")
+ rx_fifo_threshold = Param.MemorySize('384kB', "rx fifo high threshold")
+ rx_fifo_low_mark = Param.MemorySize('128kB', "rx fifo low threshold")
+ tx_fifo_high_mark = Param.MemorySize('384kB', "tx fifo high threshold")
+ tx_fifo_threshold = Param.MemorySize('128kB', "tx fifo low threshold")
+ virtual_count = Param.UInt32(1, "Virtualized SINIC")
+ zero_copy = Param.Bool(False, "Zero copy receive")
+ delay_copy = Param.Bool(False, "Delayed copy transmit")
+ virtual_addr = Param.Bool(False, "Virtual addressing")
+
+class SinicInt(EtherInt):
+ type = 'SinicInt'
+ device = Param.Sinic("Ethernet device of this interface")
diff --git a/src/python/m5/objects/Ide.py b/src/python/m5/objects/Ide.py
new file mode 100644
index 000000000..2403e6d36
--- /dev/null
+++ b/src/python/m5/objects/Ide.py
@@ -0,0 +1,14 @@
+from m5 import *
+from Pci import PciDevice
+
+class IdeID(Enum): vals = ['master', 'slave']
+
+class IdeDisk(SimObject):
+ type = 'IdeDisk'
+ delay = Param.Latency('1us', "Fixed disk delay in microseconds")
+ driveID = Param.IdeID('master', "Drive ID")
+ image = Param.DiskImage("Disk image")
+
+class IdeController(PciDevice):
+ type = 'IdeController'
+ disks = VectorParam.IdeDisk("IDE disks attached to this controller")
diff --git a/src/python/m5/objects/IntrControl.py b/src/python/m5/objects/IntrControl.py
new file mode 100644
index 000000000..66c82c182
--- /dev/null
+++ b/src/python/m5/objects/IntrControl.py
@@ -0,0 +1,4 @@
+from m5 import *
+class IntrControl(SimObject):
+ type = 'IntrControl'
+ cpu = Param.BaseCPU(Parent.any, "the cpu")
diff --git a/src/python/m5/objects/MemObject.py b/src/python/m5/objects/MemObject.py
new file mode 100644
index 000000000..4d68243e6
--- /dev/null
+++ b/src/python/m5/objects/MemObject.py
@@ -0,0 +1,5 @@
+from m5 import *
+
+class MemObject(SimObject):
+ type = 'MemObject'
+ abstract = True
diff --git a/src/python/m5/objects/MemTest.py b/src/python/m5/objects/MemTest.py
new file mode 100644
index 000000000..34299faf0
--- /dev/null
+++ b/src/python/m5/objects/MemTest.py
@@ -0,0 +1,19 @@
+from m5 import *
+class MemTest(SimObject):
+ type = 'MemTest'
+ cache = Param.BaseCache("L1 cache")
+ check_mem = Param.FunctionalMemory("check memory")
+ main_mem = Param.FunctionalMemory("hierarchical memory")
+ max_loads = Param.Counter("number of loads to execute")
+ memory_size = Param.Int(65536, "memory size")
+ percent_copies = Param.Percent(0, "target copy percentage")
+ percent_dest_unaligned = Param.Percent(50,
+ "percent of copy dest address that are unaligned")
+ percent_reads = Param.Percent(65, "target read percentage")
+ percent_source_unaligned = Param.Percent(50,
+ "percent of copy source address that are unaligned")
+ percent_uncacheable = Param.Percent(10,
+ "target uncacheable percentage")
+ progress_interval = Param.Counter(1000000,
+ "progress report interval (in accesses)")
+ trace_addr = Param.Addr(0, "address to trace")
diff --git a/src/python/m5/objects/Pci.py b/src/python/m5/objects/Pci.py
new file mode 100644
index 000000000..85cefcd44
--- /dev/null
+++ b/src/python/m5/objects/Pci.py
@@ -0,0 +1,55 @@
+from m5 import *
+from Device import BasicPioDevice, DmaDevice
+
+class PciConfigData(SimObject):
+ type = 'PciConfigData'
+ VendorID = Param.UInt16("Vendor ID")
+ DeviceID = Param.UInt16("Device ID")
+ Command = Param.UInt16(0, "Command")
+ Status = Param.UInt16(0, "Status")
+ Revision = Param.UInt8(0, "Device")
+ ProgIF = Param.UInt8(0, "Programming Interface")
+ SubClassCode = Param.UInt8(0, "Sub-Class Code")
+ ClassCode = Param.UInt8(0, "Class Code")
+ CacheLineSize = Param.UInt8(0, "System Cacheline Size")
+ LatencyTimer = Param.UInt8(0, "PCI Latency Timer")
+ HeaderType = Param.UInt8(0, "PCI Header Type")
+ BIST = Param.UInt8(0, "Built In Self Test")
+
+ BAR0 = Param.UInt32(0x00, "Base Address Register 0")
+ BAR1 = Param.UInt32(0x00, "Base Address Register 1")
+ BAR2 = Param.UInt32(0x00, "Base Address Register 2")
+ BAR3 = Param.UInt32(0x00, "Base Address Register 3")
+ BAR4 = Param.UInt32(0x00, "Base Address Register 4")
+ BAR5 = Param.UInt32(0x00, "Base Address Register 5")
+ BAR0Size = Param.MemorySize32('0B', "Base Address Register 0 Size")
+ BAR1Size = Param.MemorySize32('0B', "Base Address Register 1 Size")
+ BAR2Size = Param.MemorySize32('0B', "Base Address Register 2 Size")
+ BAR3Size = Param.MemorySize32('0B', "Base Address Register 3 Size")
+ BAR4Size = Param.MemorySize32('0B', "Base Address Register 4 Size")
+ BAR5Size = Param.MemorySize32('0B', "Base Address Register 5 Size")
+
+ CardbusCIS = Param.UInt32(0x00, "Cardbus Card Information Structure")
+ SubsystemID = Param.UInt16(0x00, "Subsystem ID")
+ SubsystemVendorID = Param.UInt16(0x00, "Subsystem Vendor ID")
+ ExpansionROM = Param.UInt32(0x00, "Expansion ROM Base Address")
+ InterruptLine = Param.UInt8(0x00, "Interrupt Line")
+ InterruptPin = Param.UInt8(0x00, "Interrupt Pin")
+ MaximumLatency = Param.UInt8(0x00, "Maximum Latency")
+ MinimumGrant = Param.UInt8(0x00, "Minimum Grant")
+
+class PciConfigAll(BasicPioDevice):
+ type = 'PciConfigAll'
+
+class PciDevice(DmaDevice):
+ type = 'PciDevice'
+ abstract = True
+ pci_bus = Param.Int("PCI bus")
+ pci_dev = Param.Int("PCI device number")
+ pci_func = Param.Int("PCI function code")
+ pio_latency = Param.Tick(1, "Programmed IO latency in simticks")
+ configdata = Param.PciConfigData(Parent.any, "PCI Config data")
+ configspace = Param.PciConfigAll(Parent.any, "PCI Configspace")
+
+class PciFake(PciDevice):
+ type = 'PciFake'
diff --git a/src/python/m5/objects/PhysicalMemory.py b/src/python/m5/objects/PhysicalMemory.py
new file mode 100644
index 000000000..c59910093
--- /dev/null
+++ b/src/python/m5/objects/PhysicalMemory.py
@@ -0,0 +1,8 @@
+from m5 import *
+from MemObject import *
+
+class PhysicalMemory(MemObject):
+ type = 'PhysicalMemory'
+ range = Param.AddrRange("Device Address")
+ file = Param.String('', "memory mapped file")
+ latency = Param.Latency(Parent.clock, "latency of an access")
diff --git a/src/python/m5/objects/Platform.py b/src/python/m5/objects/Platform.py
new file mode 100644
index 000000000..4da0ffab4
--- /dev/null
+++ b/src/python/m5/objects/Platform.py
@@ -0,0 +1,5 @@
+from m5 import *
+class Platform(SimObject):
+ type = 'Platform'
+ abstract = True
+ intrctrl = Param.IntrControl(Parent.any, "interrupt controller")
diff --git a/src/python/m5/objects/Process.py b/src/python/m5/objects/Process.py
new file mode 100644
index 000000000..60b00229e
--- /dev/null
+++ b/src/python/m5/objects/Process.py
@@ -0,0 +1,27 @@
+from m5 import *
+class Process(SimObject):
+ type = 'Process'
+ abstract = True
+ output = Param.String('cout', 'filename for stdout/stderr')
+ system = Param.System(Parent.any, "system process will run on")
+
+class LiveProcess(Process):
+ type = 'LiveProcess'
+ executable = Param.String('', "executable (overrides cmd[0] if set)")
+ cmd = VectorParam.String("command line (executable plus arguments)")
+ env = VectorParam.String('', "environment settings")
+ input = Param.String('cin', "filename for stdin")
+
+class AlphaLiveProcess(LiveProcess):
+ type = 'AlphaLiveProcess'
+
+class SparcLiveProcess(LiveProcess):
+ type = 'SparcLiveProcess'
+
+class MipsLiveProcess(LiveProcess):
+ type = 'MipsLiveProcess'
+
+class EioProcess(Process):
+ type = 'EioProcess'
+ chkpt = Param.String('', "EIO checkpoint file name (optional)")
+ file = Param.String("EIO trace file name")
diff --git a/src/python/m5/objects/Repl.py b/src/python/m5/objects/Repl.py
new file mode 100644
index 000000000..afd256082
--- /dev/null
+++ b/src/python/m5/objects/Repl.py
@@ -0,0 +1,10 @@
+from m5 import *
+class Repl(SimObject):
+ type = 'Repl'
+ abstract = True
+
+class GenRepl(Repl):
+ type = 'GenRepl'
+ fresh_res = Param.Int("associativity")
+ num_pools = Param.Int("capacity in bytes")
+ pool_res = Param.Int("block size in bytes")
diff --git a/src/python/m5/objects/Root.py b/src/python/m5/objects/Root.py
new file mode 100644
index 000000000..205a93c76
--- /dev/null
+++ b/src/python/m5/objects/Root.py
@@ -0,0 +1,23 @@
+from m5 import *
+from Serialize import Serialize
+from Statistics import Statistics
+from Trace import Trace
+from ExeTrace import ExecutionTrace
+from Debug import Debug
+
+class Root(SimObject):
+ type = 'Root'
+ clock = Param.RootClock('200MHz', "tick frequency")
+ max_tick = Param.Tick('0', "maximum simulation ticks (0 = infinite)")
+ progress_interval = Param.Tick('0',
+ "print a progress message every n ticks (0 = never)")
+ output_file = Param.String('cout', "file to dump simulator output to")
+ checkpoint = Param.String('', "checkpoint file to load")
+# stats = Param.Statistics(Statistics(), "statistics object")
+# trace = Param.Trace(Trace(), "trace object")
+# serialize = Param.Serialize(Serialize(), "checkpoint generation options")
+ stats = Statistics()
+ trace = Trace()
+ exetrace = ExecutionTrace()
+ serialize = Serialize()
+ debug = Debug()
diff --git a/src/python/m5/objects/SimConsole.py b/src/python/m5/objects/SimConsole.py
new file mode 100644
index 000000000..df3061908
--- /dev/null
+++ b/src/python/m5/objects/SimConsole.py
@@ -0,0 +1,12 @@
+from m5 import *
+class ConsoleListener(SimObject):
+ type = 'ConsoleListener'
+ port = Param.TcpPort(3456, "listen port")
+
+class SimConsole(SimObject):
+ type = 'SimConsole'
+ append_name = Param.Bool(True, "append name() to filename")
+ intr_control = Param.IntrControl(Parent.any, "interrupt controller")
+ listener = Param.ConsoleListener("console listener")
+ number = Param.Int(0, "console number")
+ output = Param.String('console', "file to dump output to")
diff --git a/src/python/m5/objects/SimpleDisk.py b/src/python/m5/objects/SimpleDisk.py
new file mode 100644
index 000000000..e34155ace
--- /dev/null
+++ b/src/python/m5/objects/SimpleDisk.py
@@ -0,0 +1,5 @@
+from m5 import *
+class SimpleDisk(SimObject):
+ type = 'SimpleDisk'
+ disk = Param.DiskImage("Disk Image")
+ system = Param.System(Parent.any, "Sysetm Pointer")
diff --git a/src/python/m5/objects/System.py b/src/python/m5/objects/System.py
new file mode 100644
index 000000000..622b5a870
--- /dev/null
+++ b/src/python/m5/objects/System.py
@@ -0,0 +1,21 @@
+from m5 import *
+
+class System(SimObject):
+ type = 'System'
+ physmem = Param.PhysicalMemory(Parent.any, "phsyical memory")
+ if build_env['FULL_SYSTEM']:
+ boot_cpu_frequency = Param.Frequency(Self.cpu[0].clock.frequency,
+ "boot processor frequency")
+ init_param = Param.UInt64(0, "numerical value to pass into simulator")
+ bin = Param.Bool(False, "is this system binned")
+ binned_fns = VectorParam.String([], "functions broken down and binned")
+ boot_osflags = Param.String("a", "boot flags to pass to the kernel")
+ kernel = Param.String("file that contains the kernel code")
+ readfile = Param.String("", "file to read startup script from")
+
+class AlphaSystem(System):
+ type = 'AlphaSystem'
+ console = Param.String("file that contains the console code")
+ pal = Param.String("file that contains palcode")
+ system_type = Param.UInt64("Type of system we are emulating")
+ system_rev = Param.UInt64("Revision of system we are emulating")
diff --git a/src/python/m5/objects/Tsunami.py b/src/python/m5/objects/Tsunami.py
new file mode 100644
index 000000000..27ea0bce8
--- /dev/null
+++ b/src/python/m5/objects/Tsunami.py
@@ -0,0 +1,27 @@
+from m5 import *
+from Device import BasicPioDevice
+from Platform import Platform
+
+class Tsunami(Platform):
+ type = 'Tsunami'
+# pciconfig = Param.PciConfigAll("PCI configuration")
+ system = Param.System(Parent.any, "system")
+
+class TsunamiCChip(BasicPioDevice):
+ type = 'TsunamiCChip'
+ tsunami = Param.Tsunami(Parent.any, "Tsunami")
+
+class IsaFake(BasicPioDevice):
+ type = 'IsaFake'
+ pio_size = Param.Addr(0x8, "Size of address range")
+
+class TsunamiIO(BasicPioDevice):
+ type = 'TsunamiIO'
+ time = Param.UInt64(1136073600,
+ "System time to use (0 for actual time, default is 1/1/06)")
+ tsunami = Param.Tsunami(Parent.any, "Tsunami")
+ frequency = Param.Frequency('1024Hz', "frequency of interrupts")
+
+class TsunamiPChip(BasicPioDevice):
+ type = 'TsunamiPChip'
+ tsunami = Param.Tsunami(Parent.any, "Tsunami")
diff --git a/src/python/m5/objects/Uart.py b/src/python/m5/objects/Uart.py
new file mode 100644
index 000000000..54754aeb9
--- /dev/null
+++ b/src/python/m5/objects/Uart.py
@@ -0,0 +1,15 @@
+from m5 import *
+from Device import BasicPioDevice
+
+class Uart(BasicPioDevice):
+ type = 'Uart'
+ abstract = True
+ sim_console = Param.SimConsole(Parent.any, "The console")
+
+class Uart8250(Uart):
+ type = 'Uart8250'
+
+if build_env['ALPHA_TLASER']:
+ class Uart8530(Uart):
+ type = 'Uart8530'
+
diff --git a/src/python/m5/smartdict.py b/src/python/m5/smartdict.py
new file mode 100644
index 000000000..cd38d7326
--- /dev/null
+++ b/src/python/m5/smartdict.py
@@ -0,0 +1,152 @@
+# Copyright (c) 2005 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# The SmartDict class fixes a couple of issues with using the content
+# of os.environ or similar dicts of strings as Python variables:
+#
+# 1) Undefined variables should return False rather than raising KeyError.
+#
+# 2) String values of 'False', '0', etc., should evaluate to False
+# (not just the empty string).
+#
+# #1 is solved by overriding __getitem__, and #2 is solved by using a
+# proxy class for values and overriding __nonzero__ on the proxy.
+# Everything else is just to (a) make proxies behave like normal
+# values otherwise, (b) make sure any dict operation returns a proxy
+# rather than a normal value, and (c) coerce values written to the
+# dict to be strings.
+
+
+from convert import *
+
+class Variable(str):
+ """Intelligent proxy class for SmartDict. Variable will use the
+ various convert functions to attempt to convert values to useable
+ types"""
+ def __int__(self):
+ return toInteger(str(self))
+ def __long__(self):
+ return toLong(str(self))
+ def __float__(self):
+ return toFloat(str(self))
+ def __nonzero__(self):
+ return toBool(str(self))
+ def convert(self, other):
+ t = type(other)
+ if t == bool:
+ return bool(self)
+ if t == int:
+ return int(self)
+ if t == long:
+ return long(self)
+ if t == float:
+ return float(self)
+ return str(self)
+ def __lt__(self, other):
+ return self.convert(other) < other
+ def __le__(self, other):
+ return self.convert(other) <= other
+ def __eq__(self, other):
+ return self.convert(other) == other
+ def __ne__(self, other):
+ return self.convert(other) != other
+ def __gt__(self, other):
+ return self.convert(other) > other
+ def __ge__(self, other):
+ return self.convert(other) >= other
+
+ def __add__(self, other):
+ return self.convert(other) + other
+ def __sub__(self, other):
+ return self.convert(other) - other
+ def __mul__(self, other):
+ return self.convert(other) * other
+ def __div__(self, other):
+ return self.convert(other) / other
+ def __truediv__(self, other):
+ return self.convert(other) / other
+
+ def __radd__(self, other):
+ return other + self.convert(other)
+ def __rsub__(self, other):
+ return other - self.convert(other)
+ def __rmul__(self, other):
+ return other * self.convert(other)
+ def __rdiv__(self, other):
+ return other / self.convert(other)
+ def __rtruediv__(self, other):
+ return other / self.convert(other)
+
+class UndefinedVariable(object):
+ """Placeholder class to represent undefined variables. Will
+ generally cause an exception whenever it is used, but evaluates to
+ zero for boolean truth testing such as in an if statement"""
+ def __nonzero__(self):
+ return False
+
+class SmartDict(dict):
+ """Dictionary class that holds strings, but intelligently converts
+ those strings to other types depending on their usage"""
+
+ def __getitem__(self, key):
+ """returns a Variable proxy if the values exists in the database and
+ returns an UndefinedVariable otherwise"""
+
+ if key in self:
+ return Variable(dict.get(self, key))
+ else:
+ # Note that this does *not* change the contents of the dict,
+ # so that even after we call env['foo'] we still get a
+ # meaningful answer from "'foo' in env" (which
+ # calls dict.__contains__, which we do not override).
+ return UndefinedVariable()
+
+ def __setitem__(self, key, item):
+ """intercept the setting of any variable so that we always
+ store strings in the dict"""
+ dict.__setitem__(self, key, str(item))
+
+ def values(self):
+ return [ Variable(v) for v in dict.values(self) ]
+
+ def itervalues(self):
+ for value in dict.itervalues(self):
+ yield Variable(value)
+
+ def items(self):
+ return [ (k, Variable(v)) for k,v in dict.items(self) ]
+
+ def iteritems(self):
+ for key,value in dict.iteritems(self):
+ yield key, Variable(value)
+
+ def get(self, key, default='False'):
+ return Variable(dict.get(self, key, str(default)))
+
+ def setdefault(self, key, default='False'):
+ return Variable(dict.setdefault(self, key, str(default)))
+
+__all__ = [ 'SmartDict' ]
diff --git a/src/sim/async.hh b/src/sim/async.hh
new file mode 100644
index 000000000..e0190a133
--- /dev/null
+++ b/src/sim/async.hh
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ASYNC_HH__
+#define __ASYNC_HH__
+
+///
+/// @file sim/async.hh
+/// This file defines flags used to handle asynchronous simulator events.
+///
+
+/// @name Asynchronous event flags.
+/// To avoid races, signal handlers simply set these flags, which are
+/// then checked in the main event loop. Defined in main.cc.
+/// @note See the PollQueue object (in pollevent.hh) for the use of async_io and async_alarm.
+//@{
+extern volatile bool async_event; ///< Some asynchronous event has happened.
+extern volatile bool async_dump; ///< Async request to dump stats.
+extern volatile bool async_exit; ///< Async request to exit simulator.
+extern volatile bool async_io; ///< Async I/O request (SIGIO).
+extern volatile bool async_alarm; ///< Async alarm event (SIGALRM).
+//@}
+
+#endif // __ASYNC_HH__
diff --git a/src/sim/builder.cc b/src/sim/builder.cc
new file mode 100644
index 000000000..7dc118985
--- /dev/null
+++ b/src/sim/builder.cc
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <assert.h>
+
+#include "base/inifile.hh"
+#include "base/misc.hh"
+#include "sim/builder.hh"
+#include "sim/configfile.hh"
+#include "sim/config_node.hh"
+#include "sim/host.hh"
+#include "sim/sim_object.hh"
+#include "sim/root.hh"
+
+using namespace std;
+
+SimObjectBuilder::SimObjectBuilder(ConfigNode *_configNode)
+ : ParamContext(_configNode->getPath(), NoAutoInit),
+ configNode(_configNode)
+{
+}
+
+SimObjectBuilder::~SimObjectBuilder()
+{
+}
+
+///////////////////////////////////////////
+//
+// SimObjectBuilder member definitions
+//
+///////////////////////////////////////////
+
+// override ParamContext::parseParams() to check params based on
+// instance name first. If not found, then check based on iniSection
+// (as in default ParamContext implementation).
+void
+SimObjectBuilder::parseParams(IniFile &iniFile)
+{
+ iniFilePtr = &iniFile; // set object member
+
+ ParamList::iterator i;
+
+ for (i = paramList->begin(); i != paramList->end(); ++i) {
+ string string_value;
+ if (iniFile.find(iniSection, (*i)->name, string_value))
+ (*i)->parse(string_value);
+ }
+}
+
+
+void
+SimObjectBuilder::printErrorProlog(ostream &os)
+{
+ ccprintf(os, "Error creating object '%s' of type '%s':\n",
+ iniSection, configNode->getType());
+}
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// SimObjectClass member definitions
+//
+////////////////////////////////////////////////////////////////////////
+
+// Map of class names to SimObjectBuilder creation functions. Need to
+// make this a pointer so we can force initialization on the first
+// reference; otherwise, some SimObjectClass constructors may be invoked
+// before the classMap constructor.
+map<string,SimObjectClass::CreateFunc> *SimObjectClass::classMap = NULL;
+
+// SimObjectClass constructor: add mapping to classMap
+SimObjectClass::SimObjectClass(const string &className, CreateFunc createFunc)
+{
+ if (classMap == NULL)
+ classMap = new map<string,SimObjectClass::CreateFunc>();
+
+ if ((*classMap)[className])
+ panic("Error: simulation object class '%s' redefined\n", className);
+
+ // add className --> createFunc to class map
+ (*classMap)[className] = createFunc;
+}
+
+
+//
+//
+SimObject *
+SimObjectClass::createObject(IniFile &configDB, ConfigNode *configNode)
+{
+ const string &type = configNode->getType();
+
+ // look up className to get appropriate createFunc
+ if (classMap->find(type) == classMap->end())
+ panic("Simulator object type '%s' not found.\n", type);
+
+
+ CreateFunc createFunc = (*classMap)[type];
+
+ // call createFunc with config hierarchy node to get object
+ // builder instance (context with parameters for object creation)
+ SimObjectBuilder *objectBuilder = (*createFunc)(configNode);
+
+ assert(objectBuilder != NULL);
+
+ // parse all parameters in context to generate parameter values
+ objectBuilder->parseParams(configDB);
+
+ // now create the actual simulation object
+ SimObject *object = objectBuilder->create();
+
+ assert(object != NULL);
+
+ // echo object parameters to stats file (for documenting the
+ // config used to generate the associated stats)
+ ccprintf(*configStream, "[%s]\n", object->name());
+ ccprintf(*configStream, "type=%s\n", type);
+ objectBuilder->showParams(*configStream);
+ ccprintf(*configStream, "\n");
+
+ // done with the SimObjectBuilder now
+ delete objectBuilder;
+
+ return object;
+}
+
+
+//
+// static method:
+//
+void
+SimObjectClass::describeAllClasses(ostream &os)
+{
+ map<string,CreateFunc>::iterator iter;
+
+ for (iter = classMap->begin(); iter != classMap->end(); ++iter) {
+ const string &className = iter->first;
+ CreateFunc createFunc = iter->second;
+
+ os << "[" << className << "]\n";
+
+ // create dummy object builder just to instantiate parameters
+ SimObjectBuilder *objectBuilder = (*createFunc)(NULL);
+
+ // now get the object builder to describe ite params
+ objectBuilder->describeParams(os);
+
+ os << endl;
+
+ // done with the object builder now
+ delete objectBuilder;
+ }
+}
diff --git a/src/sim/builder.hh b/src/sim/builder.hh
new file mode 100644
index 000000000..b32e00e76
--- /dev/null
+++ b/src/sim/builder.hh
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __BUILDER_HH__
+#define __BUILDER_HH__
+
+#include <iosfwd>
+#include <list>
+#include <map>
+#include <vector>
+
+#include "sim/param.hh"
+
+class SimObject;
+
+//
+// A SimObjectBuilder serves as an evaluation context for a set of
+// parameters that describe a specific instance of a SimObject. This
+// evaluation context corresponds to a section in the .ini file (as
+// with the base ParamContext) plus an optional node in the
+// configuration hierarchy (the configNode member) for resolving
+// SimObject references. SimObjectBuilder is an abstract superclass;
+// derived classes specialize the class for particular subclasses of
+// SimObject (e.g., BaseCache).
+//
+// For typical usage, see the definition of
+// SimObjectClass::createObject().
+//
+class SimObjectBuilder : public ParamContext
+{
+ private:
+ // The corresponding node in the configuration hierarchy.
+ // (optional: may be null if the created object is not in the
+ // hierarchy)
+ ConfigNode *configNode;
+
+ public:
+ SimObjectBuilder(ConfigNode *_configNode);
+
+ virtual ~SimObjectBuilder();
+
+ // call parse() on all params in this context to convert string
+ // representations to parameter values
+ virtual void parseParams(IniFile &iniFile);
+
+ // parameter error prolog (override of ParamContext)
+ virtual void printErrorProlog(std::ostream &);
+
+ // generate the name for this SimObject instance (derived from the
+ // configuration hierarchy node label and position)
+ virtual const std::string &getInstanceName() { return iniSection; }
+
+ // return the configuration hierarchy node for this context.
+ virtual ConfigNode *getConfigNode() { return configNode; }
+
+ // Create the actual SimObject corresponding to the parameter
+ // values in this context. This function is overridden in derived
+ // classes to call a specific constructor for a particular
+ // subclass of SimObject.
+ virtual SimObject *create() = 0;
+};
+
+
+//
+// Handy macros for initializing parameter members of classes derived
+// from SimObjectBuilder. Assumes that the name of the parameter
+// member object is the same as the textual parameter name seen by the
+// user. (Note that '#p' is expanded by the preprocessor to '"p"'.)
+//
+#define INIT_PARAM(p, desc) p(this, #p, desc)
+#define INIT_PARAM_DFLT(p, desc, dflt) p(this, #p, desc, dflt)
+
+//
+// Initialize an enumeration variable... assumes that 'map' is the
+// name of an array of mappings (char * for SimpleEnumParam, or
+// EnumParamMap for MappedEnumParam).
+//
+#define INIT_ENUM_PARAM(p, desc, map) \
+ p(this, #p, desc, map, sizeof(map)/sizeof(map[0]))
+#define INIT_ENUM_PARAM_DFLT(p, desc, map, dflt) \
+ p(this, #p, desc, map, sizeof(map)/sizeof(map[0]), dflt)
+
+//
+// An instance of SimObjectClass corresponds to a class derived from
+// SimObject. The SimObjectClass instance serves to bind the string
+// name (found in the config file) to a function that creates an
+// instance of the appropriate derived class.
+//
+// This would be much cleaner in Smalltalk or Objective-C, where types
+// are first-class objects themselves.
+//
+class SimObjectClass
+{
+ public:
+ // Type CreateFunc is a pointer to a function that creates a new
+ // simulation object builder based on a .ini-file parameter
+ // section (specified by the first string argument), a unique name
+ // for the object (specified by the second string argument), and
+ // an optional config hierarchy node (specified by the third
+ // argument). A pointer to the new SimObjectBuilder is returned.
+ typedef SimObjectBuilder *(*CreateFunc)(ConfigNode *configNode);
+
+ static std::map<std::string,CreateFunc> *classMap;
+
+ // Constructor. For example:
+ //
+ // SimObjectClass baseCacheClass("BaseCache", newBaseCacheBuilder);
+ //
+ SimObjectClass(const std::string &className, CreateFunc createFunc);
+
+ // create SimObject given name of class and pointer to
+ // configuration hierarchy node
+ static SimObject *createObject(IniFile &configDB, ConfigNode *configNode);
+
+ // print descriptions of all parameters registered with all
+ // SimObject classes
+ static void describeAllClasses(std::ostream &os);
+};
+
+//
+// Macros to encapsulate the magic of declaring & defining
+// SimObjectBuilder and SimObjectClass objects
+//
+
+#define BEGIN_DECLARE_SIM_OBJECT_PARAMS(OBJ_CLASS) \
+class OBJ_CLASS##Builder : public SimObjectBuilder \
+{ \
+ public:
+
+#define END_DECLARE_SIM_OBJECT_PARAMS(OBJ_CLASS) \
+ \
+ OBJ_CLASS##Builder(ConfigNode *configNode); \
+ virtual ~OBJ_CLASS##Builder() {} \
+ \
+ OBJ_CLASS *create(); \
+};
+
+#define BEGIN_INIT_SIM_OBJECT_PARAMS(OBJ_CLASS) \
+OBJ_CLASS##Builder::OBJ_CLASS##Builder(ConfigNode *configNode) \
+ : SimObjectBuilder(configNode),
+
+
+#define END_INIT_SIM_OBJECT_PARAMS(OBJ_CLASS) \
+{ \
+}
+
+#define CREATE_SIM_OBJECT(OBJ_CLASS) \
+OBJ_CLASS *OBJ_CLASS##Builder::create()
+
+#define REGISTER_SIM_OBJECT(CLASS_NAME, OBJ_CLASS) \
+SimObjectBuilder * \
+new##OBJ_CLASS##Builder(ConfigNode *configNode) \
+{ \
+ return new OBJ_CLASS##Builder(configNode); \
+} \
+ \
+SimObjectClass the##OBJ_CLASS##Class(CLASS_NAME, \
+ new##OBJ_CLASS##Builder); \
+ \
+/* see param.hh */ \
+DEFINE_SIM_OBJECT_CLASS_NAME(CLASS_NAME, OBJ_CLASS)
+
+
+#endif // __BUILDER_HH__
diff --git a/src/sim/byteswap.hh b/src/sim/byteswap.hh
new file mode 100644
index 000000000..a8c5da9d7
--- /dev/null
+++ b/src/sim/byteswap.hh
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2004 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//The purpose of this file is to provide endainness conversion utility
+//functions. Depending on the endianness of the guest system, either
+//the LittleEndianGuest or BigEndianGuest namespace is used.
+
+#ifndef __SIM_BYTE_SWAP_HH__
+#define __SIM_BYTE_SWAP_HH__
+
+#include "sim/host.hh"
+
+// This lets us figure out what the byte order of the host system is
+#if defined(linux)
+#include <endian.h>
+// If this is a linux system, lets used the optimized definitions if they exist.
+// If one doesn't exist, we pretty much get what is listed below, so it all
+// works out
+#include <byteswap.h>
+#else
+#include <machine/endian.h>
+#endif
+
+//These functions actually perform the swapping for parameters
+//of various bit lengths
+static inline uint64_t
+swap_byte64(uint64_t x)
+{
+#if defined(linux)
+ return bswap_64(x);
+#else
+ return (uint64_t)((((uint64_t)(x) & 0xff) << 56) |
+ ((uint64_t)(x) & 0xff00ULL) << 40 |
+ ((uint64_t)(x) & 0xff0000ULL) << 24 |
+ ((uint64_t)(x) & 0xff000000ULL) << 8 |
+ ((uint64_t)(x) & 0xff00000000ULL) >> 8 |
+ ((uint64_t)(x) & 0xff0000000000ULL) >> 24 |
+ ((uint64_t)(x) & 0xff000000000000ULL) >> 40 |
+ ((uint64_t)(x) & 0xff00000000000000ULL) >> 56) ;
+#endif
+}
+
+static inline uint32_t
+swap_byte32(uint32_t x)
+{
+#if defined(linux)
+ return bswap_32(x);
+#else
+ return (uint32_t)(((uint32_t)(x) & 0xff) << 24 |
+ ((uint32_t)(x) & 0xff00) << 8 | ((uint32_t)(x) & 0xff0000) >> 8 |
+ ((uint32_t)(x) & 0xff000000) >> 24);
+#endif
+}
+
+static inline uint16_t
+swap_byte16(uint16_t x)
+{
+#if defined(linux)
+ return bswap_16(x);
+#else
+ return (uint16_t)(((uint16_t)(x) & 0xff) << 8 |
+ ((uint16_t)(x) & 0xff00) >> 8);
+#endif
+}
+
+//This lets the compiler figure out how to call the swap_byte functions above
+//for different data types.
+static inline uint64_t swap_byte(uint64_t x) {return swap_byte64(x);}
+static inline int64_t swap_byte(int64_t x) {return swap_byte64((uint64_t)x);}
+static inline uint32_t swap_byte(uint32_t x) {return swap_byte32(x);}
+static inline int32_t swap_byte(int32_t x) {return swap_byte32((uint32_t)x);}
+//This is to prevent the following two functions from compiling on
+//64bit machines. It won't detect everything, so it should be changed.
+#ifndef __x86_64__
+static inline long swap_byte(long x) {return swap_byte32((long)x);}
+static inline unsigned long swap_byte(unsigned long x)
+ { return swap_byte32((unsigned long)x);}
+#endif
+static inline uint16_t swap_byte(uint16_t x) {return swap_byte32(x);}
+static inline int16_t swap_byte(int16_t x) {return swap_byte16((uint16_t)x);}
+static inline uint8_t swap_byte(uint8_t x) {return x;}
+static inline int8_t swap_byte(int8_t x) {return x;}
+static inline double swap_byte(double x) {return swap_byte64((uint64_t)x);}
+static inline float swap_byte(float x) {return swap_byte32((uint32_t)x);}
+
+//The conversion functions with fixed endianness on both ends don't need to
+//be in a namespace
+template <typename T> static inline T betole(T value) {return swap_byte(value);}
+template <typename T> static inline T letobe(T value) {return swap_byte(value);}
+
+//For conversions not involving the guest system, we can define the functions
+//conditionally based on the BYTE_ORDER macro and outside of the namespaces
+#if BYTE_ORDER == BIG_ENDIAN
+template <typename T> static inline T htole(T value) {return swap_byte(value);}
+template <typename T> static inline T letoh(T value) {return swap_byte(value);}
+template <typename T> static inline T htobe(T value) {return value;}
+template <typename T> static inline T betoh(T value) {return value;}
+#elif BYTE_ORDER == LITTLE_ENDIAN
+template <typename T> static inline T htole(T value) {return value;}
+template <typename T> static inline T letoh(T value) {return value;}
+template <typename T> static inline T htobe(T value) {return swap_byte(value);}
+template <typename T> static inline T betoh(T value) {return swap_byte(value);}
+#else
+ #error Invalid Endianess
+#endif
+
+namespace BigEndianGuest
+{
+ template <typename T>
+ static inline T gtole(T value) {return betole(value);}
+ template <typename T>
+ static inline T letog(T value) {return letobe(value);}
+ template <typename T>
+ static inline T gtobe(T value) {return value;}
+ template <typename T>
+ static inline T betog(T value) {return value;}
+ template <typename T>
+ static inline T htog(T value) {return htobe(value);}
+ template <typename T>
+ static inline T gtoh(T value) {return betoh(value);}
+}
+
+namespace LittleEndianGuest
+{
+ template <typename T>
+ static inline T gtole(T value) {return value;}
+ template <typename T>
+ static inline T letog(T value) {return value;}
+ template <typename T>
+ static inline T gtobe(T value) {return letobe(value);}
+ template <typename T>
+ static inline T betog(T value) {return betole(value);}
+ template <typename T>
+ static inline T htog(T value) {return htole(value);}
+ template <typename T>
+ static inline T gtoh(T value) {return letoh(value);}
+}
+#endif // __SIM_BYTE_SWAP_HH__
diff --git a/src/sim/debug.cc b/src/sim/debug.cc
new file mode 100644
index 000000000..09e5346a8
--- /dev/null
+++ b/src/sim/debug.cc
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+#include "sim/debug.hh"
+#include "sim/eventq.hh"
+#include "sim/param.hh"
+#include "sim/sim_events.hh"
+
+using namespace std;
+
+void
+debug_break()
+{
+#ifndef NDEBUG
+ kill(getpid(), SIGTRAP);
+#else
+ cprintf("debug_break suppressed, compiled with NDEBUG\n");
+#endif
+}
+
+//
+// Debug event: place a breakpoint on the process function and
+// schedule the event to break at a particular cycle
+//
+class DebugBreakEvent : public Event
+{
+ public:
+
+ DebugBreakEvent(EventQueue *q, Tick _when);
+
+ void process(); // process event
+ virtual const char *description();
+};
+
+//
+// constructor: schedule at specified time
+//
+DebugBreakEvent::DebugBreakEvent(EventQueue *q, Tick _when)
+ : Event(q, Debug_Break_Pri)
+{
+ setFlags(AutoDelete);
+ schedule(_when);
+}
+
+//
+// handle debug event: set debugger breakpoint on this function
+//
+void
+DebugBreakEvent::process()
+{
+ debug_break();
+}
+
+
+const char *
+DebugBreakEvent::description()
+{
+ return "debug break";
+}
+
+//
+// Parameter context for global debug options
+//
+class DebugContext : public ParamContext
+{
+ public:
+ DebugContext(const string &_iniSection)
+ : ParamContext(_iniSection) {}
+ void checkParams();
+};
+
+DebugContext debugParams("debug");
+
+VectorParam<Tick> break_cycles(&debugParams, "break_cycles",
+ "cycle(s) to create breakpoint events");
+
+void
+DebugContext::checkParams()
+{
+ if (break_cycles.isValid()) {
+ vector<Tick> &cycles = break_cycles;
+
+ vector<Tick>::iterator i = cycles.begin();
+ vector<Tick>::iterator end = cycles.end();
+
+ for (; i < end; ++i)
+ new DebugBreakEvent(&mainEventQueue, *i);
+ }
+}
+
+//
+// handy function to schedule DebugBreakEvent on main event queue
+// (callable from debugger)
+//
+extern "C" void sched_break_cycle(Tick when)
+{
+ new DebugBreakEvent(&mainEventQueue, when);
+}
+
+extern "C" void eventq_dump()
+{
+ mainEventQueue.dump();
+}
+
diff --git a/src/sim/debug.hh b/src/sim/debug.hh
new file mode 100644
index 000000000..75b261d80
--- /dev/null
+++ b/src/sim/debug.hh
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __DEBUG_HH__
+#define __DEBUG_HH__
+
+void debug_break();
+
+#endif // __DEBUG_HH__
diff --git a/src/sim/eventq.cc b/src/sim/eventq.cc
new file mode 100644
index 000000000..4bfd6face
--- /dev/null
+++ b/src/sim/eventq.cc
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2000-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <assert.h>
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include "cpu/smt.hh"
+#include "base/misc.hh"
+
+#include "sim/eventq.hh"
+#include "base/trace.hh"
+#include "sim/root.hh"
+
+using namespace std;
+
+//
+// Main Event Queue
+//
+// Events on this queue are processed at the *beginning* of each
+// cycle, before the pipeline simulation is performed.
+//
+EventQueue mainEventQueue("MainEventQueue");
+
+void
+EventQueue::insert(Event *event)
+{
+ if (head == NULL || event->when() < head->when() ||
+ (event->when() == head->when() &&
+ event->priority() <= head->priority())) {
+ event->next = head;
+ head = event;
+ } else {
+ Event *prev = head;
+ Event *curr = head->next;
+
+ while (curr) {
+ if (event->when() <= curr->when() &&
+ (event->when() < curr->when() ||
+ event->priority() <= curr->priority()))
+ break;
+
+ prev = curr;
+ curr = curr->next;
+ }
+
+ event->next = curr;
+ prev->next = event;
+ }
+}
+
+void
+EventQueue::remove(Event *event)
+{
+ if (head == NULL)
+ return;
+
+ if (head == event){
+ head = event->next;
+ return;
+ }
+
+ Event *prev = head;
+ Event *curr = head->next;
+ while (curr && curr != event) {
+ prev = curr;
+ curr = curr->next;
+ }
+
+ if (curr == event)
+ prev->next = curr->next;
+}
+
+void
+EventQueue::serviceOne()
+{
+ Event *event = head;
+ event->clearFlags(Event::Scheduled);
+ head = event->next;
+
+ // handle action
+ if (!event->squashed())
+ event->process();
+ else
+ event->clearFlags(Event::Squashed);
+
+ if (event->getFlags(Event::AutoDelete) && !event->scheduled())
+ delete event;
+}
+
+
+void
+Event::serialize(std::ostream &os)
+{
+ SERIALIZE_SCALAR(_when);
+ SERIALIZE_SCALAR(_priority);
+ SERIALIZE_ENUM(_flags);
+}
+
+
+void
+Event::unserialize(Checkpoint *cp, const string &section)
+{
+ if (scheduled())
+ deschedule();
+
+ UNSERIALIZE_SCALAR(_when);
+ UNSERIALIZE_SCALAR(_priority);
+
+ // need to see if original event was in a scheduled, unsquashed
+ // state, but don't want to restore those flags in the current
+ // object itself (since they aren't immediately true)
+ UNSERIALIZE_ENUM(_flags);
+ bool wasScheduled = (_flags & Scheduled) && !(_flags & Squashed);
+ _flags &= ~(Squashed | Scheduled);
+
+ if (wasScheduled) {
+ DPRINTF(Config, "rescheduling at %d\n", _when);
+ schedule(_when);
+ }
+}
+
+void
+EventQueue::serialize(ostream &os)
+{
+ std::list<Event *> eventPtrs;
+
+ int numEvents = 0;
+ Event *event = head;
+ while (event) {
+ if (event->getFlags(Event::AutoSerialize)) {
+ eventPtrs.push_back(event);
+ paramOut(os, csprintf("event%d", numEvents++), event->name());
+ }
+ event = event->next;
+ }
+
+ SERIALIZE_SCALAR(numEvents);
+
+ for (std::list<Event *>::iterator it=eventPtrs.begin();
+ it != eventPtrs.end(); ++it) {
+ (*it)->nameOut(os);
+ (*it)->serialize(os);
+ }
+}
+
+void
+EventQueue::unserialize(Checkpoint *cp, const std::string &section)
+{
+ int numEvents;
+ UNSERIALIZE_SCALAR(numEvents);
+
+ std::string eventName;
+ for (int i = 0; i < numEvents; i++) {
+ // get the pointer value associated with the event
+ paramIn(cp, section, csprintf("event%d", i), eventName);
+
+ // create the event based on its pointer value
+ Serializable::create(cp, eventName);
+ }
+}
+
+void
+EventQueue::dump()
+{
+ cprintf("============================================================\n");
+ cprintf("EventQueue Dump (cycle %d)\n", curTick);
+ cprintf("------------------------------------------------------------\n");
+
+ if (empty())
+ cprintf("<No Events>\n");
+ else {
+ Event *event = head;
+ while (event) {
+ event->dump();
+ event = event->next;
+ }
+ }
+
+ cprintf("============================================================\n");
+}
+
+extern "C"
+void
+dumpMainQueue()
+{
+ mainEventQueue.dump();
+}
+
+
+const char *
+Event::description()
+{
+ return "generic";
+}
+
+#if TRACING_ON
+void
+Event::trace(const char *action)
+{
+ // This DPRINTF is unconditional because calls to this function
+ // are protected by an 'if (DTRACE(Event))' in the inlined Event
+ // methods.
+ //
+ // This is just a default implementation for derived classes where
+ // it's not worth doing anything special. If you want to put a
+ // more informative message in the trace, override this method on
+ // the particular subclass where you have the information that
+ // needs to be printed.
+ DPRINTFN("%s event %s @ %d\n", description(), action, when());
+}
+#endif
+
+void
+Event::dump()
+{
+ cprintf("Event (%s)\n", description());
+ cprintf("Flags: %#x\n", _flags);
+#if TRACING_ON
+ cprintf("Created: %d\n", when_created);
+#endif
+ if (scheduled()) {
+#if TRACING_ON
+ cprintf("Scheduled at %d\n", when_scheduled);
+#endif
+ cprintf("Scheduled for %d, priority %d\n", when(), _priority);
+ }
+ else {
+ cprintf("Not Scheduled\n");
+ }
+}
diff --git a/src/sim/eventq.hh b/src/sim/eventq.hh
new file mode 100644
index 000000000..5fc73bb53
--- /dev/null
+++ b/src/sim/eventq.hh
@@ -0,0 +1,407 @@
+/*
+ * Copyright (c) 2000-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* @file
+ * EventQueue interfaces
+ */
+
+#ifndef __SIM_EVENTQ_HH__
+#define __SIM_EVENTQ_HH__
+
+#include <assert.h>
+
+#include <algorithm>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "sim/host.hh" // for Tick
+
+#include "base/fast_alloc.hh"
+#include "base/trace.hh"
+#include "sim/serialize.hh"
+
+class EventQueue; // forward declaration
+
+//////////////////////
+//
+// Main Event Queue
+//
+// Events on this queue are processed at the *beginning* of each
+// cycle, before the pipeline simulation is performed.
+//
+// defined in eventq.cc
+//
+//////////////////////
+extern EventQueue mainEventQueue;
+
+
+/*
+ * An item on an event queue. The action caused by a given
+ * event is specified by deriving a subclass and overriding the
+ * process() member function.
+ */
+class Event : public Serializable, public FastAlloc
+{
+ friend class EventQueue;
+
+ private:
+ /// queue to which this event belongs (though it may or may not be
+ /// scheduled on this queue yet)
+ EventQueue *queue;
+
+ Event *next;
+
+ Tick _when; //!< timestamp when event should be processed
+ int _priority; //!< event priority
+ char _flags;
+
+ protected:
+ enum Flags {
+ None = 0x0,
+ Squashed = 0x1,
+ Scheduled = 0x2,
+ AutoDelete = 0x4,
+ AutoSerialize = 0x8
+ };
+
+ bool getFlags(Flags f) const { return (_flags & f) == f; }
+ void setFlags(Flags f) { _flags |= f; }
+ void clearFlags(Flags f) { _flags &= ~f; }
+
+ protected:
+ EventQueue *theQueue() const { return queue; }
+
+#if TRACING_ON
+ Tick when_created; //!< Keep track of creation time For debugging
+ Tick when_scheduled; //!< Keep track of creation time For debugging
+
+ virtual void trace(const char *action); //!< trace event activity
+#else
+ void trace(const char *) {}
+#endif
+
+ unsigned annotated_value;
+
+ public:
+
+ /// Event priorities, to provide tie-breakers for events scheduled
+ /// at the same cycle. Most events are scheduled at the default
+ /// priority; these values are used to control events that need to
+ /// be ordered within a cycle.
+ enum Priority {
+ /// Breakpoints should happen before anything else, so we
+ /// don't miss any action when debugging.
+ Debug_Break_Pri = -100,
+
+ /// For some reason "delayed" inter-cluster writebacks are
+ /// scheduled before regular writebacks (which have default
+ /// priority). Steve?
+ Delayed_Writeback_Pri = -1,
+
+ /// Default is zero for historical reasons.
+ Default_Pri = 0,
+
+ /// CPU switches schedule the new CPU's tick event for the
+ /// same cycle (after unscheduling the old CPU's tick event).
+ /// The switch needs to come before any tick events to make
+ /// sure we don't tick both CPUs in the same cycle.
+ CPU_Switch_Pri = 31,
+
+ /// Serailization needs to occur before tick events also, so
+ /// that a serialize/unserialize is identical to an on-line
+ /// CPU switch.
+ Serialize_Pri = 32,
+
+ /// CPU ticks must come after other associated CPU events
+ /// (such as writebacks).
+ CPU_Tick_Pri = 50,
+
+ /// Statistics events (dump, reset, etc.) come after
+ /// everything else, but before exit.
+ Stat_Event_Pri = 90,
+
+ /// If we want to exit on this cycle, it's the very last thing
+ /// we do.
+ Sim_Exit_Pri = 100
+ };
+
+ /*
+ * Event constructor
+ * @param queue that the event gets scheduled on
+ */
+ Event(EventQueue *q, Priority p = Default_Pri)
+ : queue(q), next(NULL), _priority(p), _flags(None),
+#if TRACING_ON
+ when_created(curTick), when_scheduled(0),
+#endif
+ annotated_value(0)
+ {
+ }
+
+ ~Event() {}
+
+ virtual const std::string name() const {
+ return csprintf("Event_%x", (uintptr_t)this);
+ }
+
+ /// Determine if the current event is scheduled
+ bool scheduled() const { return getFlags(Scheduled); }
+
+ /// Schedule the event with the current priority or default priority
+ void schedule(Tick t);
+
+ /// Reschedule the event with the current priority
+ void reschedule(Tick t);
+
+ /// Remove the event from the current schedule
+ void deschedule();
+
+ /// Return a C string describing the event. This string should
+ /// *not* be dynamically allocated; just a const char array
+ /// describing the event class.
+ virtual const char *description();
+
+ /// Dump the current event data
+ void dump();
+
+ /*
+ * This member function is invoked when the event is processed
+ * (occurs). There is no default implementation; each subclass
+ * must provide its own implementation. The event is not
+ * automatically deleted after it is processed (to allow for
+ * statically allocated event objects).
+ *
+ * If the AutoDestroy flag is set, the object is deleted once it
+ * is processed.
+ */
+ virtual void process() = 0;
+
+ void annotate(unsigned value) { annotated_value = value; };
+ unsigned annotation() { return annotated_value; }
+
+ /// Squash the current event
+ void squash() { setFlags(Squashed); }
+
+ /// Check whether the event is squashed
+ bool squashed() { return getFlags(Squashed); }
+
+ /// Get the time that the event is scheduled
+ Tick when() const { return _when; }
+
+ /// Get the event priority
+ int priority() const { return _priority; }
+
+ struct priority_compare :
+ public std::binary_function<Event *, Event *, bool>
+ {
+ bool operator()(const Event *l, const Event *r) const {
+ return l->when() >= r->when() || l->priority() >= r->priority();
+ }
+ };
+
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+};
+
+template <class T, void (T::* F)()>
+void
+DelayFunction(Tick when, T *object)
+{
+ class DelayEvent : public Event
+ {
+ private:
+ T *object;
+
+ public:
+ DelayEvent(Tick when, T *o)
+ : Event(&mainEventQueue), object(o)
+ { setFlags(this->AutoDestroy); schedule(when); }
+ void process() { (object->*F)(); }
+ const char *description() { return "delay"; }
+ };
+
+ new DelayEvent(when, object);
+}
+
+template <class T, void (T::* F)()>
+class EventWrapper : public Event
+{
+ private:
+ T *object;
+
+ public:
+ EventWrapper(T *obj, bool del = false, EventQueue *q = &mainEventQueue,
+ Priority p = Default_Pri)
+ : Event(q, p), object(obj)
+ {
+ if (del)
+ setFlags(AutoDelete);
+ }
+ void process() { (object->*F)(); }
+};
+
+/*
+ * Queue of events sorted in time order
+ */
+class EventQueue : public Serializable
+{
+ protected:
+ std::string objName;
+
+ private:
+ Event *head;
+
+ void insert(Event *event);
+ void remove(Event *event);
+
+ public:
+
+ // constructor
+ EventQueue(const std::string &n)
+ : objName(n), head(NULL)
+ {}
+
+ virtual const std::string name() const { return objName; }
+
+ // schedule the given event on this queue
+ void schedule(Event *ev);
+ void deschedule(Event *ev);
+ void reschedule(Event *ev);
+
+ Tick nextTick() { return head->when(); }
+ void serviceOne();
+
+ // process all events up to the given timestamp. we inline a
+ // quick test to see if there are any events to process; if so,
+ // call the internal out-of-line version to process them all.
+ void serviceEvents(Tick when) {
+ while (!empty()) {
+ if (nextTick() > when)
+ break;
+
+ /**
+ * @todo this assert is a good bug catcher. I need to
+ * make it true again.
+ */
+ //assert(head->when() >= when && "event scheduled in the past");
+ serviceOne();
+ }
+ }
+
+ // default: process all events up to 'now' (curTick)
+ void serviceEvents() { serviceEvents(curTick); }
+
+ // return true if no events are queued
+ bool empty() { return head == NULL; }
+
+ void dump();
+
+ Tick nextEventTime() { return empty() ? curTick : head->when(); }
+
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+};
+
+
+//////////////////////
+//
+// inline functions
+//
+// can't put these inside declaration due to circular dependence
+// between Event and EventQueue classes.
+//
+//////////////////////
+
+// schedule at specified time (place on event queue specified via
+// constructor)
+inline void
+Event::schedule(Tick t)
+{
+ assert(!scheduled());
+ assert(t >= curTick);
+
+ setFlags(Scheduled);
+#if TRACING_ON
+ when_scheduled = curTick;
+#endif
+ _when = t;
+ queue->schedule(this);
+}
+
+inline void
+Event::deschedule()
+{
+ assert(scheduled());
+
+ clearFlags(Squashed);
+ clearFlags(Scheduled);
+ queue->deschedule(this);
+}
+
+inline void
+Event::reschedule(Tick t)
+{
+ assert(scheduled());
+ clearFlags(Squashed);
+
+#if TRACING_ON
+ when_scheduled = curTick;
+#endif
+ _when = t;
+ queue->reschedule(this);
+}
+
+inline void
+EventQueue::schedule(Event *event)
+{
+ insert(event);
+ if (DTRACE(Event))
+ event->trace("scheduled");
+}
+
+inline void
+EventQueue::deschedule(Event *event)
+{
+ remove(event);
+ if (DTRACE(Event))
+ event->trace("descheduled");
+}
+
+inline void
+EventQueue::reschedule(Event *event)
+{
+ remove(event);
+ insert(event);
+ if (DTRACE(Event))
+ event->trace("rescheduled");
+}
+
+
+
+#endif // __SIM_EVENTQ_HH__
diff --git a/src/sim/faults.cc b/src/sim/faults.cc
new file mode 100644
index 000000000..cb095f852
--- /dev/null
+++ b/src/sim/faults.cc
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "base/misc.hh"
+#include "sim/faults.hh"
+#include "cpu/exec_context.hh"
+#include "cpu/base.hh"
+
+#if !FULL_SYSTEM
+void FaultBase::invoke(ExecContext * xc)
+{
+ fatal("fault (%s) detected @ PC 0x%08p", name(), xc->readPC());
+}
+#else
+void FaultBase::invoke(ExecContext * xc)
+{
+ DPRINTF(Fault, "Fault %s at PC: %#x\n", name(), xc->readPC());
+ xc->getCpuPtr()->recordEvent(csprintf("Fault %s", name()));
+
+ assert(!xc->misspeculating());
+}
+#endif
+
+void UnimpFault::invoke(ExecContext * xc)
+{
+ panic("Unimpfault: %s\n", panicStr.c_str());
+}
diff --git a/src/sim/faults.hh b/src/sim/faults.hh
new file mode 100644
index 000000000..9b3bc9103
--- /dev/null
+++ b/src/sim/faults.hh
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __FAULTS_HH__
+#define __FAULTS_HH__
+
+#include "base/refcnt.hh"
+#include "sim/stats.hh"
+#include "config/full_system.hh"
+
+class ExecContext;
+class FaultBase;
+typedef RefCountingPtr<FaultBase> Fault;
+
+typedef const char * FaultName;
+typedef Stats::Scalar<> FaultStat;
+
+// Each class has it's name statically define in _name,
+// and has a virtual function to access it's name.
+// The function is necessary because otherwise, all objects
+// which are being accessed cast as a FaultBase * (namely
+// all faults returned using the Fault type) will use the
+// generic FaultBase name.
+
+class FaultBase : public RefCounted
+{
+ public:
+ virtual FaultName name() = 0;
+#if FULL_SYSTEM
+ virtual void invoke(ExecContext * xc);
+#else
+ virtual void invoke(ExecContext * xc);
+#endif
+// template<typename T>
+// bool isA() {return dynamic_cast<T *>(this);}
+ virtual bool isMachineCheckFault() {return false;}
+ virtual bool isAlignmentFault() {return false;}
+};
+
+FaultBase * const NoFault = 0;
+
+class UnimpFault : public FaultBase
+{
+ private:
+ std::string panicStr;
+ public:
+ UnimpFault(std::string _str)
+ : panicStr(_str)
+ { }
+
+ FaultName name() {return "Unimplemented simulator feature";}
+ void invoke(ExecContext * xc);
+};
+
+#endif // __FAULTS_HH__
diff --git a/src/sim/host.hh b/src/sim/host.hh
new file mode 100644
index 000000000..48c977331
--- /dev/null
+++ b/src/sim/host.hh
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * Defines host-dependent types:
+ * Counter, Tick, and (indirectly) {int,uint}{8,16,32,64}_t.
+ */
+
+#ifndef __HOST_HH__
+#define __HOST_HH__
+
+#include <inttypes.h>
+
+/** uint64_t constant */
+#define ULL(N) ((uint64_t)N##ULL)
+/** int64_t constant */
+#define LL(N) (((int64_t)N##LL)
+
+/** Statistics counter type. Not much excuse for not using a 64-bit
+ * integer here, but if you're desperate and only run short
+ * simulations you could make this 32 bits.
+ */
+typedef int64_t Counter;
+
+/**
+ * Clock cycle count type.
+ * @note using an unsigned breaks the cache.
+ */
+typedef int64_t Tick;
+
+/**
+ * Address type
+ * This will probably be moved somewhere else in the near future.
+ * This should be at least as big as the biggest address width in use
+ * in the system, which will probably be 64 bits.
+ */
+typedef uint64_t Addr;
+
+const Addr MaxAddr = (Addr)-1;
+
+#endif // __HOST_H__
diff --git a/src/sim/main.cc b/src/sim/main.cc
new file mode 100644
index 000000000..aecc171ed
--- /dev/null
+++ b/src/sim/main.cc
@@ -0,0 +1,433 @@
+/*
+ * Copyright (c) 2000-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+///
+/// @file sim/main.cc
+///
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <libgen.h>
+#include <stdlib.h>
+#include <signal.h>
+
+#include <list>
+#include <string>
+#include <vector>
+
+#include "base/copyright.hh"
+#include "base/embedfile.hh"
+#include "base/inifile.hh"
+#include "base/misc.hh"
+#include "base/output.hh"
+#include "base/pollevent.hh"
+#include "base/statistics.hh"
+#include "base/str.hh"
+#include "base/time.hh"
+#include "cpu/base.hh"
+#include "cpu/smt.hh"
+#include "python/pyconfig.hh"
+#include "sim/async.hh"
+#include "sim/builder.hh"
+#include "sim/configfile.hh"
+#include "sim/host.hh"
+#include "sim/sim_events.hh"
+#include "sim/sim_exit.hh"
+#include "sim/sim_object.hh"
+#include "sim/stat_control.hh"
+#include "sim/stats.hh"
+#include "sim/root.hh"
+
+using namespace std;
+
+// See async.h.
+volatile bool async_event = false;
+volatile bool async_dump = false;
+volatile bool async_dumpreset = false;
+volatile bool async_exit = false;
+volatile bool async_io = false;
+volatile bool async_alarm = false;
+
+/// Stats signal handler.
+void
+dumpStatsHandler(int sigtype)
+{
+ async_event = true;
+ async_dump = true;
+}
+
+void
+dumprstStatsHandler(int sigtype)
+{
+ async_event = true;
+ async_dumpreset = true;
+}
+
+/// Exit signal handler.
+void
+exitNowHandler(int sigtype)
+{
+ async_event = true;
+ async_exit = true;
+}
+
+/// Abort signal handler.
+void
+abortHandler(int sigtype)
+{
+ cerr << "Program aborted at cycle " << curTick << endl;
+
+#if TRACING_ON
+ // dump trace buffer, if there is one
+ Trace::theLog.dump(cerr);
+#endif
+}
+
+/// Simulator executable name
+char *myProgName = "";
+
+/// Show brief help message.
+void
+showBriefHelp(ostream &out)
+{
+ char *prog = basename(myProgName);
+
+ ccprintf(out, "Usage:\n");
+ ccprintf(out,
+"%s [-d <dir>] [-E <var>[=<val>]] [-I <dir>] [-P <python>]\n"
+" [--<var>=<val>] <config file>\n"
+"\n"
+" -d set the output directory to <dir>\n"
+" -E set the environment variable <var> to <val> (or 'True')\n"
+" -I add the directory <dir> to python's path\n"
+" -P execute <python> directly in the configuration\n"
+" --var=val set the python variable <var> to '<val>'\n"
+" <configfile> config file name (ends in .py)\n\n",
+ prog);
+
+ ccprintf(out, "%s -X\n -X extract embedded files\n\n", prog);
+ ccprintf(out, "%s -h\n -h print short help\n\n", prog);
+}
+
+/// Print welcome message.
+void
+sayHello(ostream &out)
+{
+ extern const char *compileDate; // from date.cc
+
+ ccprintf(out, "M5 Simulator System\n");
+ // display copyright
+ ccprintf(out, "%s\n", briefCopyright);
+ ccprintf(out, "M5 compiled on %d\n", compileDate);
+
+ char *host = getenv("HOSTNAME");
+ if (!host)
+ host = getenv("HOST");
+
+ if (host)
+ ccprintf(out, "M5 executing on %s\n", host);
+
+ ccprintf(out, "M5 simulation started %s\n", Time::start);
+}
+
+///
+/// Echo the command line for posterity in such a way that it can be
+/// used to rerun the same simulation (given the same .ini files).
+///
+void
+echoCommandLine(int argc, char **argv, ostream &out)
+{
+ out << "command line: " << argv[0];
+ for (int i = 1; i < argc; i++) {
+ string arg(argv[i]);
+
+ out << ' ';
+
+ // If the arg contains spaces, we need to quote it.
+ // The rest of this is overkill to make it look purty.
+
+ // print dashes first outside quotes
+ int non_dash_pos = arg.find_first_not_of("-");
+ out << arg.substr(0, non_dash_pos); // print dashes
+ string body = arg.substr(non_dash_pos); // the rest
+
+ // if it's an assignment, handle the lhs & rhs separately
+ int eq_pos = body.find("=");
+ if (eq_pos == string::npos) {
+ out << quote(body);
+ }
+ else {
+ string lhs(body.substr(0, eq_pos));
+ string rhs(body.substr(eq_pos + 1));
+
+ out << quote(lhs) << "=" << quote(rhs);
+ }
+ }
+ out << endl << endl;
+}
+
+char *
+getOptionString(int &index, int argc, char **argv)
+{
+ char *option = argv[index] + 2;
+ if (*option != '\0')
+ return option;
+
+ // We didn't find an argument, it must be in the next variable.
+ if (++index >= argc)
+ panic("option string for option '%s' not found", argv[index - 1]);
+
+ return argv[index];
+}
+
+int
+main(int argc, char **argv)
+{
+ // Save off program name
+ myProgName = argv[0];
+
+ signal(SIGFPE, SIG_IGN); // may occur on misspeculated paths
+ signal(SIGTRAP, SIG_IGN);
+ signal(SIGUSR1, dumpStatsHandler); // dump intermediate stats
+ signal(SIGUSR2, dumprstStatsHandler); // dump and reset stats
+ signal(SIGINT, exitNowHandler); // dump final stats and exit
+ signal(SIGABRT, abortHandler);
+
+ bool configfile_found = false;
+ PythonConfig pyconfig;
+ string outdir;
+
+ if (argc < 2) {
+ showBriefHelp(cerr);
+ exit(1);
+ }
+
+ sayHello(cerr);
+
+ // Parse command-line options.
+ // Since most of the complex options are handled through the
+ // config database, we don't mess with getopts, and just parse
+ // manually.
+ for (int i = 1; i < argc; ++i) {
+ char *arg_str = argv[i];
+
+ // if arg starts with '--', parse as a special python option
+ // of the format --<python var>=<string value>, if the arg
+ // starts with '-', it should be a simulator option with a
+ // format similar to getopt. In any other case, treat the
+ // option as a configuration file name and load it.
+ if (arg_str[0] == '-' && arg_str[1] == '-') {
+ string str = &arg_str[2];
+ string var, val;
+
+ if (!split_first(str, var, val, '='))
+ panic("Could not parse configuration argument '%s'\n"
+ "Expecting --<variable>=<value>\n", arg_str);
+
+ pyconfig.setVariable(var, val);
+ } else if (arg_str[0] == '-') {
+ char *option;
+ string var, val;
+
+ // switch on second char
+ switch (arg_str[1]) {
+ case 'd':
+ outdir = getOptionString(i, argc, argv);
+ break;
+
+ case 'h':
+ showBriefHelp(cerr);
+ exit(1);
+
+ case 'E':
+ option = getOptionString(i, argc, argv);
+ if (!split_first(option, var, val, '='))
+ val = "True";
+
+ if (setenv(var.c_str(), val.c_str(), true) == -1)
+ panic("setenv: %s\n", strerror(errno));
+ break;
+
+ case 'I':
+ option = getOptionString(i, argc, argv);
+ pyconfig.addPath(option);
+ break;
+
+ case 'P':
+ option = getOptionString(i, argc, argv);
+ pyconfig.writeLine(option);
+ break;
+
+ case 'X': {
+ list<EmbedFile> lst;
+ EmbedMap::all(lst);
+ list<EmbedFile>::iterator i = lst.begin();
+ list<EmbedFile>::iterator end = lst.end();
+
+ while (i != end) {
+ cprintf("Embedded File: %s\n", i->name);
+ cout.write(i->data, i->length);
+ ++i;
+ }
+
+ return 0;
+ }
+
+ default:
+ showBriefHelp(cerr);
+ panic("invalid argument '%s'\n", arg_str);
+ }
+ } else {
+ string file(arg_str);
+ string base, ext;
+
+ if (!split_last(file, base, ext, '.') || ext != "py")
+ panic("Config file '%s' must end in '.py'\n", file);
+
+ pyconfig.load(file);
+ configfile_found = true;
+ }
+ }
+
+ if (outdir.empty()) {
+ char *env = getenv("OUTPUT_DIR");
+ outdir = env ? env : ".";
+ }
+
+ simout.setDirectory(outdir);
+
+ char *env = getenv("CONFIG_OUTPUT");
+ if (!env)
+ env = "config.out";
+ configStream = simout.find(env);
+
+ if (!configfile_found)
+ panic("no configuration file specified!");
+
+ // The configuration database is now complete; start processing it.
+ IniFile inifile;
+ if (!pyconfig.output(inifile))
+ panic("Error processing python code");
+
+ // Initialize statistics database
+ Stats::InitSimStats();
+
+ // Now process the configuration hierarchy and create the SimObjects.
+ ConfigHierarchy configHierarchy(inifile);
+ configHierarchy.build();
+ configHierarchy.createSimObjects();
+
+ // Parse and check all non-config-hierarchy parameters.
+ ParamContext::parseAllContexts(inifile);
+ ParamContext::checkAllContexts();
+
+ // Print hello message to stats file if it's actually a file. If
+ // it's not (i.e. it's cout or cerr) then we already did it above.
+ if (simout.isFile(*outputStream))
+ sayHello(*outputStream);
+
+ // Echo command line and all parameter settings to stats file as well.
+ echoCommandLine(argc, argv, *outputStream);
+ ParamContext::showAllContexts(*configStream);
+
+ // Any objects that can't connect themselves until after construction should
+ // do so now
+ SimObject::connectAll();
+
+ // Do a second pass to finish initializing the sim objects
+ SimObject::initAll();
+
+ // Restore checkpointed state, if any.
+ configHierarchy.unserializeSimObjects();
+
+ // Done processing the configuration database.
+ // Check for unreferenced entries.
+ if (inifile.printUnreferenced())
+ panic("unreferenced sections/entries in the intermediate ini file");
+
+ SimObject::regAllStats();
+
+ // uncomment the following to get PC-based execution-time profile
+#ifdef DO_PROFILE
+ init_profile((char *)&_init, (char *)&_fini);
+#endif
+
+ // Check to make sure that the stats package is properly initialized
+ Stats::check();
+
+ // Reset to put the stats in a consistent state.
+ Stats::reset();
+
+ warn("Entering event queue. Starting simulation...\n");
+ SimStartup();
+ while (!mainEventQueue.empty()) {
+ assert(curTick <= mainEventQueue.nextTick() &&
+ "event scheduled in the past");
+
+ // forward current cycle to the time of the first event on the
+ // queue
+ curTick = mainEventQueue.nextTick();
+ mainEventQueue.serviceOne();
+
+ if (async_event) {
+ async_event = false;
+ if (async_dump) {
+ async_dump = false;
+
+ using namespace Stats;
+ SetupEvent(Dump, curTick);
+ }
+
+ if (async_dumpreset) {
+ async_dumpreset = false;
+
+ using namespace Stats;
+ SetupEvent(Dump | Reset, curTick);
+ }
+
+ if (async_exit) {
+ async_exit = false;
+ new SimExitEvent("User requested STOP");
+ }
+
+ if (async_io || async_alarm) {
+ async_io = false;
+ async_alarm = false;
+ pollQueue.service();
+ }
+ }
+ }
+
+ // This should never happen... every conceivable way for the
+ // simulation to terminate (hit max cycles/insts, signal,
+ // simulated system halts/exits) generates an exit event, so we
+ // should never run out of events on the queue.
+ exitNow("no events on event loop! All CPUs must be idle.", 1);
+
+ return 0;
+}
diff --git a/src/sim/param.cc b/src/sim/param.cc
new file mode 100644
index 000000000..8998d7d77
--- /dev/null
+++ b/src/sim/param.cc
@@ -0,0 +1,793 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <algorithm>
+#include <cassert>
+#include <list>
+#include <string>
+#include <vector>
+
+#include "base/inifile.hh"
+#include "base/misc.hh"
+#include "base/range.hh"
+#include "base/str.hh"
+#include "base/trace.hh"
+#include "sim/config_node.hh"
+#include "sim/configfile.hh"
+#include "sim/param.hh"
+#include "sim/sim_object.hh"
+
+using namespace std;
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// BaseParam member definitions
+//
+////////////////////////////////////////////////////////////////////////
+
+void
+BaseParam::die(const string &err) const
+{
+ context->printErrorProlog(cerr);
+ cerr << " parameter '" << name << "': "
+ << err << endl;
+ abort();
+}
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Param<T> and VectorParam<T> member definitions
+//
+// We implement parsing & displaying values for various parameter
+// types T using a set of overloaded functions:
+//
+// - parseParam(string s, T &value) parses s into value
+// - showParam(ostream &os, T &value) displays value on os
+//
+// By making these independent functions, we can reuse the same code
+// for type T in both Param<T> and VectorParam<T>.
+//
+// For enum types, the parseParam function requires additional
+// arguments, in which case we must specialize the Param<T>::parse and
+// VectorParam<T>::parse calls as well.
+//
+// Type-specific instances come first, followed by more generic
+// templated versions and their instantiations.
+//
+////////////////////////////////////////////////////////////////////////
+
+//
+// The base implementations use to_number for parsing and '<<' for
+// displaying, suitable for integer types.
+//
+template <class T>
+bool
+parseParam(const string &s, T &value)
+{
+ return to_number(s, value);
+}
+
+template <class T>
+void
+showParam(ostream &os, T const &value)
+{
+ os << value;
+}
+
+//
+// Template specializations:
+// - char (8-bit integer)
+// - floating-point types
+// - bool
+// - string
+//
+
+// Treat 8-bit ints (chars) as ints on output, not as chars
+template <>
+void
+showParam(ostream &os, const char &value)
+{
+ os << (int)value;
+}
+
+
+template <>
+void
+showParam(ostream &os, const unsigned char &value)
+{
+ os << (unsigned int)value;
+}
+
+
+// Use sscanf() for FP types as to_number() only handles integers
+template <>
+bool
+parseParam(const string &s, float &value)
+{
+ return (sscanf(s.c_str(), "%f", &value) == 1);
+}
+
+template <>
+bool
+parseParam(const string &s, double &value)
+{
+ return (sscanf(s.c_str(), "%lf", &value) == 1);
+}
+
+// Be flexible about what we take for bool
+template <>
+bool
+parseParam(const string &s, bool &value)
+{
+ const string &ls = to_lower(s);
+
+ if (ls == "true" || ls == "t" || ls == "yes" || ls == "y" || ls == "1") {
+ value = true;
+ return true;
+ }
+
+ if (ls == "false" || ls == "f" || ls == "no" || ls == "n" || ls == "0") {
+ value = false;
+ return true;
+ }
+
+ return false;
+}
+
+// Display bools as strings
+template <>
+void
+showParam(ostream &os, const bool &value)
+{
+ os << (value ? "true" : "false");
+}
+
+
+// String requires no processing to speak of
+template <>
+bool
+parseParam(const string &s, string &value)
+{
+ value = s;
+ return true;
+}
+
+template <>
+bool
+parseParam(const string &s, Range<uint32_t> &value)
+{
+ value = s;
+ return value.valid();
+}
+
+template <>
+bool
+parseParam(const string &s, Range<uint64_t> &value)
+{
+ value = s;
+ return value.valid();
+}
+
+//
+// End of parseParam/showParam definitions. Now we move on to
+// incorporate them into the Param/VectorParam parse() and showValue()
+// methods.
+//
+
+// These definitions for Param<T>::parse and VectorParam<T>::parse
+// work for any type for which parseParam() takes only two arguments
+// (i.e., all the fundamental types like int, bool, etc.), thanks to
+// overloading.
+template <class T>
+void
+Param<T>::parse(const string &s)
+{
+ if (parseParam(s, value)) {
+ wasSet = true;
+ }
+ else {
+ string err("could not parse \"");
+
+ err += s;
+ err += "\"";
+
+ die(err);
+ }
+}
+
+template <class T>
+void
+VectorParam<T>::parse(const string &s)
+{
+ if (s.empty()) {
+ wasSet = true;
+ return;
+ }
+
+ vector<string> tokens;
+
+ tokenize(tokens, s, ' ');
+
+ value.resize(tokens.size());
+
+ for (int i = 0; i < tokens.size(); i++) {
+ // need to parse into local variable to handle vector<bool>,
+ // for which operator[] returns a special reference class
+ // that's not the same as 'bool&', (since it's a packed
+ // vector)
+ T scalar_value;
+ if (!parseParam(tokens[i], scalar_value)) {
+ string err("could not parse \"");
+
+ err += s;
+ err += "\"";
+
+ die(err);
+ }
+
+ // assign parsed value to vector
+ value[i] = scalar_value;
+ }
+
+ wasSet = true;
+}
+
+// These definitions for Param<T>::showValue() and
+// VectorParam<T>::showValue() work for any type where showParam()
+// takes only two arguments (i.e., everything but the SimpleEnum and
+// MappedEnum classes).
+template <class T>
+void
+Param<T>::showValue(ostream &os) const
+{
+ showParam(os, value);
+}
+
+template <class T>
+void
+VectorParam<T>::showValue(ostream &os) const
+{
+ for (int i = 0; i < value.size(); i++) {
+ if (i != 0) {
+ os << " ";
+ }
+ showParam(os, value[i]);
+ }
+}
+
+
+#ifdef INSURE_BUILD
+#define INSTANTIATE_PARAM_TEMPLATES(type, typestr) \
+void Param<type>::showType(ostream &os) const { os << typestr; } \
+void VectorParam<type>::showType(ostream &os) const { \
+ os << "vector of " << typestr; \
+} \
+template Param<type>; \
+template VectorParam<type>;
+
+#else
+// instantiate all four methods (parse/show, scalar/vector) for basic
+// types that can use the above templates
+#define INSTANTIATE_PARAM_TEMPLATES(type, typestr) \
+template bool parseParam<type>(const string &s, type &value); \
+template void showParam<type>(ostream &os, type const &value); \
+template void Param<type>::parse(const string &); \
+template void VectorParam<type>::parse(const string &); \
+template void Param<type>::showValue(ostream &) const; \
+template void VectorParam<type>::showValue(ostream &) const; \
+template <> void Param<type>::showType(ostream &os) const { os << typestr; } \
+template <> void VectorParam<type>::showType(ostream &os) const { \
+ os << "vector of " << typestr; \
+}
+#endif
+
+INSTANTIATE_PARAM_TEMPLATES(unsigned long long, "ull")
+INSTANTIATE_PARAM_TEMPLATES(signed long long, "sll")
+INSTANTIATE_PARAM_TEMPLATES(unsigned long, "uns long")
+INSTANTIATE_PARAM_TEMPLATES(signed long, "long")
+INSTANTIATE_PARAM_TEMPLATES(unsigned int, "uns")
+INSTANTIATE_PARAM_TEMPLATES(signed int, "int")
+INSTANTIATE_PARAM_TEMPLATES(unsigned short, "uns short")
+INSTANTIATE_PARAM_TEMPLATES(signed short, "short")
+INSTANTIATE_PARAM_TEMPLATES(unsigned char, "uns char")
+INSTANTIATE_PARAM_TEMPLATES(signed char, "char")
+
+INSTANTIATE_PARAM_TEMPLATES(float, "float")
+INSTANTIATE_PARAM_TEMPLATES(double, "double")
+
+INSTANTIATE_PARAM_TEMPLATES(bool, "bool")
+INSTANTIATE_PARAM_TEMPLATES(string, "string")
+
+INSTANTIATE_PARAM_TEMPLATES(Range<uint64_t>, "uint64 range")
+INSTANTIATE_PARAM_TEMPLATES(Range<uint32_t>, "uint32 range")
+
+#undef INSTANTIATE_PARAM_TEMPLATES
+
+//
+// SimpleEnumParam & MappedEnumParam must specialize their parse(),
+// showValue(), and showType() methods.
+//
+
+//
+// SimpleEnumParam & SimpleEnumVectorParam
+//
+bool
+parseEnumParam(const char *const *map, const int num_values,
+ const string &s, int &value)
+{
+ for (int i = 0; i < num_values; ++i) {
+ if (s == map[i]) {
+ value = i;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void
+showEnumParam(ostream &os,
+ const char *const *map, const int num_values,
+ int value)
+{
+ assert(0 <= value && value < num_values);
+ os << map[value];
+}
+
+void
+showEnumType(ostream &os,
+ const char *const *map, const int num_values)
+{
+ os << "{" << map[0];
+ for (int i = 1; i < num_values; ++i)
+ os << "," << map[i];
+
+ os << "}";
+}
+
+
+//
+// MappedEnumParam & MappedEnumVectorParam
+//
+bool
+parseEnumParam(const EnumParamMap *map, const int num_values,
+ const string &s, int &value)
+{
+ for (int i = 0; i < num_values; ++i) {
+ if (s == map[i].name) {
+ value = map[i].value;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void
+showEnumParam(ostream &os,
+ const EnumParamMap *map, const int num_values,
+ int value)
+{
+ for (int i = 0; i < num_values; ++i) {
+ if (value == map[i].value) {
+ os << map[i].name;
+ return;
+ }
+ }
+
+ // if we can't find a reverse mapping just print the int value
+ os << value;
+}
+
+void
+showEnumType(ostream &os,
+ const EnumParamMap *map, const int num_values)
+{
+ os << "{" << map[0].name;
+ for (int i = 1; i < num_values; ++i)
+ os << "," << map[i].name;
+
+ os << "}";
+}
+
+
+template <class Map>
+void
+EnumParam<Map>::parse(const string &s)
+{
+ if (parseEnumParam(map, num_values, s, value)) {
+ wasSet = true;
+ } else {
+ string err("no match for enum string \"");
+
+ err += s;
+ err += "\"";
+
+ die(err);
+ }
+}
+
+template <class Map>
+void
+EnumVectorParam<Map>::parse(const string &s)
+{
+ vector<string> tokens;
+
+ if (s.empty()) {
+ wasSet = true;
+ return;
+ }
+
+ tokenize(tokens, s, ' ');
+
+ value.resize(tokens.size());
+
+ for (int i = 0; i < tokens.size(); i++) {
+ if (!parseEnumParam(map, num_values, tokens[i], value[i])) {
+ string err("no match for enum string \"");
+
+ err += s;
+ err += "\"";
+
+ die(err);
+ }
+ }
+
+ wasSet = true;
+}
+
+template <class Map>
+void
+EnumParam<Map>::showValue(ostream &os) const
+{
+ showEnumParam(os, map, num_values, value);
+}
+
+template <class Map>
+void
+EnumVectorParam<Map>::showValue(ostream &os) const
+{
+ for (int i = 0; i < value.size(); i++) {
+ if (i != 0) {
+ os << " ";
+ }
+ showEnumParam(os, map, num_values, value[i]);
+ }
+}
+
+template <class Map>
+void
+EnumParam<Map>::showType(ostream &os) const
+{
+ showEnumType(os, map, num_values);
+}
+
+template <class Map>
+void
+EnumVectorParam<Map>::showType(ostream &os) const
+{
+ os << "vector of";
+ showEnumType(os, map, num_values);
+}
+
+template class EnumParam<const char *>;
+template class EnumVectorParam<const char *>;
+
+template class EnumParam<EnumParamMap>;
+template class EnumVectorParam<EnumParamMap>;
+
+////////////////////////////////////////////////////////////////////////
+//
+// SimObjectBaseParam methods
+//
+////////////////////////////////////////////////////////////////////////
+
+bool
+parseSimObjectParam(ParamContext *context, const string &s, SimObject *&value)
+{
+ SimObject *obj;
+
+ if (to_lower(s) == "null") {
+ // explicitly set to null by user; assume that's OK
+ obj = NULL;
+ }
+ else {
+ obj = context->resolveSimObject(s);
+
+ if (obj == NULL)
+ return false;
+ }
+
+ value = obj;
+ return true;
+}
+
+
+void
+SimObjectBaseParam::showValue(ostream &os, SimObject *value) const
+{
+ os << (value ? value->name() : "null");
+}
+
+void
+SimObjectBaseParam::parse(const string &s, SimObject *&value)
+{
+ if (parseSimObjectParam(context, s, value)) {
+ wasSet = true;
+ }
+ else {
+ string err("could not resolve object name \"");
+
+ err += s;
+ err += "\"";
+
+ die(err);
+ }
+}
+
+void
+SimObjectBaseParam::parse(const string &s, vector<SimObject *>&value)
+{
+ vector<string> tokens;
+
+ tokenize(tokens, s, ' ');
+
+ value.resize(tokens.size());
+
+ for (int i = 0; i < tokens.size(); i++) {
+ if (!parseSimObjectParam(context, tokens[i], value[i])) {
+ string err("could not resolve object name \"");
+
+ err += s;
+ err += "\"";
+
+ die(err);
+ }
+ }
+
+ wasSet = true;
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// ParamContext member definitions
+//
+////////////////////////////////////////////////////////////////////////
+
+list<ParamContext *> *ParamContext::ctxList = NULL;
+
+ParamContext::ParamContext(const string &_iniSection, InitPhase _initPhase)
+ : iniFilePtr(NULL), // initialized on call to parseParams()
+ iniSection(_iniSection), paramList(NULL),
+ initPhase(_initPhase)
+{
+ // Put this context on global list for initialization
+ if (initPhase != NoAutoInit) {
+ if (ctxList == NULL)
+ ctxList = new list<ParamContext *>();
+
+ // keep list sorted by ascending initPhase values
+ list<ParamContext *>::iterator i = ctxList->begin();
+ list<ParamContext *>::iterator end = ctxList->end();
+ for (; i != end; ++i) {
+ if (initPhase <= (*i)->initPhase) {
+ // found where we want to insert
+ break;
+ }
+ }
+ // (fall through case: insert at end)
+ ctxList->insert(i, this);
+ }
+}
+
+
+void
+ParamContext::addParam(BaseParam *param)
+{
+ getParamList()->push_back(param);
+}
+
+
+void
+ParamContext::parseParams(IniFile &iniFile)
+{
+ iniFilePtr = &iniFile; // set object member
+
+ ParamList::iterator i;
+
+ for (i = getParamList()->begin(); i != getParamList()->end(); ++i) {
+ string string_value;
+
+ if (iniFile.find(iniSection, (*i)->name, string_value))
+ (*i)->parse(string_value);
+ }
+}
+
+
+// Check parameter values for validity & consistency. Default
+// implementation is no-op; derive subclass & override to add
+// actual functionality here.
+void
+ParamContext::checkParams()
+{
+ // nada
+}
+
+
+// Clean up context-related objects at end of execution. Default
+// implementation is no-op; derive subclass & override to add actual
+// functionality here.
+void
+ParamContext::cleanup()
+{
+ // nada
+}
+
+
+void
+ParamContext::describeParams(ostream &os)
+{
+ ParamList::iterator i;
+
+ for (i = getParamList()->begin(); i != getParamList()->end(); ++i) {
+ BaseParam *p = *i;
+
+ os << p->name << " (";
+ p->showType(os);
+ os << "): " << p->description << "\n";
+ }
+}
+
+
+
+void
+ParamContext::showParams(ostream &os)
+{
+ ParamList::iterator i;
+
+ for (i = getParamList()->begin(); i != getParamList()->end(); ++i) {
+ BaseParam *p = *i;
+
+ if (p->isValid()) {
+ os << p->name << "=";
+ p->showValue(os);
+ os << endl;
+ }
+ else {
+ os << "// "<< p->name << " not specified" << endl;
+ }
+ }
+}
+
+
+void
+ParamContext::printErrorProlog(ostream &os)
+{
+ os << "Parameter error in section [" << iniSection << "]: " << endl;
+}
+
+//
+// Resolve an object name to a SimObject pointer. The object will be
+// created as a side-effect if necessary. If the name contains a
+// colon (e.g., "iq:IQ"), then the object is local (invisible to
+// outside this context). If there is no colon, the name needs to be
+// resolved through the configuration hierarchy (only possible for
+// SimObjectBuilder objects, which return non-NULL for configNode()).
+//
+SimObject *
+ParamContext::resolveSimObject(const string &name)
+{
+ ConfigNode *n = getConfigNode();
+ return n ? n->resolveSimObject(name) : NULL;
+}
+
+
+//
+// static method: call parseParams() on all registered contexts
+//
+void
+ParamContext::parseAllContexts(IniFile &iniFile)
+{
+ list<ParamContext *>::iterator iter;
+
+ for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
+ ParamContext *pc = *iter;
+
+ pc->parseParams(iniFile);
+ }
+}
+
+
+//
+// static method: call checkParams() on all registered contexts
+//
+void
+ParamContext::checkAllContexts()
+{
+ list<ParamContext *>::iterator iter;
+
+ for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
+ ParamContext *pc = *iter;
+
+ pc->checkParams();
+ }
+}
+
+
+//
+// static method: call showParams() on all registered contexts
+//
+void
+ParamContext::showAllContexts(ostream &os)
+{
+ list<ParamContext *>::iterator iter;
+
+ for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
+ ParamContext *pc = *iter;
+
+ os << "[" << pc->iniSection << "]" << endl;
+ pc->showParams(os);
+ os << endl;
+ }
+}
+
+
+//
+// static method: call cleanup() on all registered contexts
+//
+void
+ParamContext::cleanupAllContexts()
+{
+ list<ParamContext *>::iterator iter;
+
+ for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
+ ParamContext *pc = *iter;
+
+ pc->cleanup();
+ }
+}
+
+
+//
+// static method: call describeParams() on all registered contexts
+//
+void
+ParamContext::describeAllContexts(ostream &os)
+{
+ list<ParamContext *>::iterator iter;
+
+ for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) {
+ ParamContext *pc = *iter;
+
+ os << "[" << pc->iniSection << "]\n";
+ pc->describeParams(os);
+ os << endl;
+ }
+}
diff --git a/src/sim/param.hh b/src/sim/param.hh
new file mode 100644
index 000000000..4a1b8bda1
--- /dev/null
+++ b/src/sim/param.hh
@@ -0,0 +1,788 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SIM_PARAM_HH__
+#define __SIM_PARAM_HH__
+
+#include <iostream>
+#include <list>
+#include <string>
+#include <vector>
+
+#include "sim/configfile.hh"
+#include "sim/startup.hh"
+
+// forward decls
+class BaseParam;
+class SimObject;
+
+//
+// The context of a parameter definition... usually a subclass of
+// SimObjectBuilder (which derives from ParamContext), but abstracted
+// here to support more global simulator control parameters as well.
+//
+class ParamContext : protected StartupCallback
+{
+ private:
+
+ // static list of all ParamContext objects, built as a side effect
+ // of the ParamContext constructor
+ static std::list<ParamContext *> *ctxList;
+
+ protected:
+
+ // .ini file (database) for parameter lookup... initialized on call
+ // to parseParams()
+ IniFile *iniFilePtr;
+
+ // .ini file section for parameter lookup
+ const std::string iniSection;
+
+ typedef std::vector<BaseParam *> ParamList;
+
+ // list of parameters defined in this context
+ ParamList *paramList;
+
+ ParamList *getParamList() {
+ if (!paramList)
+ paramList = new ParamList;
+ return paramList;
+ }
+
+ public:
+
+ /// Initialization phases for ParamContext objects.
+ enum InitPhase {
+ NoAutoInit = -1, ///< Don't initialize at all... params
+ /// will be parsed later (used by
+ /// SimObjectBuilder, which parses
+ /// params in SimObject::create().
+ OutputInitPhase = 0, ///< Output stream initialization
+ TraceInitPhase = 1, ///< Trace context initialization:
+ /// depends on output streams, but
+ /// needs to come before others so we
+ /// can use tracing in other
+ /// ParamContext init code
+ StatsInitPhase = 2, ///< Stats output initialization
+ DefaultInitPhase = 3 ///< Everything else
+ };
+
+ /// Records the initialization phase for this ParamContext.
+ InitPhase initPhase;
+
+ /// Constructor.
+ /// @param _iniSection Name of .ini section corresponding to this context.
+ /// @param _initPhase Initialization phase (see InitPhase).
+ ParamContext(const std::string &_iniSection,
+ InitPhase _initPhase = DefaultInitPhase);
+
+ virtual ~ParamContext() {}
+
+ // add a parameter to the context... called from the parameter
+ // object's constructor (see BaseParam::BaseParam())
+ void addParam(BaseParam *);
+
+ // call parse() on all params in this context to convert string
+ // representations to parameter values
+ virtual void parseParams(IniFile &iniFile);
+
+ // Check parameter values for validity & consistency. Default
+ // implementation is no-op; derive subclass & override to add
+ // actual functionality here
+ virtual void checkParams();
+
+ // Clean up at end of execution: close file descriptors, etc.
+ // Default implementation is no-op; derive subclass & override to
+ // add actual functionality here
+ virtual void cleanup();
+
+ // dump parameter descriptions
+ void describeParams(std::ostream &);
+
+ // Display the parameters & values used
+ void showParams(std::ostream &);
+
+ // print context information for parameter error
+ virtual void printErrorProlog(std::ostream &);
+
+ // resolve a SimObject name in this context to an object pointer.
+ virtual SimObject *resolveSimObject(const std::string &name);
+
+ // generate the name for this instance of this context (used as a
+ // prefix to create unique names in resolveSimObject()
+ virtual const std::string &getInstanceName() { return iniSection; }
+
+ // return the configuration hierarchy node for this context. Bare
+ // ParamContext objects have no corresponding node, so the default
+ // implementation returns NULL.
+ virtual ConfigNode *getConfigNode() { return NULL; }
+
+ // Parse all parameters registered with all ParamContext objects.
+ static void parseAllContexts(IniFile &iniFile);
+
+ // Check all parameters registered with all ParamContext objects.
+ // (calls checkParams() on each)
+ static void checkAllContexts();
+
+ // Print all parameter values on indicated ostream.
+ static void showAllContexts(std::ostream &os);
+
+ // Clean up all registered ParamContext objects. (calls cleanup()
+ // on each)
+ static void cleanupAllContexts();
+
+ // print descriptions of all parameters registered with all
+ // ParamContext objects
+ static void describeAllContexts(std::ostream &os);
+};
+
+
+//
+// Base class for all parameter objects
+//
+class BaseParam
+{
+ public:
+
+ ParamContext *context;
+ std::string name;
+ std::string description; // text description for help message
+ bool wasSet; // true if parameter was set by user
+ bool hasDefault; // true if parameter has default value
+
+ BaseParam(ParamContext *_context, const std::string &_name,
+ const std::string &_description, bool _hasDefault)
+ : context(_context), name(_name), description(_description),
+ wasSet(false), hasDefault(_hasDefault)
+ {
+ context->addParam(this);
+ }
+
+ virtual ~BaseParam() {}
+
+ // a parameter is valid only if its value was set by the user or
+ // it has a default value
+ bool isValid() const
+ {
+ return (wasSet || hasDefault);
+ }
+
+ // set value by parsing string
+ virtual void parse(const std::string &s) = 0;
+
+ // display value to stream
+ virtual void showValue(std::ostream &) const = 0;
+
+ // display type to stream
+ virtual void showType(std::ostream &) const = 0;
+
+ // signal parse or usage error
+ virtual void die(const std::string &err) const;
+};
+
+//
+// Template classes to specialize parameters to specific types.
+//
+// Param<T> is for single-valued (scalar) parameters of type T.
+// VectorParam<T> is for multi-valued (vector) parameters of type T.
+// These are specified in the .ini file as a space-delimited list of
+// arguments.
+//
+template <class T>
+class Param : public BaseParam
+{
+ protected:
+
+ T value;
+
+ public:
+
+ // Param with default value: set value to default
+ Param(ParamContext *context,
+ const std::string &name, const std::string &description, T dfltValue)
+ : BaseParam(context, name, description, true),
+ value(dfltValue)
+ {
+ }
+
+ // Param with no default value: leave value uninitialized
+ Param(ParamContext *context,
+ const std::string &name, const std::string &description)
+ : BaseParam(context, name, description, false)
+ {
+ }
+
+ virtual ~Param() {}
+
+ operator T&()
+ {
+ // if we attempt to reference an invalid parameter (i.e., one
+ // with no default value that was not set by the user), die.
+ if (!isValid())
+ die("not found");
+ return value;
+ }
+
+ // display value to stream
+ virtual void showValue(std::ostream &os) const;
+
+ // display type to stream
+ virtual void showType(std::ostream &) const;
+
+ // set value by parsing string
+ virtual void parse(const std::string &s);
+};
+
+
+//
+// Template class for vector-valued parameters (lists)
+//
+template <class T>
+class VectorParam : public BaseParam
+{
+ protected:
+
+ std::vector<T> value;
+
+ public:
+
+ typedef typename std::vector<T>::size_type size_type;
+
+ // Param with default value: set value to default
+ VectorParam(ParamContext *context, const std::string &name,
+ const std::string &description,
+ const std::vector<T> &dfltValue)
+ : BaseParam(context, name, description, true),
+ value(dfltValue)
+ {
+ }
+
+ // Param with no default value: leave value uninitialized
+ VectorParam(ParamContext *context,
+ const std::string &name, const std::string &description)
+ : BaseParam(context, name, description, false)
+ {
+ }
+
+ virtual ~VectorParam() {}
+
+ // basic vector access methods
+ size_type size() const
+ {
+ if (!isValid())
+ die("not found");
+ return value.size();
+ }
+
+ const T &operator[](size_type n) const
+ {
+ if (!isValid())
+ die("not found");
+ return value[n];
+ }
+
+ // return reference to value vector
+ operator std::vector<T>&()
+ {
+ if (!isValid())
+ die("not found");
+ return value;
+ }
+
+ // display value to stream
+ virtual void showValue(std::ostream &os) const;
+
+ // display type to stream
+ virtual void showType(std::ostream &) const;
+
+ // set value by parsing string
+ virtual void parse(const std::string &s);
+};
+
+//
+// Specialization of Param<int> and VectorParam<int> to handle
+// enumerated types is done in two ways, using SimpleEnumParam and
+// MappedEnumParam (and their vector counterparts,
+// SimpleEnumVectorParam and MappedEnumVectorParam). SimpleEnumParam
+// takes an array of strings and maps them to integers based on array
+// index. MappedEnumParam takes an array of string-to-int mappings,
+// allowing for mapping strings to non-contiguous integer values, or
+// mapping multiple strings to the same integer value.
+//
+// Both SimpleEnumParam and MappedEnumParam are implemented using a
+// single template class, EnumParam<Map>, which takes the type of the map
+// as a parameter (const char * or EnumParamMap). Similarly,
+// SimpleEnumVectorParam and MappedEnumVectorParam are both
+// implemented using EnumVectorParam<Map>.
+//
+template <class Map>
+class EnumParam : public Param<int>
+{
+ const int num_values;
+ const Map *map;
+
+ public:
+
+ // Param with default value: set value to default
+ EnumParam(ParamContext *context,
+ const std::string &name, const std::string &description,
+ const Map *_map, int _num_values,
+ int dfltValue)
+ : Param<int>(context, name, description, dfltValue),
+ num_values(_num_values), map(_map)
+ {
+ }
+
+ // Param with no default value: leave value uninitialized
+ EnumParam(ParamContext *context,
+ const std::string &name, const std::string &description,
+ const Map *_map, int _num_values)
+ : Param<int>(context, name, description),
+ num_values(_num_values), map(_map)
+ {
+ }
+
+ virtual ~EnumParam() {}
+
+ // display value to stream
+ virtual void showValue(std::ostream &os) const;
+
+ // display type to stream
+ virtual void showType(std::ostream &) const;
+
+ // set value by parsing string
+ virtual void parse(const std::string &s);
+};
+
+//
+// Vector counterpart to SimpleEnumParam
+//
+template <class Map>
+class EnumVectorParam : public VectorParam<int>
+{
+ const int num_values;
+ const Map *map;
+
+ public:
+
+ // Param with default value: set value to default
+ EnumVectorParam(ParamContext *context,
+ const std::string &name, const std::string &description,
+ const Map *_map, int _num_values,
+ std::vector<int> &dfltValue)
+ : VectorParam<int>(context, name, description, dfltValue),
+ num_values(_num_values), map(_map)
+ {
+ }
+
+ // Param with no default value: leave value uninitialized
+ EnumVectorParam(ParamContext *context,
+ const std::string &name, const std::string &description,
+ const Map *_map, int _num_values)
+ : VectorParam<int>(context, name, description),
+ num_values(_num_values), map(_map)
+ {
+ }
+
+ virtual ~EnumVectorParam() {}
+
+ // display value to stream
+ virtual void showValue(std::ostream &os) const;
+
+ // display type to stream
+ virtual void showType(std::ostream &) const;
+
+ // set value by parsing string
+ virtual void parse(const std::string &s);
+};
+
+// Specialize EnumParam for a particular enumeration type ENUM
+// (automates casting to get value of enum type)
+
+template <class ENUM>
+class SimpleEnumParam : public EnumParam<const char *>
+{
+ public:
+
+ SimpleEnumParam(ParamContext *context,
+ const std::string &name, const std::string &description,
+ const char **_map, int _num_values,
+ ENUM dfltValue)
+ : EnumParam<const char *>(context, name, description,
+ _map, _num_values, (int)dfltValue)
+ {
+ }
+
+ SimpleEnumParam(ParamContext *context,
+ const std::string &name, const std::string &description,
+ const char **_map, int _num_values)
+ : EnumParam<const char *>(context, name, description,
+ _map, _num_values)
+ {
+ }
+
+ operator ENUM() const
+ {
+ if (!isValid())
+ die("not found");
+ return (ENUM)value;
+ }
+};
+
+
+// Specialize EnumParam for a particular enumeration type ENUM
+// (automates casting to get value of enum type)
+
+template <class ENUM>
+class SimpleEnumVectorParam : public EnumVectorParam<const char *>
+{
+ public:
+
+ // skip default value constructor: too much pain to convert
+ // vector<ENUM> initializer to vector<int>
+
+
+ SimpleEnumVectorParam(ParamContext *context,
+ const std::string &name,
+ const std::string &description,
+ const char **_map, int _num_values)
+ : EnumVectorParam<const char *>(context, name, description,
+ _map, _num_values)
+ {
+ }
+
+ ENUM operator[](size_type n)
+ {
+ if (!isValid())
+ die("not found");
+ return (ENUM)value[n];
+ }
+};
+
+
+//
+// Handle enums via string-to-int map (see comment above).
+//
+
+// An array of string-to-int mappings must be supplied using the
+// following type.
+typedef struct {
+ const char *name;
+ int value;
+} EnumParamMap;
+
+// Specialize EnumParam for a particular enumeration type ENUM
+// (automates casting to get value of enum type)
+
+template <class ENUM>
+class MappedEnumParam : public EnumParam<EnumParamMap>
+{
+ public:
+
+ MappedEnumParam(ParamContext *context,
+ const std::string &name, const std::string &description,
+ const EnumParamMap *_map, int _num_values,
+ ENUM dfltValue)
+ : EnumParam<EnumParamMap>(context, name, description,
+ _map, _num_values, (int)dfltValue)
+ {
+ }
+
+ MappedEnumParam(ParamContext *context,
+ const std::string &name, const std::string &description,
+ const EnumParamMap *_map, int _num_values)
+ : EnumParam<EnumParamMap>(context, name, description,
+ _map, _num_values)
+ {
+ }
+
+ operator ENUM()
+ {
+ if (!isValid())
+ die("not found");
+ return (ENUM)value[this->n];
+ }
+};
+
+
+// Specialize EnumParam for a particular enumeration type ENUM
+// (automates casting to get value of enum type)
+
+template <class ENUM>
+class MappedEnumVectorParam : public EnumVectorParam<EnumParamMap>
+{
+ public:
+
+ // skip default value constructor: too much pain to convert
+ // vector<ENUM> initializer to vector<int>
+
+
+ MappedEnumVectorParam(ParamContext *context,
+ const std::string &name,
+ const std::string &description,
+ const EnumParamMap *_map, int _num_values)
+ : EnumVectorParam<EnumParamMap>(context, name, description,
+ _map, _num_values)
+ {
+ }
+
+ ENUM operator[](size_type n)
+ {
+ if (!isValid())
+ die("not found");
+ return (ENUM)value[n];
+ }
+};
+
+
+//
+// Parameters that point to other simulation objects (e.g. caches,
+// busses, etc.) are handled by specializing SimObjectBaseParam to the
+// specific subtype. The main purpose of SimObjectBaseParam is to
+// provide a place to stick several helper functions common to all
+// SimObject-derived parameters.
+//
+class SimObjectBaseParam : public BaseParam
+{
+ public:
+
+ SimObjectBaseParam(ParamContext *context, const std::string &name,
+ const std::string &description, bool hasDefault)
+ : BaseParam(context, name, description, hasDefault)
+ {
+ }
+
+ virtual ~SimObjectBaseParam() {}
+
+ // helper function for SimObjectParam<T>::showValue()
+ void showValue(std::ostream &os, SimObject *obj) const;
+
+ // helper function for SimObjectParam<T>::parse()
+ void parse(const std::string &s, SimObject *&value);
+
+ // helper function for SimObjectParam<T>::parse()
+ void parse(const std::string &s, std::vector<SimObject *>&value_vec);
+};
+
+
+//
+// Parameter to a specific type of SimObject. Note that T must be a
+// pointer to a class derived from SimObject (e.g., <CPU *>).
+//
+
+template <class T> class SimObjectParam;
+
+template <class T>
+class SimObjectParam<T *> : public SimObjectBaseParam
+{
+ protected:
+
+ T *value;
+
+ public:
+
+ // initialization w/o default
+ SimObjectParam(ParamContext *context,
+ const std::string &name, const std::string &description)
+ : SimObjectBaseParam(context, name, description, false)
+ {
+ }
+
+ // initialization wit=h default
+ SimObjectParam(ParamContext *context,
+ const std::string &name, const std::string &description,
+ T *dfltValue)
+ : SimObjectBaseParam(context, name, description, true),
+ value(dfltValue)
+ {
+ }
+
+ virtual ~SimObjectParam() {}
+
+ // convert to pointer
+ operator T*()
+ {
+ if (!isValid())
+ die("not found");
+ return value;
+ }
+
+ T *operator->() const
+ {
+ if (!isValid())
+ die("not found");
+ return value;
+ }
+
+ // display value to stream
+ virtual void showValue(std::ostream &os) const
+ {
+ SimObjectBaseParam::showValue(os, value);
+ }
+
+ // display type to stream: see REGISTER_SIM_OBJECT macro in
+ // sim_object.hh for declaration
+ virtual void showType(std::ostream &os) const;
+
+ // set value by parsing string
+ virtual void parse(const std::string &s)
+ {
+ SimObject *so_ptr;
+ // first parse to generic SimObject *
+ SimObjectBaseParam::parse(s, so_ptr);
+ // now dynamic_cast to specific derived type
+ value = dynamic_cast<T *>(so_ptr);
+ // check for failure of dynamic_cast
+ if (value == NULL && so_ptr != NULL)
+ die("not of appropriate type");
+ }
+};
+
+
+//
+// Vector counterpart to SimObjectParam<T>
+//
+
+template <class T> class SimObjectVectorParam;
+
+template <class T>
+class SimObjectVectorParam<T *> : public SimObjectBaseParam
+{
+ protected:
+
+ std::vector<T *> value;
+
+ public:
+
+ typedef typename std::vector<T *>::size_type size_type;
+
+ SimObjectVectorParam(ParamContext *context,
+ const std::string &name,
+ const std::string &description)
+ : SimObjectBaseParam(context, name, description, false)
+ {
+ }
+
+ SimObjectVectorParam(ParamContext *context,
+ const std::string &name,
+ const std::string &description,
+ std::vector<T *> dfltValue)
+ : SimObjectBaseParam(context, name, description, true),
+ value(dfltValue)
+ {
+ }
+
+ virtual ~SimObjectVectorParam() {}
+
+ // basic vector access methods
+ size_type size() const
+ {
+ if (!isValid())
+ die("not found");
+ return value.size();
+ }
+
+ T *&operator[](size_type n)
+ {
+ if (!isValid())
+ die("not found");
+ return value[n];
+ }
+
+ // return reference to value vector
+ operator std::vector<T *>&()
+ {
+ if (!isValid())
+ die("not found");
+ return value;
+ }
+
+ // display value to stream
+ virtual void showValue(std::ostream &os) const
+ {
+ for (int i = 0; i < value.size(); i++) {
+ if (i != 0)
+ os << " ";
+ SimObjectBaseParam::showValue(os, value[i]);
+ }
+ }
+
+ // display type to stream: see
+ virtual void showType(std::ostream &os) const;
+
+ // set value by parsing string
+ virtual void parse(const std::string &s)
+ {
+ std::vector<SimObject *> so_ptr_vec;
+ // first parse to generic SimObject * vector (from SimObjectBaseParam)
+ SimObjectBaseParam::parse(s, so_ptr_vec);
+
+ value.resize(so_ptr_vec.size());
+
+ for (int i = 0; i < so_ptr_vec.size(); ++i) {
+ // now dynamic_cast to specific derived type
+ value[i] = dynamic_cast<T *>(so_ptr_vec[i]);
+ // check for failure of dynamic_cast
+ if (value[i] == NULL && so_ptr_vec[i] != NULL)
+ die("not of appropriate type");
+ }
+ }
+};
+
+//
+// Macro to define showType() methods for SimObjectParam &
+// SimObjectVectorParam. Can't do this automatically as it requires a
+// string name for the type, which you can't get from a template
+// argument. For concrete derived SimObject types, this macro is
+// automatically invoked by REGISTER_SIM_OBJECT() (see sim_object.hh).
+//
+#define DEFINE_SIM_OBJECT_CLASS_NAME(CLASS_NAME, OBJ_CLASS) \
+template<> \
+void \
+SimObjectParam<OBJ_CLASS *>::showType(std::ostream &os) const \
+{ \
+ os << CLASS_NAME; \
+} \
+ \
+template<> \
+void \
+SimObjectVectorParam<OBJ_CLASS *>::showType(std::ostream &os) const \
+{ \
+ os << "vector of " << CLASS_NAME; \
+}
+
+
+//
+// Declarations for low-level parsing & displaying functions. These
+// are used internally, but should not be used directly by clients of
+// the parameter mechanism, but are declared here so they can be
+// shared with the serialization code (see sim/serialize.cc).
+template <class T> bool parseParam(const std::string &str, T &data);
+template <class T> void showParam(std::ostream &os, const T &data);
+
+#endif // _SIM_PARAM_HH_
diff --git a/src/sim/process.cc b/src/sim/process.cc
new file mode 100644
index 000000000..1261b8436
--- /dev/null
+++ b/src/sim/process.cc
@@ -0,0 +1,361 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <string>
+
+#include "base/intmath.hh"
+#include "base/loader/object_file.hh"
+#include "base/loader/symtab.hh"
+#include "base/statistics.hh"
+#include "config/full_system.hh"
+#include "cpu/exec_context.hh"
+#include "mem/page_table.hh"
+#include "mem/physical.hh"
+#include "mem/translating_port.hh"
+#include "sim/builder.hh"
+#include "sim/process.hh"
+#include "sim/stats.hh"
+#include "sim/syscall_emul.hh"
+#include "sim/system.hh"
+
+using namespace std;
+using namespace TheISA;
+
+//
+// The purpose of this code is to fake the loader & syscall mechanism
+// when there's no OS: thus there's no resone to use it in FULL_SYSTEM
+// mode when we do have an OS
+//
+#if FULL_SYSTEM
+#error "process.cc not compatible with FULL_SYSTEM"
+#endif
+
+// current number of allocated processes
+int num_processes = 0;
+
+Process::Process(const string &nm,
+ System *_system,
+ int stdin_fd, // initial I/O descriptors
+ int stdout_fd,
+ int stderr_fd)
+ : SimObject(nm), system(_system)
+{
+ // initialize first 3 fds (stdin, stdout, stderr)
+ fd_map[STDIN_FILENO] = stdin_fd;
+ fd_map[STDOUT_FILENO] = stdout_fd;
+ fd_map[STDERR_FILENO] = stderr_fd;
+
+ // mark remaining fds as free
+ for (int i = 3; i <= MAX_FD; ++i) {
+ fd_map[i] = -1;
+ }
+
+ mmap_start = mmap_end = 0;
+ nxm_start = nxm_end = 0;
+ pTable = new PageTable(system);
+ // other parameters will be initialized when the program is loaded
+}
+
+
+void
+Process::regStats()
+{
+ using namespace Stats;
+
+ num_syscalls
+ .name(name() + ".PROG:num_syscalls")
+ .desc("Number of system calls")
+ ;
+}
+
+//
+// static helper functions
+//
+int
+Process::openInputFile(const string &filename)
+{
+ int fd = open(filename.c_str(), O_RDONLY);
+
+ if (fd == -1) {
+ perror(NULL);
+ cerr << "unable to open \"" << filename << "\" for reading\n";
+ fatal("can't open input file");
+ }
+
+ return fd;
+}
+
+
+int
+Process::openOutputFile(const string &filename)
+{
+ int fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0774);
+
+ if (fd == -1) {
+ perror(NULL);
+ cerr << "unable to open \"" << filename << "\" for writing\n";
+ fatal("can't open output file");
+ }
+
+ return fd;
+}
+
+
+int
+Process::registerExecContext(ExecContext *xc)
+{
+ // add to list
+ int myIndex = execContexts.size();
+ execContexts.push_back(xc);
+
+ // return CPU number to caller
+ return myIndex;
+}
+
+void
+Process::startup()
+{
+ if (execContexts.empty())
+ fatal("Process %s is not associated with any CPUs!\n", name());
+
+ // first exec context for this process... initialize & enable
+ ExecContext *xc = execContexts[0];
+
+ // mark this context as active so it will start ticking.
+ xc->activate(0);
+
+ Port *mem_port;
+ mem_port = system->physmem->getPort("functional");
+ initVirtMem = new TranslatingPort(pTable, true);
+ mem_port->setPeer(initVirtMem);
+ initVirtMem->setPeer(mem_port);
+}
+
+void
+Process::replaceExecContext(ExecContext *xc, int xcIndex)
+{
+ if (xcIndex >= execContexts.size()) {
+ panic("replaceExecContext: bad xcIndex, %d >= %d\n",
+ xcIndex, execContexts.size());
+ }
+
+ execContexts[xcIndex] = xc;
+}
+
+// map simulator fd sim_fd to target fd tgt_fd
+void
+Process::dup_fd(int sim_fd, int tgt_fd)
+{
+ if (tgt_fd < 0 || tgt_fd > MAX_FD)
+ panic("Process::dup_fd tried to dup past MAX_FD (%d)", tgt_fd);
+
+ fd_map[tgt_fd] = sim_fd;
+}
+
+
+// generate new target fd for sim_fd
+int
+Process::alloc_fd(int sim_fd)
+{
+ // in case open() returns an error, don't allocate a new fd
+ if (sim_fd == -1)
+ return -1;
+
+ // find first free target fd
+ for (int free_fd = 0; free_fd < MAX_FD; ++free_fd) {
+ if (fd_map[free_fd] == -1) {
+ fd_map[free_fd] = sim_fd;
+ return free_fd;
+ }
+ }
+
+ panic("Process::alloc_fd: out of file descriptors!");
+}
+
+
+// free target fd (e.g., after close)
+void
+Process::free_fd(int tgt_fd)
+{
+ if (fd_map[tgt_fd] == -1)
+ warn("Process::free_fd: request to free unused fd %d", tgt_fd);
+
+ fd_map[tgt_fd] = -1;
+}
+
+
+// look up simulator fd for given target fd
+int
+Process::sim_fd(int tgt_fd)
+{
+ if (tgt_fd > MAX_FD)
+ return -1;
+
+ return fd_map[tgt_fd];
+}
+
+
+
+//
+// need to declare these here since there is no concrete Process type
+// that can be constructed (i.e., no REGISTER_SIM_OBJECT() macro call,
+// which is where these get declared for concrete types).
+//
+DEFINE_SIM_OBJECT_CLASS_NAME("Process", Process)
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// LiveProcess member definitions
+//
+////////////////////////////////////////////////////////////////////////
+
+
+void
+copyStringArray(vector<string> &strings, Addr array_ptr, Addr data_ptr,
+ TranslatingPort* memPort)
+{
+ Addr data_ptr_swap;
+ for (int i = 0; i < strings.size(); ++i) {
+ data_ptr_swap = htog(data_ptr);
+ memPort->writeBlob(array_ptr, (uint8_t*)&data_ptr_swap, sizeof(Addr));
+ memPort->writeString(data_ptr, strings[i].c_str());
+ array_ptr += sizeof(Addr);
+ data_ptr += strings[i].size() + 1;
+ }
+ // add NULL terminator
+ data_ptr = 0;
+
+ memPort->writeBlob(array_ptr, (uint8_t*)&data_ptr, sizeof(Addr));
+}
+
+LiveProcess::LiveProcess(const string &nm, ObjectFile *_objFile,
+ System *_system,
+ int stdin_fd, int stdout_fd, int stderr_fd,
+ vector<string> &_argv, vector<string> &_envp)
+ : Process(nm, _system, stdin_fd, stdout_fd, stderr_fd),
+ objFile(_objFile), argv(_argv), envp(_envp)
+{
+ prog_fname = argv[0];
+
+ // load up symbols, if any... these may be used for debugging or
+ // profiling.
+ if (!debugSymbolTable) {
+ debugSymbolTable = new SymbolTable();
+ if (!objFile->loadGlobalSymbols(debugSymbolTable) ||
+ !objFile->loadLocalSymbols(debugSymbolTable)) {
+ // didn't load any symbols
+ delete debugSymbolTable;
+ debugSymbolTable = NULL;
+ }
+ }
+}
+
+void
+LiveProcess::argsInit(int intSize, int pageSize)
+{
+ Process::startup();
+
+ // load object file into target memory
+ objFile->loadSections(initVirtMem);
+
+ // Calculate how much space we need for arg & env arrays.
+ int argv_array_size = intSize * (argv.size() + 1);
+ int envp_array_size = intSize * (envp.size() + 1);
+ int arg_data_size = 0;
+ for (int i = 0; i < argv.size(); ++i) {
+ arg_data_size += argv[i].size() + 1;
+ }
+ int env_data_size = 0;
+ for (int i = 0; i < envp.size(); ++i) {
+ env_data_size += envp[i].size() + 1;
+ }
+
+ int space_needed =
+ argv_array_size + envp_array_size + arg_data_size + env_data_size;
+ // for SimpleScalar compatibility
+ if (space_needed < 16384)
+ space_needed = 16384;
+
+ // set bottom of stack
+ stack_min = stack_base - space_needed;
+ // align it
+ stack_min &= ~(intSize-1);
+ stack_size = stack_base - stack_min;
+ // map memory
+ pTable->allocate(roundDown(stack_min, pageSize),
+ roundUp(stack_size, pageSize));
+
+ // map out initial stack contents
+ Addr argv_array_base = stack_min + intSize; // room for argc
+ Addr envp_array_base = argv_array_base + argv_array_size;
+ Addr arg_data_base = envp_array_base + envp_array_size;
+ Addr env_data_base = arg_data_base + arg_data_size;
+
+ // write contents to stack
+ uint64_t argc = argv.size();
+ if (intSize == 8)
+ argc = htog((uint64_t)argc);
+ else if (intSize == 4)
+ argc = htog((uint32_t)argc);
+ else
+ panic("Unknown int size");
+
+ initVirtMem->writeBlob(stack_min, (uint8_t*)&argc, intSize);
+
+ copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem);
+ copyStringArray(envp, envp_array_base, env_data_base, initVirtMem);
+
+ execContexts[0]->setIntReg(ArgumentReg0, argc);
+ execContexts[0]->setIntReg(ArgumentReg1, argv_array_base);
+ execContexts[0]->setIntReg(StackPointerReg, stack_min);
+
+ Addr prog_entry = objFile->entryPoint();
+ execContexts[0]->setPC(prog_entry);
+ execContexts[0]->setNextPC(prog_entry + sizeof(MachInst));
+ execContexts[0]->setNextNPC(prog_entry + (2 * sizeof(MachInst)));
+
+ num_processes++;
+}
+
+void
+LiveProcess::syscall(int64_t callnum, ExecContext *xc)
+{
+ num_syscalls++;
+
+ SyscallDesc *desc = getDesc(callnum);
+ if (desc == NULL)
+ fatal("Syscall %d out of range", callnum);
+
+ desc->doSyscall(callnum, this, xc);
+}
+
+DEFINE_SIM_OBJECT_CLASS_NAME("LiveProcess", LiveProcess);
diff --git a/src/sim/process.hh b/src/sim/process.hh
new file mode 100644
index 000000000..807bf330f
--- /dev/null
+++ b/src/sim/process.hh
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __PROCESS_HH__
+#define __PROCESS_HH__
+
+//
+// The purpose of this code is to fake the loader & syscall mechanism
+// when there's no OS: thus there's no reason to use it in FULL_SYSTEM
+// mode when we do have an OS.
+//
+#include "config/full_system.hh"
+
+#if !FULL_SYSTEM
+
+#include <vector>
+
+#include "base/statistics.hh"
+#include "sim/sim_object.hh"
+
+class CPUExecContext;
+class ExecContext;
+class SyscallDesc;
+class PageTable;
+class TranslatingPort;
+class System;
+
+void
+copyStringArray(std::vector<std::string> &strings, Addr array_ptr,
+ Addr data_ptr, TranslatingPort* memPort);
+
+class Process : public SimObject
+{
+ public:
+
+ /// Pointer to object representing the system this process is
+ /// running on.
+ System *system;
+
+ // have we initialized an execution context from this process? If
+ // yes, subsequent contexts are assumed to be for dynamically
+ // created threads and are not initialized.
+ bool initialContextLoaded;
+
+ // execution contexts associated with this process
+ std::vector<ExecContext *> execContexts;
+
+ // number of CPUs (esxec contexts, really) assigned to this process.
+ unsigned int numCpus() { return execContexts.size(); }
+
+ // record of blocked context
+ struct WaitRec
+ {
+ Addr waitChan;
+ ExecContext *waitingContext;
+
+ WaitRec(Addr chan, ExecContext *ctx)
+ : waitChan(chan), waitingContext(ctx)
+ { }
+ };
+
+ // list of all blocked contexts
+ std::list<WaitRec> waitList;
+
+ Addr brk_point; // top of the data segment
+
+ Addr stack_base; // stack segment base (highest address)
+ unsigned stack_size; // initial stack size
+ Addr stack_min; // lowest address accessed on the stack
+
+ // addr to use for next stack region (for multithreaded apps)
+ Addr next_thread_stack_base;
+
+ // Base of region for mmaps (when user doesn't specify an address).
+ Addr mmap_start;
+ Addr mmap_end;
+
+ // Base of region for nxm data
+ Addr nxm_start;
+ Addr nxm_end;
+
+ std::string prog_fname; // file name
+
+ Stats::Scalar<> num_syscalls; // number of syscalls executed
+
+
+ protected:
+ // constructor
+ Process(const std::string &nm,
+ System *_system,
+ int stdin_fd, // initial I/O descriptors
+ int stdout_fd,
+ int stderr_fd);
+
+ // post initialization startup
+ virtual void startup();
+
+ protected:
+ /// Memory object for initialization (image loading)
+ TranslatingPort *initVirtMem;
+
+ public:
+ PageTable *pTable;
+
+ private:
+ // file descriptor remapping support
+ static const int MAX_FD = 256; // max legal fd value
+ int fd_map[MAX_FD+1];
+
+ public:
+ // static helper functions to generate file descriptors for constructor
+ static int openInputFile(const std::string &filename);
+ static int openOutputFile(const std::string &filename);
+
+ // override of virtual SimObject method: register statistics
+ virtual void regStats();
+
+ // register an execution context for this process.
+ // returns xc's cpu number (index into execContexts[])
+ int registerExecContext(ExecContext *xc);
+
+
+ void replaceExecContext(ExecContext *xc, int xcIndex);
+
+ // map simulator fd sim_fd to target fd tgt_fd
+ void dup_fd(int sim_fd, int tgt_fd);
+
+ // generate new target fd for sim_fd
+ int alloc_fd(int sim_fd);
+
+ // free target fd (e.g., after close)
+ void free_fd(int tgt_fd);
+
+ // look up simulator fd for given target fd
+ int sim_fd(int tgt_fd);
+
+ virtual void syscall(int64_t callnum, ExecContext *xc) = 0;
+};
+
+//
+// "Live" process with system calls redirected to host system
+//
+class ObjectFile;
+class LiveProcess : public Process
+{
+ protected:
+ ObjectFile *objFile;
+ std::vector<std::string> argv;
+ std::vector<std::string> envp;
+
+ LiveProcess(const std::string &nm, ObjectFile *objFile,
+ System *_system, int stdin_fd, int stdout_fd, int stderr_fd,
+ std::vector<std::string> &argv,
+ std::vector<std::string> &envp);
+
+ virtual void argsInit(int intSize, int pageSize);
+
+ public:
+ virtual void syscall(int64_t callnum, ExecContext *xc);
+
+ virtual SyscallDesc* getDesc(int callnum) = 0;
+};
+
+
+#endif // !FULL_SYSTEM
+
+#endif // __PROCESS_HH__
diff --git a/src/sim/pseudo_inst.cc b/src/sim/pseudo_inst.cc
new file mode 100644
index 000000000..7897b5c8b
--- /dev/null
+++ b/src/sim/pseudo_inst.cc
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2003-2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <string>
+
+#include "sim/pseudo_inst.hh"
+#include "arch/vtophys.hh"
+#include "cpu/base.hh"
+#include "cpu/sampler/sampler.hh"
+#include "cpu/exec_context.hh"
+#include "kern/kernel_stats.hh"
+#include "sim/param.hh"
+#include "sim/serialize.hh"
+#include "sim/sim_exit.hh"
+#include "sim/stat_control.hh"
+#include "sim/stats.hh"
+#include "sim/system.hh"
+#include "sim/debug.hh"
+#include "sim/vptr.hh"
+
+using namespace std;
+
+extern Sampler *SampCPU;
+
+using namespace Stats;
+using namespace TheISA;
+
+namespace AlphaPseudo
+{
+ bool doStatisticsInsts;
+ bool doCheckpointInsts;
+ bool doQuiesce;
+
+ void
+ arm(ExecContext *xc)
+ {
+ xc->getCpuPtr()->kernelStats->arm();
+ }
+
+ void
+ quiesce(ExecContext *xc)
+ {
+ if (!doQuiesce)
+ return;
+
+ xc->suspend();
+ xc->getCpuPtr()->kernelStats->quiesce();
+ }
+
+ void
+ quiesceNs(ExecContext *xc, uint64_t ns)
+ {
+ if (!doQuiesce || ns == 0)
+ return;
+
+ Event *quiesceEvent = xc->getQuiesceEvent();
+
+ if (quiesceEvent->scheduled())
+ quiesceEvent->reschedule(curTick + Clock::Int::ns * ns);
+ else
+ quiesceEvent->schedule(curTick + Clock::Int::ns * ns);
+
+ xc->suspend();
+ xc->getCpuPtr()->kernelStats->quiesce();
+ }
+
+ void
+ quiesceCycles(ExecContext *xc, uint64_t cycles)
+ {
+ if (!doQuiesce || cycles == 0)
+ return;
+
+ Event *quiesceEvent = xc->getQuiesceEvent();
+
+ if (quiesceEvent->scheduled())
+ quiesceEvent->reschedule(curTick +
+ xc->getCpuPtr()->cycles(cycles));
+ else
+ quiesceEvent->schedule(curTick +
+ xc->getCpuPtr()->cycles(cycles));
+
+ xc->suspend();
+ xc->getCpuPtr()->kernelStats->quiesce();
+ }
+
+ uint64_t
+ quiesceTime(ExecContext *xc)
+ {
+ return (xc->readLastActivate() - xc->readLastSuspend()) / Clock::Int::ns;
+ }
+
+ void
+ ivlb(ExecContext *xc)
+ {
+ xc->getCpuPtr()->kernelStats->ivlb();
+ }
+
+ void
+ ivle(ExecContext *xc)
+ {
+ }
+
+ void
+ m5exit_old(ExecContext *xc)
+ {
+ SimExit(curTick, "m5_exit_old instruction encountered");
+ }
+
+ void
+ m5exit(ExecContext *xc, Tick delay)
+ {
+ Tick when = curTick + delay * Clock::Int::ns;
+ SimExit(when, "m5_exit instruction encountered");
+ }
+
+ void
+ resetstats(ExecContext *xc, Tick delay, Tick period)
+ {
+ if (!doStatisticsInsts)
+ return;
+
+
+ Tick when = curTick + delay * Clock::Int::ns;
+ Tick repeat = period * Clock::Int::ns;
+
+ using namespace Stats;
+ SetupEvent(Reset, when, repeat);
+ }
+
+ void
+ dumpstats(ExecContext *xc, Tick delay, Tick period)
+ {
+ if (!doStatisticsInsts)
+ return;
+
+
+ Tick when = curTick + delay * Clock::Int::ns;
+ Tick repeat = period * Clock::Int::ns;
+
+ using namespace Stats;
+ SetupEvent(Dump, when, repeat);
+ }
+
+ void
+ addsymbol(ExecContext *xc, Addr addr, Addr symbolAddr)
+ {
+ char symb[100];
+ CopyStringOut(xc, symb, symbolAddr, 100);
+ std::string symbol(symb);
+
+ DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr);
+
+ xc->getSystemPtr()->kernelSymtab->insert(addr,symbol);
+ }
+
+ void
+ dumpresetstats(ExecContext *xc, Tick delay, Tick period)
+ {
+ if (!doStatisticsInsts)
+ return;
+
+
+ Tick when = curTick + delay * Clock::Int::ns;
+ Tick repeat = period * Clock::Int::ns;
+
+ using namespace Stats;
+ SetupEvent(Dump|Reset, when, repeat);
+ }
+
+ void
+ m5checkpoint(ExecContext *xc, Tick delay, Tick period)
+ {
+ if (!doCheckpointInsts)
+ return;
+
+
+ Tick when = curTick + delay * Clock::Int::ns;
+ Tick repeat = period * Clock::Int::ns;
+
+ Checkpoint::setup(when, repeat);
+ }
+
+ uint64_t
+ readfile(ExecContext *xc, Addr vaddr, uint64_t len, uint64_t offset)
+ {
+ const string &file = xc->getCpuPtr()->system->params()->readfile;
+ if (file.empty()) {
+ return ULL(0);
+ }
+
+ uint64_t result = 0;
+
+ int fd = ::open(file.c_str(), O_RDONLY, 0);
+ if (fd < 0)
+ panic("could not open file %s\n", file);
+
+ if (::lseek(fd, offset, SEEK_SET) < 0)
+ panic("could not seek: %s", strerror(errno));
+
+ char *buf = new char[len];
+ char *p = buf;
+ while (len > 0) {
+ int bytes = ::read(fd, p, len);
+ if (bytes <= 0)
+ break;
+
+ p += bytes;
+ result += bytes;
+ len -= bytes;
+ }
+
+ close(fd);
+ CopyIn(xc, vaddr, buf, result);
+ delete [] buf;
+ return result;
+ }
+
+ class Context : public ParamContext
+ {
+ public:
+ Context(const string &section) : ParamContext(section) {}
+ void checkParams();
+ };
+
+ Context context("pseudo_inst");
+
+ Param<bool> __quiesce(&context, "quiesce",
+ "enable quiesce instructions",
+ true);
+ Param<bool> __statistics(&context, "statistics",
+ "enable statistics pseudo instructions",
+ true);
+ Param<bool> __checkpoint(&context, "checkpoint",
+ "enable checkpoint pseudo instructions",
+ true);
+
+ void
+ Context::checkParams()
+ {
+ doQuiesce = __quiesce;
+ doStatisticsInsts = __statistics;
+ doCheckpointInsts = __checkpoint;
+ }
+
+ void debugbreak(ExecContext *xc)
+ {
+ debug_break();
+ }
+
+ void switchcpu(ExecContext *xc)
+ {
+ if (SampCPU)
+ SampCPU->switchCPUs();
+ }
+}
diff --git a/src/sim/pseudo_inst.hh b/src/sim/pseudo_inst.hh
new file mode 100644
index 000000000..4dd427c99
--- /dev/null
+++ b/src/sim/pseudo_inst.hh
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2003-2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+class ExecContext;
+
+//We need the "Tick" data type from here
+#include "sim/host.hh"
+//We need the "Addr" data type from here
+#include "arch/isa_traits.hh"
+
+namespace AlphaPseudo
+{
+ /**
+ * @todo these externs are only here for a hack in fullCPU::takeOver...
+ */
+ extern bool doStatisticsInsts;
+ extern bool doCheckpointInsts;
+ extern bool doQuiesce;
+
+ void arm(ExecContext *xc);
+ void quiesce(ExecContext *xc);
+ void quiesceNs(ExecContext *xc, uint64_t ns);
+ void quiesceCycles(ExecContext *xc, uint64_t cycles);
+ uint64_t quiesceTime(ExecContext *xc);
+ void ivlb(ExecContext *xc);
+ void ivle(ExecContext *xc);
+ void m5exit(ExecContext *xc, Tick delay);
+ void m5exit_old(ExecContext *xc);
+ void resetstats(ExecContext *xc, Tick delay, Tick period);
+ void dumpstats(ExecContext *xc, Tick delay, Tick period);
+ void dumpresetstats(ExecContext *xc, Tick delay, Tick period);
+ void m5checkpoint(ExecContext *xc, Tick delay, Tick period);
+ uint64_t readfile(ExecContext *xc, Addr vaddr, uint64_t len, uint64_t offset);
+ void debugbreak(ExecContext *xc);
+ void switchcpu(ExecContext *xc);
+ void addsymbol(ExecContext *xc, Addr addr, Addr symbolAddr);
+}
diff --git a/src/sim/root.cc b/src/sim/root.cc
new file mode 100644
index 000000000..6348ec104
--- /dev/null
+++ b/src/sim/root.cc
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <cstring>
+#include <fstream>
+#include <list>
+#include <string>
+#include <vector>
+
+#include "base/misc.hh"
+#include "base/output.hh"
+#include "sim/builder.hh"
+#include "sim/host.hh"
+#include "sim/sim_events.hh"
+#include "sim/sim_object.hh"
+#include "sim/root.hh"
+
+using namespace std;
+
+Tick curTick = 0;
+ostream *outputStream;
+ostream *configStream;
+
+/// The simulated frequency of curTick. (This is only here for a short time)
+Tick ticksPerSecond;
+
+namespace Clock {
+/// The simulated frequency of curTick. (In ticks per second)
+Tick Frequency;
+
+namespace Float {
+double s;
+double ms;
+double us;
+double ns;
+double ps;
+
+double Hz;
+double kHz;
+double MHz;
+double GHZ;
+/* namespace Float */ }
+
+namespace Int {
+Tick s;
+Tick ms;
+Tick us;
+Tick ns;
+Tick ps;
+/* namespace Float */ }
+
+/* namespace Clock */ }
+
+
+// Dummy Object
+class Root : public SimObject
+{
+ private:
+ Tick max_tick;
+ Tick progress_interval;
+
+ public:
+ Root(const std::string &name, Tick maxtick, Tick pi)
+ : SimObject(name), max_tick(maxtick), progress_interval(pi)
+ {}
+
+ virtual void startup();
+};
+
+void
+Root::startup()
+{
+ if (max_tick != 0)
+ new SimExitEvent(curTick + max_tick, "reached maximum cycle count");
+
+ if (progress_interval != 0)
+ new ProgressEvent(&mainEventQueue, progress_interval);
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(Root)
+
+ Param<Tick> clock;
+ Param<Tick> max_tick;
+ Param<Tick> progress_interval;
+ Param<string> output_file;
+
+END_DECLARE_SIM_OBJECT_PARAMS(Root)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(Root)
+
+ INIT_PARAM(clock, "tick frequency"),
+ INIT_PARAM(max_tick, "maximum simulation time"),
+ INIT_PARAM(progress_interval, "print a progress message"),
+ INIT_PARAM(output_file, "file to dump simulator output to")
+
+END_INIT_SIM_OBJECT_PARAMS(Root)
+
+CREATE_SIM_OBJECT(Root)
+{
+ static bool created = false;
+ if (created)
+ panic("only one root object allowed!");
+
+ created = true;
+
+ outputStream = simout.find(output_file);
+ Root *root = new Root(getInstanceName(), max_tick, progress_interval);
+
+ using namespace Clock;
+ Frequency = clock;
+ Float::s = static_cast<double>(Frequency);
+ Float::ms = Float::s / 1.0e3;
+ Float::us = Float::s / 1.0e6;
+ Float::ns = Float::s / 1.0e9;
+ Float::ps = Float::s / 1.0e12;
+
+ Float::Hz = 1.0 / Float::s;
+ Float::kHz = 1.0 / Float::ms;
+ Float::MHz = 1.0 / Float::us;
+ Float::GHZ = 1.0 / Float::ns;
+
+ Int::s = Frequency;
+ Int::ms = Int::s / 1000;
+ Int::us = Int::ms / 1000;
+ Int::ns = Int::us / 1000;
+ Int::ps = Int::ns / 1000;
+
+ return root;
+}
+
+REGISTER_SIM_OBJECT("Root", Root)
diff --git a/src/sim/serialize.cc b/src/sim/serialize.cc
new file mode 100644
index 000000000..c4ef124bb
--- /dev/null
+++ b/src/sim/serialize.cc
@@ -0,0 +1,484 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#include <fstream>
+#include <list>
+#include <string>
+#include <vector>
+
+#include "base/inifile.hh"
+#include "base/misc.hh"
+#include "base/output.hh"
+#include "base/str.hh"
+#include "base/trace.hh"
+#include "sim/config_node.hh"
+#include "sim/eventq.hh"
+#include "sim/param.hh"
+#include "sim/serialize.hh"
+#include "sim/sim_events.hh"
+#include "sim/sim_exit.hh"
+#include "sim/sim_object.hh"
+
+using namespace std;
+
+int Serializable::ckptMaxCount = 0;
+int Serializable::ckptCount = 0;
+int Serializable::ckptPrevCount = -1;
+
+void
+Serializable::nameOut(ostream &os)
+{
+ os << "\n[" << name() << "]\n";
+}
+
+void
+Serializable::nameOut(ostream &os, const string &_name)
+{
+ os << "\n[" << _name << "]\n";
+}
+
+template <class T>
+void
+paramOut(ostream &os, const std::string &name, const T &param)
+{
+ os << name << "=";
+ showParam(os, param);
+ os << "\n";
+}
+
+
+template <class T>
+void
+paramIn(Checkpoint *cp, const std::string &section,
+ const std::string &name, T &param)
+{
+ std::string str;
+ if (!cp->find(section, name, str) || !parseParam(str, param)) {
+ fatal("Can't unserialize '%s:%s'\n", section, name);
+ }
+}
+
+
+template <class T>
+void
+arrayParamOut(ostream &os, const std::string &name,
+ const T *param, int size)
+{
+ os << name << "=";
+ if (size > 0)
+ showParam(os, param[0]);
+ for (int i = 1; i < size; ++i) {
+ os << " ";
+ showParam(os, param[i]);
+ }
+ os << "\n";
+}
+
+
+template <class T>
+void
+arrayParamIn(Checkpoint *cp, const std::string &section,
+ const std::string &name, T *param, int size)
+{
+ std::string str;
+ if (!cp->find(section, name, str)) {
+ fatal("Can't unserialize '%s:%s'\n", section, name);
+ }
+
+ // code below stolen from VectorParam<T>::parse().
+ // it would be nice to unify these somehow...
+
+ vector<string> tokens;
+
+ tokenize(tokens, str, ' ');
+
+ // Need this if we were doing a vector
+ // value.resize(tokens.size());
+
+ if (tokens.size() != size) {
+ fatal("Array size mismatch on %s:%s'\n", section, name);
+ }
+
+ for (int i = 0; i < tokens.size(); i++) {
+ // need to parse into local variable to handle vector<bool>,
+ // for which operator[] returns a special reference class
+ // that's not the same as 'bool&', (since it's a packed
+ // vector)
+ T scalar_value;
+ if (!parseParam(tokens[i], scalar_value)) {
+ string err("could not parse \"");
+
+ err += str;
+ err += "\"";
+
+ fatal(err);
+ }
+
+ // assign parsed value to vector
+ param[i] = scalar_value;
+ }
+}
+
+
+void
+objParamIn(Checkpoint *cp, const std::string &section,
+ const std::string &name, Serializable * &param)
+{
+ if (!cp->findObj(section, name, param)) {
+ fatal("Can't unserialize '%s:%s'\n", section, name);
+ }
+}
+
+
+#define INSTANTIATE_PARAM_TEMPLATES(type) \
+template void \
+paramOut(ostream &os, const std::string &name, type const &param); \
+template void \
+paramIn(Checkpoint *cp, const std::string &section, \
+ const std::string &name, type & param); \
+template void \
+arrayParamOut(ostream &os, const std::string &name, \
+ type const *param, int size); \
+template void \
+arrayParamIn(Checkpoint *cp, const std::string &section, \
+ const std::string &name, type *param, int size);
+
+INSTANTIATE_PARAM_TEMPLATES(signed char)
+INSTANTIATE_PARAM_TEMPLATES(unsigned char)
+INSTANTIATE_PARAM_TEMPLATES(signed short)
+INSTANTIATE_PARAM_TEMPLATES(unsigned short)
+INSTANTIATE_PARAM_TEMPLATES(signed int)
+INSTANTIATE_PARAM_TEMPLATES(unsigned int)
+INSTANTIATE_PARAM_TEMPLATES(signed long)
+INSTANTIATE_PARAM_TEMPLATES(unsigned long)
+INSTANTIATE_PARAM_TEMPLATES(signed long long)
+INSTANTIATE_PARAM_TEMPLATES(unsigned long long)
+INSTANTIATE_PARAM_TEMPLATES(bool)
+INSTANTIATE_PARAM_TEMPLATES(string)
+
+
+/////////////////////////////
+
+/// Container for serializing global variables (not associated with
+/// any serialized object).
+class Globals : public Serializable
+{
+ public:
+ const string name() const;
+ void serialize(ostream &os);
+ void unserialize(Checkpoint *cp);
+};
+
+/// The one and only instance of the Globals class.
+Globals globals;
+
+const string
+Globals::name() const
+{
+ return "Globals";
+}
+
+void
+Globals::serialize(ostream &os)
+{
+ nameOut(os);
+ SERIALIZE_SCALAR(curTick);
+
+ nameOut(os, "MainEventQueue");
+ mainEventQueue.serialize(os);
+}
+
+void
+Globals::unserialize(Checkpoint *cp)
+{
+ const string &section = name();
+ UNSERIALIZE_SCALAR(curTick);
+
+ mainEventQueue.unserialize(cp, "MainEventQueue");
+}
+
+void
+Serializable::serializeAll()
+{
+ string dir = Checkpoint::dir();
+ if (mkdir(dir.c_str(), 0775) == -1 && errno != EEXIST)
+ fatal("couldn't mkdir %s\n", dir);
+
+ string cpt_file = dir + Checkpoint::baseFilename;
+ ofstream outstream(cpt_file.c_str());
+ time_t t = time(NULL);
+ outstream << "// checkpoint generated: " << ctime(&t);
+
+ globals.serialize(outstream);
+ SimObject::serializeAll(outstream);
+
+ assert(Serializable::ckptPrevCount + 1 == Serializable::ckptCount);
+ Serializable::ckptPrevCount++;
+ if (ckptMaxCount && ++ckptCount >= ckptMaxCount)
+ SimExit(curTick + 1, "Maximum number of checkpoints dropped");
+
+}
+
+
+void
+Serializable::unserializeGlobals(Checkpoint *cp)
+{
+ globals.unserialize(cp);
+}
+
+
+class SerializeEvent : public Event
+{
+ protected:
+ Tick repeat;
+
+ public:
+ SerializeEvent(Tick _when, Tick _repeat);
+ virtual void process();
+ virtual void serialize(std::ostream &os)
+ {
+ panic("Cannot serialize the SerializeEvent");
+ }
+
+};
+
+SerializeEvent::SerializeEvent(Tick _when, Tick _repeat)
+ : Event(&mainEventQueue, Serialize_Pri), repeat(_repeat)
+{
+ setFlags(AutoDelete);
+ schedule(_when);
+}
+
+void
+SerializeEvent::process()
+{
+ Serializable::serializeAll();
+ if (repeat)
+ schedule(curTick + repeat);
+}
+
+const char *Checkpoint::baseFilename = "m5.cpt";
+
+static string checkpointDirBase;
+
+string
+Checkpoint::dir()
+{
+ // use csprintf to insert curTick into directory name if it
+ // appears to have a format placeholder in it.
+ return (checkpointDirBase.find("%") != string::npos) ?
+ csprintf(checkpointDirBase, curTick) : checkpointDirBase;
+}
+
+void
+Checkpoint::setup(Tick when, Tick period)
+{
+ new SerializeEvent(when, period);
+}
+
+class SerializeParamContext : public ParamContext
+{
+ private:
+ SerializeEvent *event;
+
+ public:
+ SerializeParamContext(const string &section);
+ ~SerializeParamContext();
+ void checkParams();
+};
+
+SerializeParamContext serialParams("serialize");
+
+Param<string> serialize_dir(&serialParams, "dir",
+ "dir to stick checkpoint in "
+ "(sprintf format with cycle #)");
+
+Param<Counter> serialize_cycle(&serialParams,
+ "cycle",
+ "cycle to serialize",
+ 0);
+
+Param<Counter> serialize_period(&serialParams,
+ "period",
+ "period to repeat serializations",
+ 0);
+
+Param<int> serialize_count(&serialParams, "count",
+ "maximum number of checkpoints to drop");
+
+SerializeParamContext::SerializeParamContext(const string &section)
+ : ParamContext(section), event(NULL)
+{ }
+
+SerializeParamContext::~SerializeParamContext()
+{
+}
+
+void
+SerializeParamContext::checkParams()
+{
+ checkpointDirBase = simout.resolve(serialize_dir);
+
+ // guarantee that directory ends with a '/'
+ if (checkpointDirBase[checkpointDirBase.size() - 1] != '/')
+ checkpointDirBase += "/";
+
+ if (serialize_cycle > 0)
+ Checkpoint::setup(serialize_cycle, serialize_period);
+
+ Serializable::ckptMaxCount = serialize_count;
+}
+
+void
+debug_serialize()
+{
+ Serializable::serializeAll();
+}
+
+void
+debug_serialize(Tick when)
+{
+ new SerializeEvent(when, 0);
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// SerializableClass member definitions
+//
+////////////////////////////////////////////////////////////////////////
+
+// Map of class names to SerializableBuilder creation functions.
+// Need to make this a pointer so we can force initialization on the
+// first reference; otherwise, some SerializableClass constructors
+// may be invoked before the classMap constructor.
+map<string,SerializableClass::CreateFunc> *SerializableClass::classMap = 0;
+
+// SerializableClass constructor: add mapping to classMap
+SerializableClass::SerializableClass(const string &className,
+ CreateFunc createFunc)
+{
+ if (classMap == NULL)
+ classMap = new map<string,SerializableClass::CreateFunc>();
+
+ if ((*classMap)[className])
+ {
+ cerr << "Error: simulation object class " << className << " redefined"
+ << endl;
+ fatal("");
+ }
+
+ // add className --> createFunc to class map
+ (*classMap)[className] = createFunc;
+}
+
+
+//
+//
+Serializable *
+SerializableClass::createObject(Checkpoint *cp,
+ const std::string &section)
+{
+ string className;
+
+ if (!cp->find(section, "type", className)) {
+ fatal("Serializable::create: no 'type' entry in section '%s'.\n",
+ section);
+ }
+
+ CreateFunc createFunc = (*classMap)[className];
+
+ if (createFunc == NULL) {
+ fatal("Serializable::create: no create function for class '%s'.\n",
+ className);
+ }
+
+ Serializable *object = createFunc(cp, section);
+
+ assert(object != NULL);
+
+ return object;
+}
+
+
+Serializable *
+Serializable::create(Checkpoint *cp, const std::string &section)
+{
+ Serializable *object = SerializableClass::createObject(cp, section);
+ object->unserialize(cp, section);
+ return object;
+}
+
+
+Checkpoint::Checkpoint(const std::string &cpt_dir, const std::string &path,
+ const ConfigNode *_configNode)
+ : db(new IniFile), basePath(path), configNode(_configNode), cptDir(cpt_dir)
+{
+ string filename = cpt_dir + "/" + Checkpoint::baseFilename;
+ if (!db->load(filename)) {
+ fatal("Can't load checkpoint file '%s'\n", filename);
+ }
+}
+
+
+bool
+Checkpoint::find(const std::string &section, const std::string &entry,
+ std::string &value)
+{
+ return db->find(section, entry, value);
+}
+
+
+bool
+Checkpoint::findObj(const std::string &section, const std::string &entry,
+ Serializable *&value)
+{
+ string path;
+
+ if (!db->find(section, entry, path))
+ return false;
+
+ if ((value = configNode->resolveSimObject(path)) != NULL)
+ return true;
+
+ if ((value = objMap[path]) != NULL)
+ return true;
+
+ return false;
+}
+
+
+bool
+Checkpoint::sectionExists(const std::string &section)
+{
+ return db->sectionExists(section);
+}
diff --git a/src/sim/serialize.hh b/src/sim/serialize.hh
new file mode 100644
index 000000000..d8f5f8fc5
--- /dev/null
+++ b/src/sim/serialize.hh
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* @file
+ * Serialization Interface Declarations
+ */
+
+#ifndef __SERIALIZE_HH__
+#define __SERIALIZE_HH__
+
+
+#include <list>
+#include <iostream>
+#include <map>
+
+#include "sim/host.hh"
+#include "sim/configfile.hh"
+
+class Serializable;
+class Checkpoint;
+
+template <class T>
+void paramOut(std::ostream &os, const std::string &name, const T &param);
+
+template <class T>
+void paramIn(Checkpoint *cp, const std::string &section,
+ const std::string &name, T &param);
+
+template <class T>
+void arrayParamOut(std::ostream &os, const std::string &name,
+ const T *param, int size);
+
+template <class T>
+void arrayParamIn(Checkpoint *cp, const std::string &section,
+ const std::string &name, T *param, int size);
+
+void
+objParamIn(Checkpoint *cp, const std::string &section,
+ const std::string &name, Serializable * &param);
+
+
+//
+// These macros are streamlined to use in serialize/unserialize
+// functions. It's assumed that serialize() has a parameter 'os' for
+// the ostream, and unserialize() has parameters 'cp' and 'section'.
+#define SERIALIZE_SCALAR(scalar) paramOut(os, #scalar, scalar)
+
+#define UNSERIALIZE_SCALAR(scalar) paramIn(cp, section, #scalar, scalar)
+
+// ENUMs are like SCALARs, but we cast them to ints on the way out
+#define SERIALIZE_ENUM(scalar) paramOut(os, #scalar, (int)scalar)
+
+#define UNSERIALIZE_ENUM(scalar) \
+ do { \
+ int tmp; \
+ paramIn(cp, section, #scalar, tmp); \
+ scalar = (typeof(scalar))tmp; \
+ } while (0)
+
+#define SERIALIZE_ARRAY(member, size) \
+ arrayParamOut(os, #member, member, size)
+
+#define UNSERIALIZE_ARRAY(member, size) \
+ arrayParamIn(cp, section, #member, member, size)
+
+#define SERIALIZE_OBJPTR(objptr) paramOut(os, #objptr, (objptr)->name())
+
+#define UNSERIALIZE_OBJPTR(objptr) \
+ do { \
+ Serializable *sptr; \
+ objParamIn(cp, section, #objptr, sptr); \
+ objptr = dynamic_cast<typeof(objptr)>(sptr); \
+ } while (0)
+
+/*
+ * Basic support for object serialization.
+ */
+class Serializable
+{
+ protected:
+ void nameOut(std::ostream &os);
+ void nameOut(std::ostream &os, const std::string &_name);
+
+ public:
+ Serializable() {}
+ virtual ~Serializable() {}
+
+ // manditory virtual function, so objects must provide names
+ virtual const std::string name() const = 0;
+
+ virtual void serialize(std::ostream &os) {}
+ virtual void unserialize(Checkpoint *cp, const std::string &section) {}
+
+ static Serializable *create(Checkpoint *cp,
+ const std::string &section);
+
+ static int ckptCount;
+ static int ckptMaxCount;
+ static int ckptPrevCount;
+ static void serializeAll();
+ static void unserializeGlobals(Checkpoint *cp);
+};
+
+//
+// A SerializableBuilder serves as an evaluation context for a set of
+// parameters that describe a specific instance of a Serializable. This
+// evaluation context corresponds to a section in the .ini file (as
+// with the base ParamContext) plus an optional node in the
+// configuration hierarchy (the configNode member) for resolving
+// Serializable references. SerializableBuilder is an abstract superclass;
+// derived classes specialize the class for particular subclasses of
+// Serializable (e.g., BaseCache).
+//
+// For typical usage, see the definition of
+// SerializableClass::createObject().
+//
+class SerializableBuilder
+{
+ public:
+
+ SerializableBuilder() {}
+
+ virtual ~SerializableBuilder() {}
+
+ // Create the actual Serializable corresponding to the parameter
+ // values in this context. This function is overridden in derived
+ // classes to call a specific constructor for a particular
+ // subclass of Serializable.
+ virtual Serializable *create() = 0;
+};
+
+//
+// An instance of SerializableClass corresponds to a class derived from
+// Serializable. The SerializableClass instance serves to bind the string
+// name (found in the config file) to a function that creates an
+// instance of the appropriate derived class.
+//
+// This would be much cleaner in Smalltalk or Objective-C, where types
+// are first-class objects themselves.
+//
+class SerializableClass
+{
+ public:
+
+ // Type CreateFunc is a pointer to a function that creates a new
+ // simulation object builder based on a .ini-file parameter
+ // section (specified by the first string argument), a unique name
+ // for the object (specified by the second string argument), and
+ // an optional config hierarchy node (specified by the third
+ // argument). A pointer to the new SerializableBuilder is returned.
+ typedef Serializable *(*CreateFunc)(Checkpoint *cp,
+ const std::string &section);
+
+ static std::map<std::string,CreateFunc> *classMap;
+
+ // Constructor. For example:
+ //
+ // SerializableClass baseCacheSerializableClass("BaseCacheSerializable",
+ // newBaseCacheSerializableBuilder);
+ //
+ SerializableClass(const std::string &className, CreateFunc createFunc);
+
+ // create Serializable given name of class and pointer to
+ // configuration hierarchy node
+ static Serializable *createObject(Checkpoint *cp,
+ const std::string &section);
+};
+
+//
+// Macros to encapsulate the magic of declaring & defining
+// SerializableBuilder and SerializableClass objects
+//
+
+#define REGISTER_SERIALIZEABLE(CLASS_NAME, OBJ_CLASS) \
+SerializableClass the##OBJ_CLASS##Class(CLASS_NAME, \
+ OBJ_CLASS::createForUnserialize);
+
+class Checkpoint
+{
+ private:
+
+ IniFile *db;
+ const std::string basePath;
+ const ConfigNode *configNode;
+ std::map<std::string, Serializable*> objMap;
+
+ public:
+ Checkpoint(const std::string &cpt_dir, const std::string &path,
+ const ConfigNode *_configNode);
+
+ const std::string cptDir;
+
+ bool find(const std::string &section, const std::string &entry,
+ std::string &value);
+
+ bool findObj(const std::string &section, const std::string &entry,
+ Serializable *&value);
+
+ bool sectionExists(const std::string &section);
+
+ // The following static functions have to do with checkpoint
+ // creation rather than restoration. This class makes a handy
+ // namespace for them though.
+
+ // Export current checkpoint directory name so other objects can
+ // derive filenames from it (e.g., memory). The return value is
+ // guaranteed to end in '/' so filenames can be directly appended.
+ // This function is only valid while a checkpoint is being created.
+ static std::string dir();
+
+ // Filename for base checkpoint file within directory.
+ static const char *baseFilename;
+
+ // Set up a checkpoint creation event or series of events.
+ static void setup(Tick when, Tick period = 0);
+};
+
+#endif // __SERIALIZE_HH__
diff --git a/src/sim/sim_events.cc b/src/sim/sim_events.cc
new file mode 100644
index 000000000..c2bdca9df
--- /dev/null
+++ b/src/sim/sim_events.cc
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string>
+
+#include "base/callback.hh"
+#include "base/hostinfo.hh"
+#include "sim/eventq.hh"
+#include "sim/param.hh"
+#include "sim/sim_events.hh"
+#include "sim/sim_exit.hh"
+#include "sim/startup.hh"
+#include "sim/stats.hh"
+
+using namespace std;
+
+//
+// handle termination event
+//
+void
+SimExitEvent::process()
+{
+ // This event does not autodelete because exitNow may be called,
+ // and the function will never be allowed to finish.
+ if (theQueue() == &mainEventQueue) {
+ string _cause = cause;
+ int _code = code;
+ delete this;
+ exitNow(_cause, _code);
+ } else {
+ new SimExitEvent(cause, code);
+ delete this;
+ }
+}
+
+
+const char *
+SimExitEvent::description()
+{
+ return "simulation termination";
+}
+
+//
+// constructor: automatically schedules at specified time
+//
+CountedExitEvent::CountedExitEvent(EventQueue *q, const std::string &_cause,
+ Tick _when, int &_downCounter)
+ : Event(q, Sim_Exit_Pri),
+ cause(_cause),
+ downCounter(_downCounter)
+{
+ // catch stupid mistakes
+ assert(downCounter > 0);
+
+ schedule(_when);
+}
+
+
+//
+// handle termination event
+//
+void
+CountedExitEvent::process()
+{
+ if (--downCounter == 0) {
+ new SimExitEvent(cause, 0);
+ }
+}
+
+
+const char *
+CountedExitEvent::description()
+{
+ return "counted exit";
+}
+
+#ifdef CHECK_SWAP_CYCLES
+new CheckSwapEvent(&mainEventQueue, CHECK_SWAP_CYCLES);
+#endif
+
+void
+CheckSwapEvent::process()
+{
+ /* Check the amount of free swap space */
+ long swap;
+
+ /* returns free swap in KBytes */
+ swap = procInfo("/proc/meminfo", "SwapFree:");
+
+ if (swap < 1000)
+ ccprintf(cerr, "\a\a\aWarning! Swap space is low (%d)\n", swap);
+
+ if (swap < 100) {
+ cerr << "\a\aAborting Simulation! Inadequate swap space!\n\n";
+ new SimExitEvent("Lack of swap space");
+ }
+
+ schedule(curTick + interval);
+}
+
+const char *
+CheckSwapEvent::description()
+{
+ return "check swap";
+}
+
+//
+// handle progress event: print message and reschedule
+//
+void
+ProgressEvent::process()
+{
+ DPRINTFN("ProgressEvent\n");
+ // reschedule for next interval
+ schedule(curTick + interval);
+}
+
+
+const char *
+ProgressEvent::description()
+{
+ return "progress message";
+}
diff --git a/src/sim/sim_events.hh b/src/sim/sim_events.hh
new file mode 100644
index 000000000..c93914457
--- /dev/null
+++ b/src/sim/sim_events.hh
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SIM_SIM_EVENTS_HH__
+#define __SIM_SIM_EVENTS_HH__
+
+#include "sim/eventq.hh"
+
+//
+// Event to terminate simulation at a particular cycle/instruction
+//
+class SimExitEvent : public Event
+{
+ private:
+ // string explaining why we're terminating
+ std::string cause;
+ int code;
+
+ public:
+ SimExitEvent(const std::string &_cause, int c = 0)
+ : Event(&mainEventQueue, Sim_Exit_Pri), cause(_cause),
+ code(c)
+ { schedule(curTick); }
+
+ SimExitEvent(Tick _when, const std::string &_cause, int c = 0)
+ : Event(&mainEventQueue, Sim_Exit_Pri), cause(_cause),
+ code(c)
+ { schedule(_when); }
+
+ SimExitEvent(EventQueue *q, const std::string &_cause, int c = 0)
+ : Event(q, Sim_Exit_Pri), cause(_cause), code(c)
+ { schedule(curTick); }
+
+ SimExitEvent(EventQueue *q, Tick _when, const std::string &_cause,
+ int c = 0)
+ : Event(q, Sim_Exit_Pri), cause(_cause), code(c)
+ { schedule(_when); }
+
+ void process(); // process event
+
+ virtual const char *description();
+};
+
+//
+// Event class to terminate simulation after 'n' related events have
+// occurred using a shared counter: used to terminate when *all*
+// threads have reached a particular instruction count
+//
+class CountedExitEvent : public Event
+{
+ private:
+ std::string cause; // string explaining why we're terminating
+ int &downCounter; // decrement & terminate if zero
+
+ public:
+ CountedExitEvent(EventQueue *q, const std::string &_cause,
+ Tick _when, int &_downCounter);
+
+ void process(); // process event
+
+ virtual const char *description();
+};
+
+//
+// Event to check swap usage
+//
+class CheckSwapEvent : public Event
+{
+ private:
+ int interval;
+
+ public:
+ CheckSwapEvent(EventQueue *q, int ival)
+ : Event(q), interval(ival)
+ { schedule(curTick + interval); }
+
+ void process(); // process event
+
+ virtual const char *description();
+};
+
+//
+// Progress event: print out cycle every so often so we know we're
+// making forward progress.
+//
+class ProgressEvent : public Event
+{
+ protected:
+ Tick interval;
+
+ public:
+ ProgressEvent(EventQueue *q, Tick ival)
+ : Event(q), interval(ival)
+ { schedule(curTick + interval); }
+
+ void process(); // process event
+
+ virtual const char *description();
+};
+
+#endif // __SIM_SIM_EVENTS_HH__
diff --git a/src/sim/sim_exit.hh b/src/sim/sim_exit.hh
new file mode 100644
index 000000000..f14256933
--- /dev/null
+++ b/src/sim/sim_exit.hh
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SIM_EXIT_HH__
+#define __SIM_EXIT_HH__
+
+#include <string>
+
+#include "sim/host.hh"
+
+class Callback;
+
+void registerExitCallback(Callback *);
+
+void exitNow(const std::string &cause, int exit_code);
+void exitNow(const char *cause, int exit_code);
+void SimExit(Tick when, const char *message);
+
+#endif // __SIM_EXIT_HH__
diff --git a/src/sim/sim_object.cc b/src/sim/sim_object.cc
new file mode 100644
index 000000000..17d58ba4f
--- /dev/null
+++ b/src/sim/sim_object.cc
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <assert.h>
+
+#include "base/callback.hh"
+#include "base/inifile.hh"
+#include "base/match.hh"
+#include "base/misc.hh"
+#include "base/trace.hh"
+#include "base/stats/events.hh"
+#include "base/serializer.hh"
+#include "sim/configfile.hh"
+#include "sim/host.hh"
+#include "sim/sim_object.hh"
+#include "sim/stats.hh"
+#include "sim/param.hh"
+
+using namespace std;
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// SimObject member definitions
+//
+////////////////////////////////////////////////////////////////////////
+
+//
+// static list of all SimObjects, used for initialization etc.
+//
+SimObject::SimObjectList SimObject::simObjectList;
+
+namespace Stats {
+ extern ObjectMatch event_ignore;
+}
+
+//
+// SimObject constructor: used to maintain static simObjectList
+//
+SimObject::SimObject(Params *p)
+ : _params(p)
+{
+#ifdef DEBUG
+ doDebugBreak = false;
+#endif
+
+ doRecordEvent = !Stats::event_ignore.match(name());
+ simObjectList.push_back(this);
+}
+
+//
+// SimObject constructor: used to maintain static simObjectList
+//
+SimObject::SimObject(const string &_name)
+ : _params(new Params)
+{
+ _params->name = _name;
+#ifdef DEBUG
+ doDebugBreak = false;
+#endif
+
+ doRecordEvent = !Stats::event_ignore.match(name());
+ simObjectList.push_back(this);
+}
+
+void
+SimObject::connect()
+{
+}
+
+void
+SimObject::init()
+{
+}
+
+//
+// no default statistics, so nothing to do in base implementation
+//
+void
+SimObject::regStats()
+{
+}
+
+void
+SimObject::regFormulas()
+{
+}
+
+void
+SimObject::resetStats()
+{
+}
+
+//
+// static function:
+// call regStats() on all SimObjects and then regFormulas() on all
+// SimObjects.
+//
+struct SimObjectResetCB : public Callback
+{
+ virtual void process() { SimObject::resetAllStats(); }
+};
+
+namespace {
+ static SimObjectResetCB StatResetCB;
+}
+
+void
+SimObject::regAllStats()
+{
+ SimObjectList::iterator i;
+ SimObjectList::iterator end = simObjectList.end();
+
+ /**
+ * @todo change cprintfs to DPRINTFs
+ */
+ for (i = simObjectList.begin(); i != end; ++i) {
+#ifdef STAT_DEBUG
+ cprintf("registering stats for %s\n", (*i)->name());
+#endif
+ (*i)->regStats();
+ }
+
+ for (i = simObjectList.begin(); i != end; ++i) {
+#ifdef STAT_DEBUG
+ cprintf("registering formulas for %s\n", (*i)->name());
+#endif
+ (*i)->regFormulas();
+ }
+
+ Stats::registerResetCallback(&StatResetCB);
+}
+
+//
+// static function: call connect() on all SimObjects.
+//
+void
+SimObject::connectAll()
+{
+ SimObjectList::iterator i = simObjectList.begin();
+ SimObjectList::iterator end = simObjectList.end();
+
+ for (; i != end; ++i) {
+ SimObject *obj = *i;
+ obj->connect();
+ }
+}
+
+//
+// static function: call init() on all SimObjects.
+//
+void
+SimObject::initAll()
+{
+ SimObjectList::iterator i = simObjectList.begin();
+ SimObjectList::iterator end = simObjectList.end();
+
+ for (; i != end; ++i) {
+ SimObject *obj = *i;
+ obj->init();
+ }
+}
+
+//
+// static function: call resetStats() on all SimObjects.
+//
+void
+SimObject::resetAllStats()
+{
+ SimObjectList::iterator i = simObjectList.begin();
+ SimObjectList::iterator end = simObjectList.end();
+
+ for (; i != end; ++i) {
+ SimObject *obj = *i;
+ obj->resetStats();
+ }
+}
+
+//
+// static function: serialize all SimObjects.
+//
+void
+SimObject::serializeAll(ostream &os)
+{
+ SimObjectList::reverse_iterator ri = simObjectList.rbegin();
+ SimObjectList::reverse_iterator rend = simObjectList.rend();
+
+ for (; ri != rend; ++ri) {
+ SimObject *obj = *ri;
+ obj->nameOut(os);
+ obj->serialize(os);
+ }
+}
+
+#ifdef DEBUG
+//
+// static function: flag which objects should have the debugger break
+//
+void
+SimObject::debugObjectBreak(const string &objs)
+{
+ SimObjectList::const_iterator i = simObjectList.begin();
+ SimObjectList::const_iterator end = simObjectList.end();
+
+ ObjectMatch match(objs);
+ for (; i != end; ++i) {
+ SimObject *obj = *i;
+ obj->doDebugBreak = match.match(obj->name());
+ }
+}
+
+extern "C"
+void
+debugObjectBreak(const char *objs)
+{
+ SimObject::debugObjectBreak(string(objs));
+}
+#endif
+
+void
+SimObject::recordEvent(const std::string &stat)
+{
+ if (doRecordEvent)
+ Stats::recordEvent(stat);
+}
+
+void
+SimObject::drain(Serializer *serializer)
+{
+ serializer->signalDrained();
+}
+
+DEFINE_SIM_OBJECT_CLASS_NAME("SimObject", SimObject)
diff --git a/src/sim/sim_object.hh b/src/sim/sim_object.hh
new file mode 100644
index 000000000..76aba7ea1
--- /dev/null
+++ b/src/sim/sim_object.hh
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* @file
+ * User Console Definitions
+ */
+
+#ifndef __SIM_OBJECT_HH__
+#define __SIM_OBJECT_HH__
+
+#include <map>
+#include <list>
+#include <vector>
+#include <iostream>
+
+#include "sim/serialize.hh"
+#include "sim/startup.hh"
+
+class Serializer;
+
+/*
+ * Abstract superclass for simulation objects. Represents things that
+ * correspond to physical components and can be specified via the
+ * config file (CPUs, caches, etc.).
+ */
+class SimObject : public Serializable, protected StartupCallback
+{
+ public:
+ struct Params {
+ std::string name;
+ };
+
+ protected:
+ Params *_params;
+
+ public:
+ const Params *params() const { return _params; }
+
+ private:
+ friend class Serializer;
+
+ typedef std::vector<SimObject *> SimObjectList;
+
+ // list of all instantiated simulation objects
+ static SimObjectList simObjectList;
+
+ public:
+ SimObject(Params *_params);
+ SimObject(const std::string &_name);
+
+ virtual ~SimObject() {}
+
+ virtual const std::string name() const { return params()->name; }
+
+ // initialization pass of all objects.
+ // Gets invoked after construction, before unserialize.
+ virtual void init();
+ virtual void connect();
+ static void initAll();
+ static void connectAll();
+
+ // register statistics for this object
+ virtual void regStats();
+ virtual void regFormulas();
+ virtual void resetStats();
+
+ // static: call reg_stats on all SimObjects
+ static void regAllStats();
+
+ // static: call resetStats on all SimObjects
+ static void resetAllStats();
+
+ // static: call nameOut() & serialize() on all SimObjects
+ static void serializeAll(std::ostream &);
+
+ // Methods to drain objects in order to take checkpoints
+ // Or switch from timing -> atomic memory model
+ virtual void drain(Serializer *serializer);
+ virtual void resume() { return;} ;
+ virtual void serializationComplete()
+ { assert(0 && "Unimplemented"); };
+
+#ifdef DEBUG
+ public:
+ bool doDebugBreak;
+ static void debugObjectBreak(const std::string &objs);
+#endif
+
+ public:
+ bool doRecordEvent;
+ void recordEvent(const std::string &stat);
+};
+
+#endif // __SIM_OBJECT_HH__
diff --git a/src/sim/startup.cc b/src/sim/startup.cc
new file mode 100644
index 000000000..683e6c746
--- /dev/null
+++ b/src/sim/startup.cc
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <list>
+
+#include "base/misc.hh"
+#include "sim/debug.hh"
+#include "sim/startup.hh"
+
+typedef std::list<StartupCallback *> startupq_t;
+
+startupq_t *startupq = NULL;
+
+StartupCallback::StartupCallback()
+{
+ if (startupq == NULL)
+ startupq = new startupq_t;
+ startupq->push_back(this);
+}
+
+StartupCallback::~StartupCallback()
+{
+ startupq->remove(this);
+}
+
+void StartupCallback::startup() { }
+
+void
+SimStartup()
+{
+ startupq_t::iterator i = startupq->begin();
+ startupq_t::iterator end = startupq->end();
+
+ while (i != end) {
+ (*i)->startup();
+ ++i;
+ }
+}
diff --git a/src/sim/startup.hh b/src/sim/startup.hh
new file mode 100644
index 000000000..3c9b654f1
--- /dev/null
+++ b/src/sim/startup.hh
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SIM_STARTUP_HH__
+#define __SIM_STARTUP_HH__
+
+struct StartupCallback
+{
+ StartupCallback();
+ virtual ~StartupCallback();
+ virtual void startup();
+};
+
+void SimStartup();
+
+#endif // __SIM_STARTUP_HH__
diff --git a/src/sim/stat_control.cc b/src/sim/stat_control.cc
new file mode 100644
index 000000000..85c405b7f
--- /dev/null
+++ b/src/sim/stat_control.cc
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// This file will contain default statistics for the simulator that
+// don't really belong to a specific simulator object
+
+#include <fstream>
+#include <iostream>
+#include <list>
+
+#include "base/callback.hh"
+#include "base/hostinfo.hh"
+#include "base/statistics.hh"
+#include "base/str.hh"
+#include "base/time.hh"
+#include "base/stats/output.hh"
+#include "cpu/base.hh"
+#include "sim/eventq.hh"
+#include "sim/sim_object.hh"
+#include "sim/stat_control.hh"
+#include "sim/root.hh"
+
+using namespace std;
+
+Stats::Formula hostInstRate;
+Stats::Formula hostTickRate;
+Stats::Value hostMemory;
+Stats::Value hostSeconds;
+
+Stats::Value simTicks;
+Stats::Value simInsts;
+Stats::Value simFreq;
+Stats::Formula simSeconds;
+
+namespace Stats {
+
+Time statTime(true);
+Tick startTick;
+Tick lastDump(0);
+
+class SimTicksReset : public Callback
+{
+ public:
+ void process()
+ {
+ statTime.set();
+ startTick = curTick;
+ }
+};
+
+double
+statElapsedTime()
+{
+ Time now(true);
+ Time elapsed = now - statTime;
+ return elapsed();
+}
+
+Tick
+statElapsedTicks()
+{
+ return curTick - startTick;
+}
+
+SimTicksReset simTicksReset;
+
+void
+InitSimStats()
+{
+ simInsts
+ .functor(BaseCPU::numSimulatedInstructions)
+ .name("sim_insts")
+ .desc("Number of instructions simulated")
+ .precision(0)
+ .prereq(simInsts)
+ ;
+
+ simSeconds
+ .name("sim_seconds")
+ .desc("Number of seconds simulated")
+ ;
+
+ simFreq
+ .scalar(Clock::Frequency)
+ .name("sim_freq")
+ .desc("Frequency of simulated ticks")
+ ;
+
+ simTicks
+ .functor(statElapsedTicks)
+ .name("sim_ticks")
+ .desc("Number of ticks simulated")
+ ;
+
+ hostInstRate
+ .name("host_inst_rate")
+ .desc("Simulator instruction rate (inst/s)")
+ .precision(0)
+ .prereq(simInsts)
+ ;
+
+ hostMemory
+ .functor(memUsage)
+ .name("host_mem_usage")
+ .desc("Number of bytes of host memory used")
+ .prereq(hostMemory)
+ ;
+
+ hostSeconds
+ .functor(statElapsedTime)
+ .name("host_seconds")
+ .desc("Real time elapsed on the host")
+ .precision(2)
+ ;
+
+ hostTickRate
+ .name("host_tick_rate")
+ .desc("Simulator tick rate (ticks/s)")
+ .precision(0)
+ ;
+
+ simSeconds = simTicks / simFreq;
+ hostInstRate = simInsts / hostSeconds;
+ hostTickRate = simTicks / hostSeconds;
+
+ registerResetCallback(&simTicksReset);
+}
+
+class StatEvent : public Event
+{
+ protected:
+ int flags;
+ Tick repeat;
+
+ public:
+ StatEvent(int _flags, Tick _when, Tick _repeat);
+ virtual void process();
+ virtual const char *description();
+};
+
+StatEvent::StatEvent(int _flags, Tick _when, Tick _repeat)
+ : Event(&mainEventQueue, Stat_Event_Pri),
+ flags(_flags), repeat(_repeat)
+{
+ setFlags(AutoDelete);
+ schedule(_when);
+}
+
+const char *
+StatEvent::description()
+{
+ return "Statistics dump and/or reset";
+}
+
+void
+StatEvent::process()
+{
+ if (flags & Stats::Dump)
+ DumpNow();
+
+ if (flags & Stats::Reset)
+ reset();
+
+ if (repeat)
+ schedule(curTick + repeat);
+}
+
+list<Output *> OutputList;
+
+void
+DumpNow()
+{
+ assert(lastDump <= curTick);
+ if (lastDump == curTick)
+ return;
+ lastDump = curTick;
+
+ list<Output *>::iterator i = OutputList.begin();
+ list<Output *>::iterator end = OutputList.end();
+ for (; i != end; ++i) {
+ Output *output = *i;
+ if (!output->valid())
+ continue;
+
+ output->output();
+ }
+}
+
+void
+SetupEvent(int flags, Tick when, Tick repeat)
+{
+ new StatEvent(flags, when, repeat);
+}
+
+/* namespace Stats */ }
+
+extern "C" void
+debugDumpStats()
+{
+ Stats::DumpNow();
+}
+
diff --git a/src/sim/stat_control.hh b/src/sim/stat_control.hh
new file mode 100644
index 000000000..a22ce76af
--- /dev/null
+++ b/src/sim/stat_control.hh
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SIM_STAT_CONTROL_HH__
+#define __SIM_STAT_CONTROL_HH__
+
+#include <fstream>
+#include <list>
+
+namespace Stats {
+
+enum {
+ Reset = 0x1,
+ Dump = 0x2
+};
+
+class Output;
+extern std::list<Output *> OutputList;
+
+void DumpNow();
+void SetupEvent(int flags, Tick when, Tick repeat = 0);
+
+void InitSimStats();
+
+/* namespace Stats */ }
+
+#endif // __SIM_STAT_CONTROL_HH__
diff --git a/src/sim/stats.hh b/src/sim/stats.hh
new file mode 100644
index 000000000..8e97d041f
--- /dev/null
+++ b/src/sim/stats.hh
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SIM_STATS_HH__
+#define __SIM_STATS_HH__
+
+#include "base/statistics.hh"
+
+extern Stats::Formula simSeconds;
+extern Stats::Value simTicks;
+
+#endif // __SIM_SIM_STATS_HH__
diff --git a/src/sim/syscall_emul.cc b/src/sim/syscall_emul.cc
new file mode 100644
index 000000000..ed0da628e
--- /dev/null
+++ b/src/sim/syscall_emul.cc
@@ -0,0 +1,454 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <string>
+#include <iostream>
+
+#include "sim/syscall_emul.hh"
+#include "base/chunk_generator.hh"
+#include "base/trace.hh"
+#include "cpu/exec_context.hh"
+#include "cpu/base.hh"
+#include "mem/page_table.hh"
+#include "sim/process.hh"
+
+#include "sim/sim_events.hh"
+
+using namespace std;
+using namespace TheISA;
+
+void
+SyscallDesc::doSyscall(int callnum, Process *process, ExecContext *xc)
+{
+ DPRINTFR(SyscallVerbose, "%d: %s: syscall %s called w/arguments %d,%d,%d,%d\n",
+ curTick,xc->getCpuPtr()->name(), name,
+ xc->getSyscallArg(0),xc->getSyscallArg(1),
+ xc->getSyscallArg(2),xc->getSyscallArg(3));
+
+ SyscallReturn retval = (*funcPtr)(this, callnum, process, xc);
+
+ DPRINTFR(SyscallVerbose, "%d: %s: syscall %s returns %d\n",
+ curTick,xc->getCpuPtr()->name(), name, retval.value());
+
+ if (!(flags & SyscallDesc::SuppressReturnValue))
+ xc->setSyscallReturn(retval);
+}
+
+
+SyscallReturn
+unimplementedFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ fatal("syscall %s (#%d) unimplemented.", desc->name, callnum);
+
+ return 1;
+}
+
+
+SyscallReturn
+ignoreFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ warn("ignoring syscall %s(%d, %d, ...)", desc->name,
+ xc->getSyscallArg(0), xc->getSyscallArg(1));
+
+ return 0;
+}
+
+
+SyscallReturn
+exitFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ new SimExitEvent("target called exit()", xc->getSyscallArg(0) & 0xff);
+
+ return 1;
+}
+
+
+SyscallReturn
+getpagesizeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
+{
+ return (int)VMPageSize;
+}
+
+
+SyscallReturn
+obreakFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
+{
+ Addr junk;
+
+ // change brk addr to first arg
+ Addr new_brk = xc->getSyscallArg(0);
+ if (new_brk != 0) {
+ for (ChunkGenerator gen(p->brk_point, new_brk - p->brk_point,
+ VMPageSize); !gen.done(); gen.next()) {
+ if (!p->pTable->translate(gen.addr(), junk))
+ p->pTable->allocate(roundDown(gen.addr(), VMPageSize),
+ VMPageSize);
+ }
+ p->brk_point = new_brk;
+ }
+ DPRINTF(SyscallVerbose, "Break Point changed to: %#X\n", p->brk_point);
+ return p->brk_point;
+}
+
+
+SyscallReturn
+closeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
+{
+ int target_fd = xc->getSyscallArg(0);
+ int status = close(p->sim_fd(target_fd));
+ if (status >= 0)
+ p->free_fd(target_fd);
+ return status;
+}
+
+
+SyscallReturn
+readFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
+{
+ int fd = p->sim_fd(xc->getSyscallArg(0));
+ int nbytes = xc->getSyscallArg(2);
+ BufferArg bufArg(xc->getSyscallArg(1), nbytes);
+
+ int bytes_read = read(fd, bufArg.bufferPtr(), nbytes);
+
+ if (bytes_read != -1)
+ bufArg.copyOut(xc->getMemPort());
+
+ return bytes_read;
+}
+
+SyscallReturn
+writeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
+{
+ int fd = p->sim_fd(xc->getSyscallArg(0));
+ int nbytes = xc->getSyscallArg(2);
+ BufferArg bufArg(xc->getSyscallArg(1), nbytes);
+
+ bufArg.copyIn(xc->getMemPort());
+
+ int bytes_written = write(fd, bufArg.bufferPtr(), nbytes);
+
+ fsync(fd);
+
+ return bytes_written;
+}
+
+
+SyscallReturn
+lseekFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
+{
+ int fd = p->sim_fd(xc->getSyscallArg(0));
+ uint64_t offs = xc->getSyscallArg(1);
+ int whence = xc->getSyscallArg(2);
+
+ off_t result = lseek(fd, offs, whence);
+
+ return (result == (off_t)-1) ? -errno : result;
+}
+
+
+SyscallReturn
+munmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
+{
+ // given that we don't really implement mmap, munmap is really easy
+ return 0;
+}
+
+
+const char *hostname = "m5.eecs.umich.edu";
+
+SyscallReturn
+gethostnameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
+{
+ int name_len = xc->getSyscallArg(1);
+ BufferArg name(xc->getSyscallArg(0), name_len);
+
+ strncpy((char *)name.bufferPtr(), hostname, name_len);
+
+ name.copyOut(xc->getMemPort());
+
+ return 0;
+}
+
+SyscallReturn
+unlinkFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
+{
+ string path;
+
+ if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
+ return (TheISA::IntReg)-EFAULT;
+
+ int result = unlink(path.c_str());
+ return (result == -1) ? -errno : result;
+}
+
+SyscallReturn
+renameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
+{
+ string old_name;
+
+ if (!xc->getMemPort()->tryReadString(old_name, xc->getSyscallArg(0)))
+ return -EFAULT;
+
+ string new_name;
+
+ if (!xc->getMemPort()->tryReadString(new_name, xc->getSyscallArg(1)))
+ return -EFAULT;
+
+ int64_t result = rename(old_name.c_str(), new_name.c_str());
+ return (result == -1) ? -errno : result;
+}
+
+SyscallReturn
+truncateFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
+{
+ string path;
+
+ if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
+ return -EFAULT;
+
+ off_t length = xc->getSyscallArg(1);
+
+ int result = truncate(path.c_str(), length);
+ return (result == -1) ? -errno : result;
+}
+
+SyscallReturn
+ftruncateFunc(SyscallDesc *desc, int num, Process *process, ExecContext *xc)
+{
+ int fd = process->sim_fd(xc->getSyscallArg(0));
+
+ if (fd < 0)
+ return -EBADF;
+
+ off_t length = xc->getSyscallArg(1);
+
+ int result = ftruncate(fd, length);
+ return (result == -1) ? -errno : result;
+}
+
+SyscallReturn
+chownFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
+{
+ string path;
+
+ if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
+ return -EFAULT;
+
+ /* XXX endianess */
+ uint32_t owner = xc->getSyscallArg(1);
+ uid_t hostOwner = owner;
+ uint32_t group = xc->getSyscallArg(2);
+ gid_t hostGroup = group;
+
+ int result = chown(path.c_str(), hostOwner, hostGroup);
+ return (result == -1) ? -errno : result;
+}
+
+SyscallReturn
+fchownFunc(SyscallDesc *desc, int num, Process *process, ExecContext *xc)
+{
+ int fd = process->sim_fd(xc->getSyscallArg(0));
+
+ if (fd < 0)
+ return -EBADF;
+
+ /* XXX endianess */
+ uint32_t owner = xc->getSyscallArg(1);
+ uid_t hostOwner = owner;
+ uint32_t group = xc->getSyscallArg(2);
+ gid_t hostGroup = group;
+
+ int result = fchown(fd, hostOwner, hostGroup);
+ return (result == -1) ? -errno : result;
+}
+
+
+SyscallReturn
+fcntlFunc(SyscallDesc *desc, int num, Process *process,
+ ExecContext *xc)
+{
+ int fd = xc->getSyscallArg(0);
+
+ if (fd < 0 || process->sim_fd(fd) < 0)
+ return -EBADF;
+
+ int cmd = xc->getSyscallArg(1);
+ switch (cmd) {
+ case 0: // F_DUPFD
+ // if we really wanted to support this, we'd need to do it
+ // in the target fd space.
+ warn("fcntl(%d, F_DUPFD) not supported, error returned\n", fd);
+ return -EMFILE;
+
+ case 1: // F_GETFD (get close-on-exec flag)
+ case 2: // F_SETFD (set close-on-exec flag)
+ return 0;
+
+ case 3: // F_GETFL (get file flags)
+ case 4: // F_SETFL (set file flags)
+ // not sure if this is totally valid, but we'll pass it through
+ // to the underlying OS
+ warn("fcntl(%d, %d) passed through to host\n", fd, cmd);
+ return fcntl(process->sim_fd(fd), cmd);
+ // return 0;
+
+ case 7: // F_GETLK (get lock)
+ case 8: // F_SETLK (set lock)
+ case 9: // F_SETLKW (set lock and wait)
+ // don't mess with file locking... just act like it's OK
+ warn("File lock call (fcntl(%d, %d)) ignored.\n", fd, cmd);
+ return 0;
+
+ default:
+ warn("Unknown fcntl command %d\n", cmd);
+ return 0;
+ }
+}
+
+SyscallReturn
+pipePseudoFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ int fds[2], sim_fds[2];
+ int pipe_retval = pipe(fds);
+
+ if (pipe_retval < 0) {
+ // error
+ return pipe_retval;
+ }
+
+ sim_fds[0] = process->alloc_fd(fds[0]);
+ sim_fds[1] = process->alloc_fd(fds[1]);
+
+ // Alpha Linux convention for pipe() is that fd[0] is returned as
+ // the return value of the function, and fd[1] is returned in r20.
+ xc->setIntReg(SyscallPseudoReturnReg, sim_fds[1]);
+ return sim_fds[0];
+}
+
+
+SyscallReturn
+getpidPseudoFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ // Make up a PID. There's no interprocess communication in
+ // fake_syscall mode, so there's no way for a process to know it's
+ // not getting a unique value.
+
+ xc->setIntReg(SyscallPseudoReturnReg, 99);
+ return 100;
+}
+
+
+SyscallReturn
+getuidPseudoFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ // Make up a UID and EUID... it shouldn't matter, and we want the
+ // simulation to be deterministic.
+
+ // EUID goes in r20.
+ xc->setIntReg(SyscallPseudoReturnReg, 100); //EUID
+ return 100; // UID
+}
+
+
+SyscallReturn
+getgidPseudoFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ // Get current group ID. EGID goes in r20.
+ xc->setIntReg(SyscallPseudoReturnReg, 100); //EGID
+ return 100;
+}
+
+
+SyscallReturn
+setuidFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ // can't fathom why a benchmark would call this.
+ warn("Ignoring call to setuid(%d)\n", xc->getSyscallArg(0));
+ return 0;
+}
+
+SyscallReturn
+getpidFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ // Make up a PID. There's no interprocess communication in
+ // fake_syscall mode, so there's no way for a process to know it's
+ // not getting a unique value.
+
+ xc->setIntReg(SyscallPseudoReturnReg, 99); //PID
+ return 100;
+}
+
+SyscallReturn
+getppidFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ return 99;
+}
+
+SyscallReturn
+getuidFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ return 100; // UID
+}
+
+SyscallReturn
+geteuidFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ return 100; // UID
+}
+
+SyscallReturn
+getgidFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ return 100;
+}
+
+SyscallReturn
+getegidFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ return 100;
+}
+
+
diff --git a/src/sim/syscall_emul.hh b/src/sim/syscall_emul.hh
new file mode 100644
index 000000000..00f016410
--- /dev/null
+++ b/src/sim/syscall_emul.hh
@@ -0,0 +1,849 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SIM_SYSCALL_EMUL_HH__
+#define __SIM_SYSCALL_EMUL_HH__
+
+#define BSD_HOST (defined(__APPLE__) || defined(__OpenBSD__) || \
+ defined(__FreeBSD__))
+
+///
+/// @file syscall_emul.hh
+///
+/// This file defines objects used to emulate syscalls from the target
+/// application on the host machine.
+
+#include <errno.h>
+#include <string>
+#ifdef __CYGWIN32__
+#include <sys/fcntl.h> // for O_BINARY
+#endif
+#include <sys/uio.h>
+
+#include "arch/isa_traits.hh" // for Addr
+#include "base/chunk_generator.hh"
+#include "base/intmath.hh" // for RoundUp
+#include "base/misc.hh"
+#include "base/trace.hh"
+#include "cpu/base.hh"
+#include "cpu/exec_context.hh"
+#include "mem/translating_port.hh"
+#include "mem/page_table.hh"
+#include "sim/process.hh"
+
+///
+/// System call descriptor.
+///
+class SyscallDesc {
+
+ public:
+
+ /// Typedef for target syscall handler functions.
+ typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num,
+ Process *, ExecContext *);
+
+ const char *name; //!< Syscall name (e.g., "open").
+ FuncPtr funcPtr; //!< Pointer to emulation function.
+ int flags; //!< Flags (see Flags enum).
+
+ /// Flag values for controlling syscall behavior.
+ enum Flags {
+ /// Don't set return regs according to funcPtr return value.
+ /// Used for syscalls with non-standard return conventions
+ /// that explicitly set the ExecContext regs (e.g.,
+ /// sigreturn).
+ SuppressReturnValue = 1
+ };
+
+ /// Constructor.
+ SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0)
+ : name(_name), funcPtr(_funcPtr), flags(_flags)
+ {
+ }
+
+ /// Emulate the syscall. Public interface for calling through funcPtr.
+ void doSyscall(int callnum, Process *proc, ExecContext *xc);
+};
+
+
+class BaseBufferArg {
+
+ public:
+
+ BaseBufferArg(Addr _addr, int _size) : addr(_addr), size(_size)
+ {
+ bufPtr = new uint8_t[size];
+ // clear out buffer: in case we only partially populate this,
+ // and then do a copyOut(), we want to make sure we don't
+ // introduce any random junk into the simulated address space
+ memset(bufPtr, 0, size);
+ }
+
+ virtual ~BaseBufferArg() { delete [] bufPtr; }
+
+ //
+ // copy data into simulator space (read from target memory)
+ //
+ virtual bool copyIn(TranslatingPort *memport)
+ {
+ memport->readBlob(addr, bufPtr, size);
+ return true; // no EFAULT detection for now
+ }
+
+ //
+ // copy data out of simulator space (write to target memory)
+ //
+ virtual bool copyOut(TranslatingPort *memport)
+ {
+ memport->writeBlob(addr, bufPtr, size);
+ return true; // no EFAULT detection for now
+ }
+
+ protected:
+ Addr addr;
+ int size;
+ uint8_t *bufPtr;
+};
+
+
+class BufferArg : public BaseBufferArg
+{
+ public:
+ BufferArg(Addr _addr, int _size) : BaseBufferArg(_addr, _size) { }
+ void *bufferPtr() { return bufPtr; }
+};
+
+template <class T>
+class TypedBufferArg : public BaseBufferArg
+{
+ public:
+ // user can optionally specify a specific number of bytes to
+ // allocate to deal with those structs that have variable-size
+ // arrays at the end
+ TypedBufferArg(Addr _addr, int _size = sizeof(T))
+ : BaseBufferArg(_addr, _size)
+ { }
+
+ // type case
+ operator T*() { return (T *)bufPtr; }
+
+ // dereference operators
+ T &operator*() { return *((T *)bufPtr); }
+ T* operator->() { return (T *)bufPtr; }
+ T &operator[](int i) { return ((T *)bufPtr)[i]; }
+};
+
+//////////////////////////////////////////////////////////////////////
+//
+// The following emulation functions are generic enough that they
+// don't need to be recompiled for different emulated OS's. They are
+// defined in sim/syscall_emul.cc.
+//
+//////////////////////////////////////////////////////////////////////
+
+
+/// Handler for unimplemented syscalls that we haven't thought about.
+SyscallReturn unimplementedFunc(SyscallDesc *desc, int num,
+ Process *p, ExecContext *xc);
+
+/// Handler for unimplemented syscalls that we never intend to
+/// implement (signal handling, etc.) and should not affect the correct
+/// behavior of the program. Print a warning only if the appropriate
+/// trace flag is enabled. Return success to the target program.
+SyscallReturn ignoreFunc(SyscallDesc *desc, int num,
+ Process *p, ExecContext *xc);
+
+/// Target exit() handler: terminate simulation.
+SyscallReturn exitFunc(SyscallDesc *desc, int num,
+ Process *p, ExecContext *xc);
+
+/// Target getpagesize() handler.
+SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num,
+ Process *p, ExecContext *xc);
+
+/// Target obreak() handler: set brk address.
+SyscallReturn obreakFunc(SyscallDesc *desc, int num,
+ Process *p, ExecContext *xc);
+
+/// Target close() handler.
+SyscallReturn closeFunc(SyscallDesc *desc, int num,
+ Process *p, ExecContext *xc);
+
+/// Target read() handler.
+SyscallReturn readFunc(SyscallDesc *desc, int num,
+ Process *p, ExecContext *xc);
+
+/// Target write() handler.
+SyscallReturn writeFunc(SyscallDesc *desc, int num,
+ Process *p, ExecContext *xc);
+
+/// Target lseek() handler.
+SyscallReturn lseekFunc(SyscallDesc *desc, int num,
+ Process *p, ExecContext *xc);
+
+/// Target munmap() handler.
+SyscallReturn munmapFunc(SyscallDesc *desc, int num,
+ Process *p, ExecContext *xc);
+
+/// Target gethostname() handler.
+SyscallReturn gethostnameFunc(SyscallDesc *desc, int num,
+ Process *p, ExecContext *xc);
+
+/// Target unlink() handler.
+SyscallReturn unlinkFunc(SyscallDesc *desc, int num,
+ Process *p, ExecContext *xc);
+
+/// Target rename() handler.
+SyscallReturn renameFunc(SyscallDesc *desc, int num,
+ Process *p, ExecContext *xc);
+
+
+/// Target truncate() handler.
+SyscallReturn truncateFunc(SyscallDesc *desc, int num,
+ Process *p, ExecContext *xc);
+
+
+/// Target ftruncate() handler.
+SyscallReturn ftruncateFunc(SyscallDesc *desc, int num,
+ Process *p, ExecContext *xc);
+
+
+/// Target chown() handler.
+SyscallReturn chownFunc(SyscallDesc *desc, int num,
+ Process *p, ExecContext *xc);
+
+
+/// Target fchown() handler.
+SyscallReturn fchownFunc(SyscallDesc *desc, int num,
+ Process *p, ExecContext *xc);
+
+/// Target fnctl() handler.
+SyscallReturn fcntlFunc(SyscallDesc *desc, int num,
+ Process *process, ExecContext *xc);
+
+/// Target setuid() handler.
+SyscallReturn setuidFunc(SyscallDesc *desc, int num,
+ Process *p, ExecContext *xc);
+
+/// Target getpid() handler.
+SyscallReturn getpidFunc(SyscallDesc *desc, int num,
+ Process *p, ExecContext *xc);
+
+/// Target getuid() handler.
+SyscallReturn getuidFunc(SyscallDesc *desc, int num,
+ Process *p, ExecContext *xc);
+
+/// Target getgid() handler.
+SyscallReturn getgidFunc(SyscallDesc *desc, int num,
+ Process *p, ExecContext *xc);
+
+/// Target getppid() handler.
+SyscallReturn getppidFunc(SyscallDesc *desc, int num,
+ Process *p, ExecContext *xc);
+
+/// Target geteuid() handler.
+SyscallReturn geteuidFunc(SyscallDesc *desc, int num,
+ Process *p, ExecContext *xc);
+
+/// Target getegid() handler.
+SyscallReturn getegidFunc(SyscallDesc *desc, int num,
+ Process *p, ExecContext *xc);
+
+
+
+/// Pseudo Funcs - These functions use a different return convension,
+/// returning a second value in a register other than the normal return register
+SyscallReturn pipePseudoFunc(SyscallDesc *desc, int num,
+ Process *process, ExecContext *xc);
+
+/// Target getpidPseudo() handler.
+SyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num,
+ Process *p, ExecContext *xc);
+
+/// Target getuidPseudo() handler.
+SyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num,
+ Process *p, ExecContext *xc);
+
+/// Target getgidPseudo() handler.
+SyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num,
+ Process *p, ExecContext *xc);
+
+
+/// This struct is used to build an target-OS-dependent table that
+/// maps the target's open() flags to the host open() flags.
+struct OpenFlagTransTable {
+ int tgtFlag; //!< Target system flag value.
+ int hostFlag; //!< Corresponding host system flag value.
+};
+
+
+
+/// A readable name for 1,000,000, for converting microseconds to seconds.
+const int one_million = 1000000;
+
+/// Approximate seconds since the epoch (1/1/1970). About a billion,
+/// by my reckoning. We want to keep this a constant (not use the
+/// real-world time) to keep simulations repeatable.
+const unsigned seconds_since_epoch = 1000000000;
+
+/// Helper function to convert current elapsed time to seconds and
+/// microseconds.
+template <class T1, class T2>
+void
+getElapsedTime(T1 &sec, T2 &usec)
+{
+ int elapsed_usecs = curTick / Clock::Int::us;
+ sec = elapsed_usecs / one_million;
+ usec = elapsed_usecs % one_million;
+}
+
+//////////////////////////////////////////////////////////////////////
+//
+// The following emulation functions are generic, but need to be
+// templated to account for differences in types, constants, etc.
+//
+//////////////////////////////////////////////////////////////////////
+
+/// Target ioctl() handler. For the most part, programs call ioctl()
+/// only to find out if their stdout is a tty, to determine whether to
+/// do line or block buffering.
+template <class OS>
+SyscallReturn
+ioctlFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ int fd = xc->getSyscallArg(0);
+ unsigned req = xc->getSyscallArg(1);
+
+ DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req);
+
+ if (fd < 0 || process->sim_fd(fd) < 0) {
+ // doesn't map to any simulator fd: not a valid target fd
+ return -EBADF;
+ }
+
+ switch (req) {
+ case OS::TIOCISATTY:
+ case OS::TIOCGETP:
+ case OS::TIOCSETP:
+ case OS::TIOCSETN:
+ case OS::TIOCSETC:
+ case OS::TIOCGETC:
+ case OS::TIOCGETS:
+ case OS::TIOCGETA:
+ return -ENOTTY;
+
+ default:
+ fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ 0x%llx\n",
+ fd, req, xc->readPC());
+ }
+}
+
+/// Target open() handler.
+template <class OS>
+SyscallReturn
+openFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ std::string path;
+
+ if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
+ return -EFAULT;
+
+ if (path == "/dev/sysdev0") {
+ // This is a memory-mapped high-resolution timer device on Alpha.
+ // We don't support it, so just punt.
+ warn("Ignoring open(%s, ...)\n", path);
+ return -ENOENT;
+ }
+
+ int tgtFlags = xc->getSyscallArg(1);
+ int mode = xc->getSyscallArg(2);
+ int hostFlags = 0;
+
+ // translate open flags
+ for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) {
+ if (tgtFlags & OS::openFlagTable[i].tgtFlag) {
+ tgtFlags &= ~OS::openFlagTable[i].tgtFlag;
+ hostFlags |= OS::openFlagTable[i].hostFlag;
+ }
+ }
+
+ // any target flags left?
+ if (tgtFlags != 0)
+ warn("Syscall: open: cannot decode flags 0x%x", tgtFlags);
+
+#ifdef __CYGWIN32__
+ hostFlags |= O_BINARY;
+#endif
+
+ DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str());
+
+ // open the file
+ int fd = open(path.c_str(), hostFlags, mode);
+
+ return (fd == -1) ? -errno : process->alloc_fd(fd);
+}
+
+
+/// Target chmod() handler.
+template <class OS>
+SyscallReturn
+chmodFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ std::string path;
+
+ if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
+ return -EFAULT;
+
+ uint32_t mode = xc->getSyscallArg(1);
+ mode_t hostMode = 0;
+
+ // XXX translate mode flags via OS::something???
+ hostMode = mode;
+
+ // do the chmod
+ int result = chmod(path.c_str(), hostMode);
+ if (result < 0)
+ return -errno;
+
+ return 0;
+}
+
+
+/// Target fchmod() handler.
+template <class OS>
+SyscallReturn
+fchmodFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ int fd = xc->getSyscallArg(0);
+ if (fd < 0 || process->sim_fd(fd) < 0) {
+ // doesn't map to any simulator fd: not a valid target fd
+ return -EBADF;
+ }
+
+ uint32_t mode = xc->getSyscallArg(1);
+ mode_t hostMode = 0;
+
+ // XXX translate mode flags via OS::someting???
+ hostMode = mode;
+
+ // do the fchmod
+ int result = fchmod(process->sim_fd(fd), hostMode);
+ if (result < 0)
+ return -errno;
+
+ return 0;
+}
+
+
+/// Target stat() handler.
+template <class OS>
+SyscallReturn
+statFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ std::string path;
+
+ if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
+ return -EFAULT;
+
+ struct stat hostBuf;
+ int result = stat(path.c_str(), &hostBuf);
+
+ if (result < 0)
+ return -errno;
+
+ OS::copyOutStatBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf);
+
+ return 0;
+}
+
+
+/// Target fstat64() handler.
+template <class OS>
+SyscallReturn
+fstat64Func(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ int fd = xc->getSyscallArg(0);
+ if (fd < 0 || process->sim_fd(fd) < 0) {
+ // doesn't map to any simulator fd: not a valid target fd
+ return -EBADF;
+ }
+
+#if BSD_HOST
+ struct stat hostBuf;
+ int result = fstat(process->sim_fd(fd), &hostBuf);
+#else
+ struct stat64 hostBuf;
+ int result = fstat64(process->sim_fd(fd), &hostBuf);
+#endif
+
+ if (result < 0)
+ return -errno;
+
+ OS::copyOutStat64Buf(xc->getMemPort(), fd, xc->getSyscallArg(1), &hostBuf);
+
+ return 0;
+}
+
+
+/// Target lstat() handler.
+template <class OS>
+SyscallReturn
+lstatFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ std::string path;
+
+ if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
+ return -EFAULT;
+
+ struct stat hostBuf;
+ int result = lstat(path.c_str(), &hostBuf);
+
+ if (result < 0)
+ return -errno;
+
+ OS::copyOutStatBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf);
+
+ return 0;
+}
+
+/// Target lstat64() handler.
+template <class OS>
+SyscallReturn
+lstat64Func(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ std::string path;
+
+ if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
+ return -EFAULT;
+
+#if BSD_HOST
+ struct stat hostBuf;
+ int result = lstat(path.c_str(), &hostBuf);
+#else
+ struct stat64 hostBuf;
+ int result = lstat64(path.c_str(), &hostBuf);
+#endif
+
+ if (result < 0)
+ return -errno;
+
+ OS::copyOutStat64Buf(xc->getMemPort(), -1, xc->getSyscallArg(1), &hostBuf);
+
+ return 0;
+}
+
+/// Target fstat() handler.
+template <class OS>
+SyscallReturn
+fstatFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ int fd = process->sim_fd(xc->getSyscallArg(0));
+
+ DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd);
+
+ if (fd < 0)
+ return -EBADF;
+
+ struct stat hostBuf;
+ int result = fstat(fd, &hostBuf);
+
+ if (result < 0)
+ return -errno;
+
+ OS::copyOutStatBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf);
+
+ return 0;
+}
+
+
+/// Target statfs() handler.
+template <class OS>
+SyscallReturn
+statfsFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ std::string path;
+
+ if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
+ return -EFAULT;
+
+ struct statfs hostBuf;
+ int result = statfs(path.c_str(), &hostBuf);
+
+ if (result < 0)
+ return -errno;
+
+ OS::copyOutStatfsBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf);
+
+ return 0;
+}
+
+
+/// Target fstatfs() handler.
+template <class OS>
+SyscallReturn
+fstatfsFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ int fd = process->sim_fd(xc->getSyscallArg(0));
+
+ if (fd < 0)
+ return -EBADF;
+
+ struct statfs hostBuf;
+ int result = fstatfs(fd, &hostBuf);
+
+ if (result < 0)
+ return -errno;
+
+ OS::copyOutStatfsBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf);
+
+ return 0;
+}
+
+
+/// Target writev() handler.
+template <class OS>
+SyscallReturn
+writevFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ int fd = xc->getSyscallArg(0);
+ if (fd < 0 || process->sim_fd(fd) < 0) {
+ // doesn't map to any simulator fd: not a valid target fd
+ return -EBADF;
+ }
+
+ TranslatingPort *p = xc->getMemPort();
+ uint64_t tiov_base = xc->getSyscallArg(1);
+ size_t count = xc->getSyscallArg(2);
+ struct iovec hiov[count];
+ for (int i = 0; i < count; ++i)
+ {
+ typename OS::tgt_iovec tiov;
+
+ p->readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec),
+ (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec));
+ hiov[i].iov_len = gtoh(tiov.iov_len);
+ hiov[i].iov_base = new char [hiov[i].iov_len];
+ p->readBlob(gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base,
+ hiov[i].iov_len);
+ }
+
+ int result = writev(process->sim_fd(fd), hiov, count);
+
+ for (int i = 0; i < count; ++i)
+ {
+ delete [] (char *)hiov[i].iov_base;
+ }
+
+ if (result < 0)
+ return -errno;
+
+ return 0;
+}
+
+
+/// Target mmap() handler.
+///
+/// We don't really handle mmap(). If the target is mmaping an
+/// anonymous region or /dev/zero, we can get away with doing basically
+/// nothing (since memory is initialized to zero and the simulator
+/// doesn't really check addresses anyway). Always print a warning,
+/// since this could be seriously broken if we're not mapping
+/// /dev/zero.
+//
+/// Someday we should explicitly check for /dev/zero in open, flag the
+/// file descriptor, and fail (or implement!) a non-anonymous mmap to
+/// anything else.
+template <class OS>
+SyscallReturn
+mmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
+{
+ Addr start = xc->getSyscallArg(0);
+ uint64_t length = xc->getSyscallArg(1);
+ // int prot = xc->getSyscallArg(2);
+ int flags = xc->getSyscallArg(3);
+ // int fd = p->sim_fd(xc->getSyscallArg(4));
+ // int offset = xc->getSyscallArg(5);
+
+ if ((start % TheISA::VMPageSize) != 0 ||
+ (length % TheISA::VMPageSize) != 0) {
+ warn("mmap failing: arguments not page-aligned: "
+ "start 0x%x length 0x%x",
+ start, length);
+ return -EINVAL;
+ }
+
+ if (start != 0) {
+ warn("mmap: ignoring suggested map address 0x%x, using 0x%x",
+ start, p->mmap_end);
+ }
+
+ // pick next address from our "mmap region"
+ start = p->mmap_end;
+ p->pTable->allocate(start, length);
+ p->mmap_end += length;
+
+ if (!(flags & OS::TGT_MAP_ANONYMOUS)) {
+ warn("allowing mmap of file @ fd %d. "
+ "This will break if not /dev/zero.", xc->getSyscallArg(4));
+ }
+
+ return start;
+}
+
+/// Target getrlimit() handler.
+template <class OS>
+SyscallReturn
+getrlimitFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ unsigned resource = xc->getSyscallArg(0);
+ TypedBufferArg<typename OS::rlimit> rlp(xc->getSyscallArg(1));
+
+ switch (resource) {
+ case OS::TGT_RLIMIT_STACK:
+ // max stack size in bytes: make up a number (2MB for now)
+ rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
+ rlp->rlim_cur = htog(rlp->rlim_cur);
+ rlp->rlim_max = htog(rlp->rlim_max);
+ break;
+
+ default:
+ std::cerr << "getrlimitFunc: unimplemented resource " << resource
+ << std::endl;
+ abort();
+ break;
+ }
+
+ rlp.copyOut(xc->getMemPort());
+ return 0;
+}
+
+/// Target gettimeofday() handler.
+template <class OS>
+SyscallReturn
+gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ TypedBufferArg<typename OS::timeval> tp(xc->getSyscallArg(0));
+
+ getElapsedTime(tp->tv_sec, tp->tv_usec);
+ tp->tv_sec += seconds_since_epoch;
+ tp->tv_sec = htog(tp->tv_sec);
+ tp->tv_usec = htog(tp->tv_usec);
+
+ tp.copyOut(xc->getMemPort());
+
+ return 0;
+}
+
+
+/// Target utimes() handler.
+template <class OS>
+SyscallReturn
+utimesFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ std::string path;
+
+ if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
+ return -EFAULT;
+
+ TypedBufferArg<typename OS::timeval [2]> tp(xc->getSyscallArg(1));
+ tp.copyIn(xc->getMemPort());
+
+ struct timeval hostTimeval[2];
+ for (int i = 0; i < 2; ++i)
+ {
+ hostTimeval[i].tv_sec = gtoh((*tp)[i].tv_sec);
+ hostTimeval[i].tv_usec = gtoh((*tp)[i].tv_usec);
+ }
+ int result = utimes(path.c_str(), hostTimeval);
+
+ if (result < 0)
+ return -errno;
+
+ return 0;
+}
+/// Target getrusage() function.
+template <class OS>
+SyscallReturn
+getrusageFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ int who = xc->getSyscallArg(0); // THREAD, SELF, or CHILDREN
+ TypedBufferArg<typename OS::rusage> rup(xc->getSyscallArg(1));
+
+ if (who != OS::TGT_RUSAGE_SELF) {
+ // don't really handle THREAD or CHILDREN, but just warn and
+ // plow ahead
+ warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.",
+ who);
+ }
+
+ getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec);
+ rup->ru_utime.tv_sec = htog(rup->ru_utime.tv_sec);
+ rup->ru_utime.tv_usec = htog(rup->ru_utime.tv_usec);
+
+ rup->ru_stime.tv_sec = 0;
+ rup->ru_stime.tv_usec = 0;
+ rup->ru_maxrss = 0;
+ rup->ru_ixrss = 0;
+ rup->ru_idrss = 0;
+ rup->ru_isrss = 0;
+ rup->ru_minflt = 0;
+ rup->ru_majflt = 0;
+ rup->ru_nswap = 0;
+ rup->ru_inblock = 0;
+ rup->ru_oublock = 0;
+ rup->ru_msgsnd = 0;
+ rup->ru_msgrcv = 0;
+ rup->ru_nsignals = 0;
+ rup->ru_nvcsw = 0;
+ rup->ru_nivcsw = 0;
+
+ rup.copyOut(xc->getMemPort());
+
+ return 0;
+}
+
+
+
+
+#endif // __SIM_SYSCALL_EMUL_HH__
diff --git a/src/sim/system.cc b/src/sim/system.cc
new file mode 100644
index 000000000..ca9d68d77
--- /dev/null
+++ b/src/sim/system.cc
@@ -0,0 +1,265 @@
+#include "arch/isa_traits.hh"
+#include "base/loader/object_file.hh"
+#include "base/loader/symtab.hh"
+#include "base/trace.hh"
+#include "cpu/exec_context.hh"
+#include "mem/mem_object.hh"
+#include "mem/physical.hh"
+#include "sim/builder.hh"
+#include "sim/byteswap.hh"
+#include "sim/system.hh"
+#if FULL_SYSTEM
+#include "arch/vtophys.hh"
+#include "base/remote_gdb.hh"
+#include "kern/kernel_stats.hh"
+#endif
+
+using namespace std;
+using namespace TheISA;
+
+vector<System *> System::systemList;
+
+int System::numSystemsRunning = 0;
+
+System::System(Params *p)
+ : SimObject(p->name), physmem(p->physmem), numcpus(0),
+#if FULL_SYSTEM
+ init_param(p->init_param),
+#else
+ page_ptr(0),
+#endif
+ _params(p)
+{
+ // add self to global system list
+ systemList.push_back(this);
+
+#if FULL_SYSTEM
+ kernelSymtab = new SymbolTable;
+ debugSymbolTable = new SymbolTable;
+
+
+ /**
+ * Get a functional port to memory
+ */
+ Port *mem_port;
+ mem_port = physmem->getPort("functional");
+ functionalPort.setPeer(mem_port);
+ mem_port->setPeer(&functionalPort);
+
+ mem_port = physmem->getPort("functional");
+ virtPort.setPeer(mem_port);
+ mem_port->setPeer(&virtPort);
+
+
+ /**
+ * Load the kernel code into memory
+ */
+ // Load kernel code
+ kernel = createObjectFile(params()->kernel_path);
+ if (kernel == NULL)
+ fatal("Could not load kernel file %s", params()->kernel_path);
+
+ // Load program sections into memory
+ kernel->loadSections(&functionalPort, LoadAddrMask);
+
+ // setup entry points
+ kernelStart = kernel->textBase();
+ kernelEnd = kernel->bssBase() + kernel->bssSize();
+ kernelEntry = kernel->entryPoint();
+
+ // load symbols
+ if (!kernel->loadGlobalSymbols(kernelSymtab))
+ panic("could not load kernel symbols\n");
+
+ if (!kernel->loadLocalSymbols(kernelSymtab))
+ panic("could not load kernel local symbols\n");
+
+ if (!kernel->loadGlobalSymbols(debugSymbolTable))
+ panic("could not load kernel symbols\n");
+
+ if (!kernel->loadLocalSymbols(debugSymbolTable))
+ panic("could not load kernel local symbols\n");
+
+ DPRINTF(Loader, "Kernel start = %#x\n", kernelStart);
+ DPRINTF(Loader, "Kernel end = %#x\n", kernelEnd);
+ DPRINTF(Loader, "Kernel entry = %#x\n", kernelEntry);
+ DPRINTF(Loader, "Kernel loaded...\n");
+
+ kernelBinning = new Kernel::Binning(this);
+#endif // FULL_SYSTEM
+
+ // increment the number of running systms
+ numSystemsRunning++;
+}
+
+System::~System()
+{
+#if FULL_SYSTEM
+ delete kernelSymtab;
+ delete kernel;
+
+ delete kernelBinning;
+#else
+ panic("System::fixFuncEventAddr needs to be rewritten "
+ "to work with syscall emulation");
+#endif // FULL_SYSTEM}
+}
+
+#if FULL_SYSTEM
+
+
+int rgdb_wait = -1;
+
+#endif // FULL_SYSTEM
+
+int
+System::registerExecContext(ExecContext *xc, int id)
+{
+ if (id == -1) {
+ for (id = 0; id < execContexts.size(); id++) {
+ if (!execContexts[id])
+ break;
+ }
+ }
+
+ if (execContexts.size() <= id)
+ execContexts.resize(id + 1);
+
+ if (execContexts[id])
+ panic("Cannot have two CPUs with the same id (%d)\n", id);
+
+ execContexts[id] = xc;
+ numcpus++;
+
+#if FULL_SYSTEM
+ RemoteGDB *rgdb = new RemoteGDB(this, xc);
+ GDBListener *gdbl = new GDBListener(rgdb, 7000 + id);
+ gdbl->listen();
+ /**
+ * Uncommenting this line waits for a remote debugger to connect
+ * to the simulator before continuing.
+ */
+ if (rgdb_wait != -1 && rgdb_wait == id)
+ gdbl->accept();
+
+ if (remoteGDB.size() <= id) {
+ remoteGDB.resize(id + 1);
+ }
+
+ remoteGDB[id] = rgdb;
+#endif // FULL_SYSTEM
+
+ return id;
+}
+
+void
+System::startup()
+{
+ int i;
+ for (i = 0; i < execContexts.size(); i++)
+ execContexts[i]->activate(0);
+}
+
+void
+System::replaceExecContext(ExecContext *xc, int id)
+{
+ if (id >= execContexts.size()) {
+ panic("replaceExecContext: bad id, %d >= %d\n",
+ id, execContexts.size());
+ }
+
+ execContexts[id] = xc;
+#if FULL_SYSTEM
+ remoteGDB[id]->replaceExecContext(xc);
+#endif // FULL_SYSTEM
+}
+
+#if !FULL_SYSTEM
+Addr
+System::new_page()
+{
+ Addr return_addr = page_ptr << LogVMPageSize;
+ ++page_ptr;
+ return return_addr;
+}
+#endif
+
+void
+System::regStats()
+{
+#if FULL_SYSTEM
+ kernelBinning->regStats(name() + ".kern");
+#endif // FULL_SYSTEM
+}
+
+void
+System::serialize(ostream &os)
+{
+#if FULL_SYSTEM
+ kernelBinning->serialize(os);
+
+ kernelSymtab->serialize("kernel_symtab", os);
+#endif // FULL_SYSTEM
+}
+
+
+void
+System::unserialize(Checkpoint *cp, const string &section)
+{
+#if FULL_SYSTEM
+ kernelBinning->unserialize(cp, section);
+
+ kernelSymtab->unserialize("kernel_symtab", cp, section);
+#endif // FULL_SYSTEM
+}
+
+void
+System::printSystems()
+{
+ vector<System *>::iterator i = systemList.begin();
+ vector<System *>::iterator end = systemList.end();
+ for (; i != end; ++i) {
+ System *sys = *i;
+ cerr << "System " << sys->name() << ": " << hex << sys << endl;
+ }
+}
+
+extern "C"
+void
+printSystems()
+{
+ System::printSystems();
+}
+
+#if FULL_SYSTEM
+
+// In full system mode, only derived classes (e.g. AlphaLinuxSystem)
+// can be created directly.
+
+DEFINE_SIM_OBJECT_CLASS_NAME("System", System)
+
+#else
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(System)
+
+ SimObjectParam<PhysicalMemory *> physmem;
+
+END_DECLARE_SIM_OBJECT_PARAMS(System)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(System)
+
+ INIT_PARAM(physmem, "physical memory")
+
+END_INIT_SIM_OBJECT_PARAMS(System)
+
+CREATE_SIM_OBJECT(System)
+{
+ System::Params *p = new System::Params;
+ p->name = getInstanceName();
+ p->physmem = physmem;
+ return new System(p);
+}
+
+REGISTER_SIM_OBJECT("System", System)
+
+#endif
diff --git a/src/sim/system.hh b/src/sim/system.hh
new file mode 100644
index 000000000..7e21bd587
--- /dev/null
+++ b/src/sim/system.hh
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SYSTEM_HH__
+#define __SYSTEM_HH__
+
+#include <string>
+#include <vector>
+
+#include "base/loader/symtab.hh"
+#include "base/misc.hh"
+#include "base/statistics.hh"
+#include "cpu/pc_event.hh"
+#include "mem/port.hh"
+#include "sim/sim_object.hh"
+#if FULL_SYSTEM
+#include "kern/system_events.hh"
+#include "mem/vport.hh"
+#endif
+
+class BaseCPU;
+class ExecContext;
+class ObjectFile;
+class PhysicalMemory;
+
+#if FULL_SYSTEM
+class Platform;
+class GDBListener;
+class RemoteGDB;
+namespace Kernel { class Binning; }
+#endif
+
+class System : public SimObject
+{
+ public:
+ PhysicalMemory *physmem;
+ PCEventQueue pcEventQueue;
+
+ std::vector<ExecContext *> execContexts;
+ int numcpus;
+
+ int getNumCPUs()
+ {
+ if (numcpus != execContexts.size())
+ panic("cpu array not fully populated!");
+
+ return numcpus;
+ }
+
+#if FULL_SYSTEM
+ Platform *platform;
+ uint64_t init_param;
+
+ /** Port to physical memory used for writing object files into ram at
+ * boot.*/
+ FunctionalPort functionalPort;
+ VirtualPort virtPort;
+
+ /** kernel symbol table */
+ SymbolTable *kernelSymtab;
+
+ /** Object pointer for the kernel code */
+ ObjectFile *kernel;
+
+ /** Begining of kernel code */
+ Addr kernelStart;
+
+ /** End of kernel code */
+ Addr kernelEnd;
+
+ /** Entry point in the kernel to start at */
+ Addr kernelEntry;
+
+ Kernel::Binning *kernelBinning;
+
+#else
+
+ int page_ptr;
+
+
+#endif // FULL_SYSTEM
+
+ protected:
+
+#if FULL_SYSTEM
+ /**
+ * Fix up an address used to match PCs for hooking simulator
+ * events on to target function executions. See comment in
+ * system.cc for details.
+ */
+ virtual Addr fixFuncEventAddr(Addr addr) = 0;
+
+ /**
+ * Add a function-based event to the given function, to be looked
+ * up in the specified symbol table.
+ */
+ template <class T>
+ T *System::addFuncEvent(SymbolTable *symtab, const char *lbl)
+ {
+ Addr addr = 0; // initialize only to avoid compiler warning
+
+ if (symtab->findAddress(lbl, addr)) {
+ T *ev = new T(&pcEventQueue, lbl, fixFuncEventAddr(addr));
+ return ev;
+ }
+
+ return NULL;
+ }
+
+ /** Add a function-based event to kernel code. */
+ template <class T>
+ T *System::addKernelFuncEvent(const char *lbl)
+ {
+ return addFuncEvent<T>(kernelSymtab, lbl);
+ }
+
+#endif
+ public:
+#if FULL_SYSTEM
+ std::vector<RemoteGDB *> remoteGDB;
+ std::vector<GDBListener *> gdbListen;
+ virtual bool breakpoint() = 0;
+#endif // FULL_SYSTEM
+
+ public:
+ struct Params
+ {
+ std::string name;
+ PhysicalMemory *physmem;
+
+#if FULL_SYSTEM
+ Tick boot_cpu_frequency;
+ std::string boot_osflags;
+ uint64_t init_param;
+ bool bin;
+ std::vector<std::string> binned_fns;
+ bool bin_int;
+
+ std::string kernel_path;
+ std::string readfile;
+#endif
+ };
+
+ protected:
+ Params *_params;
+
+ public:
+ System(Params *p);
+ ~System();
+
+ void startup();
+
+ const Params *params() const { return (const Params *)_params; }
+
+ public:
+
+#if FULL_SYSTEM
+ /**
+ * Returns the addess the kernel starts at.
+ * @return address the kernel starts at
+ */
+ Addr getKernelStart() const { return kernelStart; }
+
+ /**
+ * Returns the addess the kernel ends at.
+ * @return address the kernel ends at
+ */
+ Addr getKernelEnd() const { return kernelEnd; }
+
+ /**
+ * Returns the addess the entry point to the kernel code.
+ * @return entry point of the kernel code
+ */
+ Addr getKernelEntry() const { return kernelEntry; }
+
+#else
+
+ Addr new_page();
+
+#endif // FULL_SYSTEM
+
+ int registerExecContext(ExecContext *xc, int xcIndex);
+ void replaceExecContext(ExecContext *xc, int xcIndex);
+
+ void regStats();
+ void serialize(std::ostream &os);
+ void unserialize(Checkpoint *cp, const std::string &section);
+
+ public:
+ ////////////////////////////////////////////
+ //
+ // STATIC GLOBAL SYSTEM LIST
+ //
+ ////////////////////////////////////////////
+
+ static std::vector<System *> systemList;
+ static int numSystemsRunning;
+
+ static void printSystems();
+
+
+};
+
+#endif // __SYSTEM_HH__
diff --git a/src/sim/vptr.hh b/src/sim/vptr.hh
new file mode 100644
index 000000000..cc57e63f0
--- /dev/null
+++ b/src/sim/vptr.hh
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ARCH_ALPHA_VPTR_HH__
+#define __ARCH_ALPHA_VPTR_HH__
+
+#include "arch/vtophys.hh"
+#include "arch/isa_traits.hh"
+
+class ExecContext;
+
+template <class T>
+class VPtr
+{
+ public:
+ typedef T Type;
+
+ private:
+ ExecContext *xc;
+ Addr ptr;
+
+ public:
+ ExecContext *GetXC() const { return xc; }
+ Addr GetPointer() const { return ptr; }
+
+ public:
+ explicit VPtr(ExecContext *_xc, Addr p = 0) : xc(_xc), ptr(p) { }
+ template <class U>
+ VPtr(const VPtr<U> &vp) : xc(vp.GetXC()), ptr(vp.GetPointer()) {}
+ ~VPtr() {}
+
+ bool operator!() const
+ {
+ return ptr == 0;
+ }
+
+ VPtr<T> operator+(int offset)
+ {
+ VPtr<T> ptr(*this);
+ ptr += offset;
+
+ return ptr;
+ }
+
+ const VPtr<T> &operator+=(int offset)
+ {
+ ptr += offset;
+ assert((ptr & (TheISA::PageBytes - 1)) + sizeof(T)
+ < TheISA::PageBytes);
+
+ return *this;
+ }
+
+ const VPtr<T> &operator=(Addr p)
+ {
+ assert((p & (TheISA::PageBytes - 1)) + sizeof(T)
+ < TheISA::PageBytes);
+ ptr = p;
+
+ return *this;
+ }
+
+ template <class U>
+ const VPtr<T> &operator=(const VPtr<U> &vp)
+ {
+ xc = vp.GetXC();
+ ptr = vp.GetPointer();
+
+ return *this;
+ }
+
+ operator T *()
+ {
+ panic("Needs to be rewritten\n");
+/* void *addr = vtomem(xc, ptr, sizeof(T));
+ return (T *)addr;
+ */
+ }
+
+ T *operator->()
+ {
+ panic("Needs to be rewritten\n");
+/* void *addr = vtomem(xc, ptr, sizeof(T));
+ return (T *)addr;
+ */
+ }
+
+ T &operator*()
+ {
+ panic("Needs to be rewritten\n");
+/* void *addr = vtomem(xc, ptr, sizeof(T));
+ return *(T *)addr;
+ */
+ }
+};
+
+#endif // __ARCH_ALPHA_VPTR_HH__
diff --git a/src/unittest/Makefile b/src/unittest/Makefile
new file mode 100644
index 000000000..1f0584066
--- /dev/null
+++ b/src/unittest/Makefile
@@ -0,0 +1,98 @@
+# Copyright (c) 2006 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: Nathan Binkert
+# Steve Reinhardt
+
+CC?= gcc
+CXX?= g++
+PYTHON?=/usr/bin/env python
+
+CURDIR?= $(shell /bin/pwd)
+SRCDIR?= $(CURDIR)/..
+
+CCFLAGS= -g -O0 -MMD -I. -I$(SRCDIR) -I- -DTRACING_ON=0
+MYSQL= -I/usr/include/mysql -L/usr/lib/mysql -lmysqlclient
+
+VPATH=$(SRCDIR):$(CURDIR)
+
+default:
+ @echo "You must specify a target"
+
+base/traceflags.cc base/traceflags.hh: $(SRCDIR)/base/traceflags.py
+ mkdir -p base; \
+ cd base; \
+ $(PYTHON) $<
+
+bitvectest: test/bitvectest.cc
+ $(CXX) $(CCFLAGS) -o $@ $^
+
+circletest: test/circletest.cc base/circlebuf.cc
+ $(CXX) $(CCFLAGS) -o $@ $^
+
+cprintftest: test/cprintftest.cc base/cprintf.cc
+ $(CXX) $(CCFLAGS) -o $@ $^
+
+initest: test/initest.cc base/str.cc base/inifile.cc base/cprintf.cc
+ $(CXX) $(CCFLAGS) -o $@ $^
+
+lrutest: test/lru_test.cc
+ $(CXX) $(CCFLAGS) -o $@ $^
+
+nmtest: test/nmtest.cc base/output.cc base/hostinfo.cc base/cprintf.cc base/misc.cc base/loader/object_file.cc base/loader/symtab.cc base/misc.cc base/str.cc base/loader/aout_object.cc base/loader/ecoff_object.cc base/loader/elf_object.cc
+ $(CXX) $(CCFLAGS) -I/n/ziff/z/binkertn/build/work/ALPHA_FS -lelf -o $@ $^
+
+offtest: test/offtest.cc
+ $(CXX) $(CCFLAGS) -o $@ $^
+
+rangetest: test/rangetest.cc base/range.cc base/str.cc
+ $(CXX) $(CCFLAGS) -o $@ $^
+
+STATTEST+= base/cprintf.cc base/hostinfo.cc base/misc.cc base/mysql.cc
+STATTEST+= base/python.cc base/str.cc base/time.cc
+STATTEST+= base/statistics.cc base/stats/mysql.cc base/stats/python.cc
+STATTEST+= base/stats/statdb.cc base/stats/text.cc base/stats/visit.cc
+STATTEST+= test/stattest.cc
+stattest: $(STATTEST)
+ $(CXX) $(CCFLAGS) $(MYSQL) -o $@ $^
+
+strnumtest: test/strnumtest.cc base/str.cc
+ $(CXX) $(CCFLAGS) -o $@ $^
+
+symtest: test/symtest.cc base/misc.cc base/symtab.cc base/str.cc
+ $(CXX) $(CCFLAGS) -o $@ $^
+
+tokentest: test/tokentest.cc base/str.cc
+ $(CXX) $(CCFLAGS) -o $@ $^
+
+TRACE+=test/tracetest.cc base/trace.cc base/trace_flags.cc base/cprintf.cc
+TRACE+=base/str.cc base/misc.cc
+tracetest: $(TRACE)
+ $(CXX) $(CCFLAGS) -o $@ $^
+
+clean:
+ @rm -rf *test *~ .#* *.core core base
+.PHONY: clean
diff --git a/src/unittest/bitvectest.cc b/src/unittest/bitvectest.cc
new file mode 100644
index 000000000..1b8c332f5
--- /dev/null
+++ b/src/unittest/bitvectest.cc
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <iostream.h>
+
+#include <vector>
+
+int
+main()
+{
+ vector<bool> v1(100);
+
+ v1[0] = true;
+ v1.resize(500);
+ v1[100] = true;
+ v1[499] = true;
+ v1.resize(10000);
+ v1[9999] = true;
+
+ cout << "v1.size() = " << v1.size() << "\n";
+ for (int i = 0; i < v1.size(); i++)
+ if (v1[i])
+ cout << "v1[" << i << "] = " << v1[i] << "\n";
+
+ cout << "\n";
+
+ vector<bool> v2 = v1;
+
+ for (int i = 0; i < v2.size(); i++)
+ if (v2[i])
+ cout << "v2[" << i << "] = " << v2[i] << "\n";
+
+ cout << "v1 " << ((v1 == v2) ? "==" : "!=") << " v2" << "\n";
+ v2[8583] = true;
+ cout << "v1 " << ((v1 == v2) ? "==" : "!=") << " v2" << "\n";
+ v1[8583] = true;
+ cout << "v1 " << ((v1 == v2) ? "==" : "!=") << " v2" << "\n";
+ v1.resize(100000);
+ cout << "v1 " << ((v1 == v2) ? "==" : "!=") << " v2" << "\n";
+ cout << flush;
+}
diff --git a/src/unittest/circletest.cc b/src/unittest/circletest.cc
new file mode 100644
index 000000000..bb15f8c64
--- /dev/null
+++ b/src/unittest/circletest.cc
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <fcntl.h>
+#include <iostream.h>
+#include <unistd.h>
+
+#include "base/circlebuf.hh"
+
+char *strings[] =
+{ "This is the first test\n",
+ "he went with his woman to the store\n",
+ "the man with the bat hit the woman with the hat\n",
+ "that that is is that that was\n",
+ "sue sells sea shells by the sea shore\n",
+ "go to the store and buy me some milk and bread\n",
+ "the friendly flight attendants spoke soothingly to the frightened passengers in their native languages\n"
+};
+
+const int num_strings = sizeof(strings) / sizeof(char *);
+
+int
+main()
+{
+ CircleBuf buf(1024);
+
+ for (int count = 0; count < 100; count++)
+ buf.write(strings[count % num_strings]);
+ buf.read(STDOUT_FILENO);
+ write(STDOUT_FILENO, "<\n", 2);
+
+ for (int count = 0; count < 100; count++)
+ buf.write(strings[count % num_strings]);
+ buf.read(STDOUT_FILENO, 100);
+ write(STDOUT_FILENO, "<\n", 2);
+
+ buf.flush();
+ buf.write("asdfa asdf asd fasdf asdf\n");
+ buf.write("");
+ buf.write("");
+ buf.write("");
+ buf.write("");
+ buf.write("");
+ buf.write("");
+ buf.read(STDOUT_FILENO);
+ write(STDOUT_FILENO, "<\n", 2);
+}
diff --git a/src/unittest/cprintftest.cc b/src/unittest/cprintftest.cc
new file mode 100644
index 000000000..361f84028
--- /dev/null
+++ b/src/unittest/cprintftest.cc
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <iostream>
+#include <list>
+#include <string>
+#include <sstream>
+
+#include "base/cprintf.hh"
+
+using namespace std;
+
+int
+main()
+{
+ char foo[9];
+ cprintf("%s\n", foo);
+
+ cprintf("%shits%%s + %smisses%%s\n", "test", "test");
+ cprintf("%%s%-10s %c he went home \'\"%d %#o %#x %1.5f %1.2E\n",
+ "hello", 'A', 1, 0xff, 0xfffffffffffffULL, 3.141592653589, 1.1e10);
+
+ cout << cformat("%s %#x %s\n") << "hello" << 0 << "foo 0\n";
+ cerr << cformat("%s %#x\n") << "hello" << 1 << "foo 1\n";
+
+ cprintf("another test\n");
+
+ stringstream buffer;
+ ccprintf(buffer, "%-10s %c he home \'\"%d %#o %#x %1.5f %1.2E\n",
+ "hello", 'A', 1, 0xff, 0xfffffffffffffULL, 3.14159265, 1.1e10);
+
+ double f = 314159.26535897932384;
+
+ #define ctest(x, y) printf(x, y); cprintf(x, y); cprintf("\n");
+ ctest("%1.8f\n", f);
+ ctest("%2.8f\n", f);
+ ctest("%3.8f\n", f);
+ ctest("%4.8f\n", f);
+ ctest("%5.8f\n", f);
+ ctest("%6.8f\n", f);
+ ctest("%12.8f\n", f);
+ ctest("%1000.8f\n", f);
+ ctest("%1.0f\n", f);
+ ctest("%1.1f\n", f);
+ ctest("%1.2f\n", f);
+ ctest("%1.3f\n", f);
+ ctest("%1.4f\n", f);
+ ctest("%1.5f\n", f);
+ ctest("%1.6f\n", f);
+ ctest("%1.7f\n", f);
+ ctest("%1.8f\n", f);
+ ctest("%1.9f\n", f);
+ ctest("%1.10f\n", f);
+ ctest("%1.11f\n", f);
+ ctest("%1.12f\n", f);
+ ctest("%1.13f\n", f);
+ ctest("%1.14f\n", f);
+ ctest("%1.15f\n", f);
+ ctest("%1.16f\n", f);
+ ctest("%1.17f\n", f);
+ ctest("%1.18f\n", f);
+
+ cout << "foo\n";
+
+ f = 0.00000026535897932384;
+ ctest("%1.8f\n", f);
+ ctest("%2.8f\n", f);
+ ctest("%3.8f\n", f);
+ ctest("%4.8f\n", f);
+ ctest("%5.8f\n", f);
+ ctest("%6.8f\n", f);
+ ctest("%12.8f\n", f);
+ ctest("%1.0f\n", f);
+ ctest("%1.1f\n", f);
+ ctest("%1.2f\n", f);
+ ctest("%1.3f\n", f);
+ ctest("%1.4f\n", f);
+ ctest("%1.5f\n", f);
+ ctest("%1.6f\n", f);
+ ctest("%1.7f\n", f);
+ ctest("%1.8f\n", f);
+ ctest("%1.9f\n", f);
+ ctest("%1.10f\n", f);
+ ctest("%1.11f\n", f);
+ ctest("%1.12f\n", f);
+ ctest("%1.13f\n", f);
+ ctest("%1.14f\n", f);
+ ctest("%1.15f\n", f);
+ ctest("%1.16f\n", f);
+ ctest("%1.17f\n", f);
+ ctest("%1.18f\n", f);
+
+ f = 0.00000026535897932384;
+ ctest("%1.8e\n", f);
+ ctest("%2.8e\n", f);
+ ctest("%3.8e\n", f);
+ ctest("%4.8e\n", f);
+ ctest("%5.8e\n", f);
+ ctest("%6.8e\n", f);
+ ctest("%12.8e\n", f);
+ ctest("%1.0e\n", f);
+ ctest("%1.1e\n", f);
+ ctest("%1.2e\n", f);
+ ctest("%1.3e\n", f);
+ ctest("%1.4e\n", f);
+ ctest("%1.5e\n", f);
+ ctest("%1.6e\n", f);
+ ctest("%1.7e\n", f);
+ ctest("%1.8e\n", f);
+ ctest("%1.9e\n", f);
+ ctest("%1.10e\n", f);
+ ctest("%1.11e\n", f);
+ ctest("%1.12e\n", f);
+ ctest("%1.13e\n", f);
+ ctest("%1.14e\n", f);
+ ctest("%1.15e\n", f);
+ ctest("%1.16e\n", f);
+ ctest("%1.17e\n", f);
+ ctest("%1.18e\n", f);
+
+ cout << buffer.str();
+
+ cout.width(0);
+ cout.precision(1);
+ cout << f << "\n";
+
+ string foo1 = "string test";
+ cprintf("%s\n", foo1);
+
+ stringstream foo2;
+ foo2 << "stringstream test";
+ cprintf("%s\n", foo2);
+
+ cprintf("%c %c\n", 'c', 65);
+
+ cout << '9';
+ return 0;
+}
diff --git a/src/unittest/foo.ini b/src/unittest/foo.ini
new file mode 100644
index 000000000..534a4e001
--- /dev/null
+++ b/src/unittest/foo.ini
@@ -0,0 +1,10 @@
+#define JUNK
+[Foo]
+Foo1=89
+Foo2=384
+
+[General]
+Test3=89
+
+[Junk]
+Test4+=mia
diff --git a/src/unittest/genini.py b/src/unittest/genini.py
new file mode 100755
index 000000000..2af81fe2b
--- /dev/null
+++ b/src/unittest/genini.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python
+# Copyright (c) 2005 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import getopt, os, os.path, sys
+from os.path import join as joinpath, realpath
+
+mypath = sys.path[0]
+sys.path.append(joinpath(mypath, '..'))
+sys.path.append(joinpath(mypath, '../python'))
+sys.path.append(joinpath(mypath, '../util/pbs'))
+
+pathlist = [ '.' ]
+
+m5_build_env = {}
+
+try:
+ opts, args = getopt.getopt(sys.argv[1:], '-E:I:')
+ for opt,arg in opts:
+ if opt == '-E':
+ offset = arg.find('=')
+ if offset == -1:
+ name = arg
+ value = 'True'
+ else:
+ name = arg[:offset]
+ value = arg[offset+1:]
+ os.environ[name] = value
+ m5_build_env[name] = value
+ if opt == '-I':
+ pathlist.append(arg)
+except getopt.GetoptError:
+ sys.exit('Improper Usage')
+
+import __main__
+__main__.m5_build_env = m5_build_env
+
+from m5 import *
+
+for path in pathlist:
+ AddToPath(path)
+
+for arg in args:
+ m5execfile(arg, globals())
+
+if globals().has_key('root') and isinstance(root, Root):
+ instantiate(root)
+else:
+ print "Instantiation skipped: no root object found."
diff --git a/src/unittest/initest.cc b/src/unittest/initest.cc
new file mode 100644
index 000000000..0c5ac2343
--- /dev/null
+++ b/src/unittest/initest.cc
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+
+#include "base/inifile.hh"
+#include "base/cprintf.hh"
+
+using namespace std;
+
+char *progname;
+
+void
+usage()
+{
+ cout << "Usage: " << progname << " <ini file>\n";
+ exit(1);
+}
+
+#if 0
+char *defines = getenv("CONFIG_DEFINES");
+if (defines) {
+ char *c = defines;
+ while ((c = strchr(c, ' ')) != NULL) {
+ *c++ = '\0';
+ count++;
+ }
+ count++;
+}
+
+#endif
+
+int
+main(int argc, char *argv[])
+{
+ IniFile simConfigDB;
+
+ progname = argv[0];
+
+ vector<char *> cppArgs;
+
+ vector<char *> cpp_options;
+ cpp_options.reserve(argc * 2);
+
+ for (int i = 1; i < argc; ++i) {
+ char *arg_str = argv[i];
+
+ // if arg starts with '-', parse as option,
+ // else treat it as a configuration file name and load it
+ if (arg_str[0] == '-') {
+
+ // switch on second char
+ switch (arg_str[1]) {
+ case 'D':
+ case 'U':
+ case 'I':
+ // cpp options: record & pass to cpp. Note that these
+ // cannot have spaces, i.e., '-Dname=val' is OK, but
+ // '-D name=val' is not. I don't consider this a
+ // problem, since even though gnu cpp accepts the
+ // latter, other cpp implementations do not (Tru64,
+ // for one).
+ cppArgs.push_back(arg_str);
+ break;
+
+ case '-':
+ // command-line configuration parameter:
+ // '--<section>:<parameter>=<value>'
+
+ if (!simConfigDB.add(arg_str + 2)) {
+ // parse error
+ ccprintf(cerr,
+ "Could not parse configuration argument '%s'\n"
+ "Expecting --<section>:<parameter>=<value>\n",
+ arg_str);
+ exit(0);
+ }
+ break;
+
+ default:
+ usage();
+ }
+ }
+ else {
+ // no '-', treat as config file name
+
+ if (!simConfigDB.loadCPP(arg_str, cppArgs)) {
+ cprintf("Error processing file %s\n", arg_str);
+ exit(1);
+ }
+ }
+ }
+
+ string value;
+
+#define FIND(C, E) \
+ if (simConfigDB.find(C, E, value)) \
+ cout << ">" << value << "<\n"; \
+ else \
+ cout << "Not Found!\n"
+
+ FIND("General", "Test2");
+ FIND("Junk", "Test3");
+ FIND("Junk", "Test4");
+ FIND("General", "Test1");
+ FIND("Junk2", "test3");
+ FIND("General", "Test3");
+
+ cout << "\n";
+
+ simConfigDB.dump();
+
+ return 0;
+}
diff --git a/src/unittest/initest.ini b/src/unittest/initest.ini
new file mode 100644
index 000000000..ebf2719d8
--- /dev/null
+++ b/src/unittest/initest.ini
@@ -0,0 +1,14 @@
+#define JUNK
+// General stuff
+#define FOO(X) BAR##X
+[General]
+ Test1=FOO(asdf)
+ Test2=bar
+
+#ifdef JUNK
+[Junk] // This is the junk
+Test3=yo
+Test4=mama
+#endif
+
+#include "foo.ini"
diff --git a/src/unittest/lru_test.cc b/src/unittest/lru_test.cc
new file mode 100644
index 000000000..2829163de
--- /dev/null
+++ b/src/unittest/lru_test.cc
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <iostream>
+#include "bhgp.hh"
+
+int main(void)
+{
+ typedef AssociativeTable<unsigned int, unsigned int> tableType;
+ tableType table(10, 4); // 40 entry table
+
+ std::cout << "Initial state:" << std::endl;
+ table.dump();
+
+ std::cout << "Inserting (2, 1)" << std::endl;
+ table[2] = 1;
+ table.dump();
+
+ std::cout << "Inserting (5, 2)" << std::endl;
+ table[5] = 2;
+ table.dump();
+
+ std::cout << "Inserting (10 + 2, 3)" << std::endl;
+ table[10 + 2] = 3;
+ table.dump();
+
+ tableType::const_iterator i = table.find(2);
+ assert(i != table.end());
+ std::cout << "Accessed 2: " << *i << std::endl;
+ table.dump();
+
+ i = table.find(10 + 2);
+ assert(i != table.end());
+ std::cout << "Accessed 10 + 2: " << *i << std::endl;
+ table.dump();
+
+ i = table.find(34);
+ assert(i == table.end());
+
+ std::cout << "Inserting (2 * 10 + 2, 4)" << std::endl;
+ table[2 * 10 + 2] = 4;
+ table.dump();
+
+ std::cout << "Replacing (10 + 2) with 5" << std::endl;
+ table[10 + 2] = 5;
+ table.dump();
+
+ std::cout << "Inserting (3 * 10 + 2, 6)" << std::endl;
+ table[3 * 10 + 2] = 6;
+ table.dump();
+
+ std::cout << "Inserting (4 * 10 + 2, 7)" << std::endl;
+ table[4 * 10 + 2] = 7;
+ table.dump();
+
+ return(0);
+}
diff --git a/src/unittest/nmtest.cc b/src/unittest/nmtest.cc
new file mode 100644
index 000000000..e9c20d19d
--- /dev/null
+++ b/src/unittest/nmtest.cc
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include "base/loader/object_file.hh"
+#include "base/loader/symtab.hh"
+#include "base/misc.hh"
+#include "base/str.hh"
+
+using namespace std;
+Tick curTick;
+
+ostream *outputStream = &cout;
+
+int
+main(int argc, char *argv[])
+{
+ if (argc != 2 && argc != 3)
+ panic("usage: %s <filename> <symbol>\n", argv[0]);
+
+ ObjectFile *obj = createObjectFile(argv[1]);
+ if (!obj)
+ panic("file not found\n");
+
+ SymbolTable symtab;
+ obj->loadGlobalSymbols(&symtab);
+ obj->loadLocalSymbols(&symtab);
+
+ if (argc == 2) {
+ SymbolTable::ATable::const_iterator i = symtab.getAddrTable().begin();
+ SymbolTable::ATable::const_iterator end = symtab.getAddrTable().end();
+ while (i != end) {
+ cprintf("%#x %s\n", i->first, i->second);
+ ++i;
+ }
+ } else {
+ string symbol = argv[2];
+ Addr address;
+
+ if (symbol[0] == '0' && symbol[1] == 'x') {
+ if (to_number(symbol, address) &&
+ symtab.findSymbol(address, symbol))
+ cprintf("address = %#x, symbol = %s\n", address, symbol);
+ else
+ cprintf("address = %#x was not found\n", address);
+ } else {
+ if (symtab.findAddress(symbol, address))
+ cprintf("symbol = %s address = %#x\n", symbol, address);
+ else
+ cprintf("symbol = %s was not found\n", symbol);
+ }
+ }
+
+ return 0;
+}
diff --git a/src/unittest/offtest.cc b/src/unittest/offtest.cc
new file mode 100644
index 000000000..d3f035b73
--- /dev/null
+++ b/src/unittest/offtest.cc
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <stddef.h>
+#include <stdio.h>
+#include "dev/pcireg.h"
+
+int
+main()
+{
+#define POFFSET(x) \
+ printf("offsetof(PCIConfig, hdr."#x") = %d\n", \
+ offsetof(PCIConfig, hdr.x))
+
+ POFFSET(vendor);
+ POFFSET(device);
+ POFFSET(command);
+ POFFSET(status);
+ POFFSET(revision);
+ POFFSET(progIF);
+ POFFSET(subClassCode);
+ POFFSET(classCode);
+ POFFSET(cacheLineSize);
+ POFFSET(latencyTimer);
+ POFFSET(headerType);
+ POFFSET(bist);
+ POFFSET(pci0.baseAddr0);
+ POFFSET(pci0.baseAddr1);
+ POFFSET(pci0.baseAddr2);
+ POFFSET(pci0.baseAddr3);
+ POFFSET(pci0.baseAddr4);
+ POFFSET(pci0.baseAddr5);
+ POFFSET(pci0.cardbusCIS);
+ POFFSET(pci0.subsystemVendorID);
+ POFFSET(pci0.expansionROM);
+ POFFSET(pci0.reserved0);
+ POFFSET(pci0.reserved1);
+ POFFSET(pci0.interruptLine);
+ POFFSET(pci0.interruptPin);
+ POFFSET(pci0.minimumGrant);
+ POFFSET(pci0.minimumLatency);
+
+ return 0;
+}
diff --git a/src/unittest/paramtest.cc b/src/unittest/paramtest.cc
new file mode 100644
index 000000000..cb31c49d5
--- /dev/null
+++ b/src/unittest/paramtest.cc
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//
+// This file is not part of the regular simulator. It is solely for
+// testing the parameter code. Edit the Makefile to add param_test.cc
+// to the sources list, then use configs/test.ini as the configuration
+// file.
+//
+#include "sim/sim_object.hh"
+#include "mem/cache/cache.hh"
+
+class ParamTest : public SimObject
+{
+ public:
+ ParamTest(string name)
+ : SimObject(name)
+ {
+ }
+
+ virtual ~ParamTest() {}
+};
+
+enum Enum1Type { Enum0 };
+enum Enum2Type { Enum10 };
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(ParamTest)
+
+ Param<int> intparam;
+ VectorParam<int> vecint;
+ Param<string> stringparam;
+ VectorParam<string> vecstring;
+ Param<bool> boolparam;
+ VectorParam<bool> vecbool;
+ SimObjectParam<BaseMemory *> memobj;
+ SimObjectVectorParam<BaseMemory *> vecmemobj;
+ SimpleEnumParam<Enum1Type> enum1;
+ MappedEnumParam<Enum2Type> enum2;
+ SimpleEnumVectorParam<Enum1Type> vecenum1;
+ MappedEnumVectorParam<Enum2Type> vecenum2;
+
+END_DECLARE_SIM_OBJECT_PARAMS(ParamTest)
+
+const char *enum1_strings[] =
+{
+ "zero", "one", "two", "three"
+};
+
+const EnumParamMap enum2_map[] =
+{
+ { "ten", 10 },
+ { "twenty", 20 },
+ { "thirty", 30 },
+ { "forty", 40 }
+};
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(ParamTest)
+
+ INIT_PARAM(intparam, "intparam"),
+ INIT_PARAM(vecint, "vecint"),
+ INIT_PARAM(stringparam, "stringparam"),
+ INIT_PARAM(vecstring, "vecstring"),
+ INIT_PARAM(boolparam, "boolparam"),
+ INIT_PARAM(vecbool, "vecbool"),
+ INIT_PARAM(memobj, "memobj"),
+ INIT_PARAM(vecmemobj, "vecmemobj"),
+ INIT_ENUM_PARAM(enum1, "enum1", enum1_strings),
+ INIT_ENUM_PARAM(enum2, "enum2", enum2_map),
+ INIT_ENUM_PARAM(vecenum1, "vecenum1", enum1_strings),
+ INIT_ENUM_PARAM(vecenum2, "vecenum2", enum2_map)
+
+END_INIT_SIM_OBJECT_PARAMS(ParamTest)
+
+
+CREATE_SIM_OBJECT(ParamTest)
+{
+ return new ParamTest(getInstanceName());
+}
+
+REGISTER_SIM_OBJECT("ParamTest", ParamTest)
diff --git a/src/unittest/rangetest.cc b/src/unittest/rangetest.cc
new file mode 100644
index 000000000..41d438f48
--- /dev/null
+++ b/src/unittest/rangetest.cc
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <iostream>
+#include <string>
+
+#include "base/range.hh"
+
+using namespace std;
+
+int
+main()
+{
+ Range<int> r1(make_pair(9, 28));
+ Range<unsigned> r2("0x1000:+0x100");
+
+ cout << r1 << "\n"
+ << r2 << "\n";
+
+#define RANGETEST(X, C, Y) \
+ cout << X << " "#C" " << Y << " => " << ((X C Y) ? "true" : "false") << "\n"
+
+#define TESTEM(X, Y) do { \
+ RANGETEST(X, < , Y); \
+ RANGETEST(X, <=, Y); \
+ RANGETEST(X, > , Y); \
+ RANGETEST(X, >=, Y); \
+ RANGETEST(X, ==, Y); \
+ RANGETEST(X, !=, Y); \
+ RANGETEST(Y, < , X); \
+ RANGETEST(Y, <=, X); \
+ RANGETEST(Y, > , X); \
+ RANGETEST(Y, >=, X); \
+ RANGETEST(Y, ==, X); \
+ RANGETEST(Y, !=, X); \
+} while (0)
+
+ TESTEM(8, r1);
+ TESTEM(9, r1);
+ TESTEM(27, r1);
+ TESTEM(28, r1);
+
+ TESTEM(0x0fff, r2);
+ TESTEM(0x1000, r2);
+ TESTEM(0x10ff, r2);
+ TESTEM(0x1100, r2);
+
+ return 0;
+}
diff --git a/src/unittest/sized_test.cc b/src/unittest/sized_test.cc
new file mode 100644
index 000000000..86cd13e5b
--- /dev/null
+++ b/src/unittest/sized_test.cc
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <iostream>
+#include <algorithm>
+
+#include "sized.hh"
+#include <queue>
+#include <typeinfo>
+
+template<typename C>
+void print(C &cont)
+{
+ std::cout << std::endl;
+ std::cout << "Printing " << typeid(cont).name() << std::endl;
+ while (!cont.empty()) {
+ std::cout << cont.front() << " ";
+ cont.pop();
+ }
+ std::cout << std::endl;
+}
+
+int main(void)
+{
+ sized<std::queue<int>, sized_error_policy<std::queue<int> > >
+ error_queue(10);
+ sized<std::queue<int>, sized_drop_policy<std::queue<int> > >
+ drop_queue(5);
+
+ for (int i = 0; i < 10; ++i) {
+ error_queue.push(i);
+ }
+
+ for (int i = 0; i < 3; ++i) {
+ drop_queue.push(i);
+ }
+
+ print(error_queue);
+ print(drop_queue);
+
+ return(0);
+}
diff --git a/src/unittest/stattest.cc b/src/unittest/stattest.cc
new file mode 100644
index 000000000..b944eff45
--- /dev/null
+++ b/src/unittest/stattest.cc
@@ -0,0 +1,560 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <iomanip>
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <unistd.h>
+
+#include "base/cprintf.hh"
+#include "base/misc.hh"
+#include "base/statistics.hh"
+#include "base/stats/text.hh"
+#include "base/stats/mysql.hh"
+#include "sim/host.hh"
+
+using namespace std;
+using namespace Stats;
+
+Tick curTick = 0;
+Tick ticksPerSecond = ULL(2000000000);
+
+Scalar<> s1;
+Scalar<> s2;
+Average<> s3;
+Scalar<MainBin> s4;
+Vector<MainBin> s5;
+Distribution<MainBin> s6;
+Vector<MainBin> s7;
+AverageVector<> s8;
+StandardDeviation<> s9;
+AverageDeviation<> s10;
+Scalar<> s11;
+Distribution<> s12;
+VectorDistribution<> s13;
+VectorStandardDeviation<> s14;
+VectorAverageDeviation<> s15;
+Vector2d<> s16;
+
+Formula f1;
+Formula f2;
+Formula f3;
+Value f4;
+Value f5;
+Formula f6;
+Formula f7;
+
+MainBin bin1("bin1");
+MainBin bin2("bin2");
+
+ostream *outputStream = &cout;
+
+double
+testfunc()
+{
+ return 9.8;
+}
+
+class TestClass {
+ public:
+ double operator()() { return 9.7; }
+};
+
+char *progname = "";
+
+void
+usage()
+{
+ panic("incorrect usage.\n"
+ "usage:\n"
+ "\t%s [-t [-c] [-d]]\n", progname);
+}
+
+int
+main(int argc, char *argv[])
+{
+ bool descriptions = false;
+ bool compat = false;
+ bool text = false;
+ string mysql_name;
+ string mysql_host;
+ string mysql_user = "binkertn";
+ string mysql_passwd;
+
+ char c;
+ progname = argv[0];
+ while ((c = getopt(argc, argv, "cdh:P:p:s:tu:")) != -1) {
+ switch (c) {
+ case 'c':
+ compat = true;
+ break;
+ case 'd':
+ descriptions = true;
+ break;
+ case 'h':
+ mysql_host = optarg;
+ break;
+ case 'P':
+ mysql_passwd = optarg;
+ break;
+ case 's':
+ mysql_name = optarg;
+ break;
+ case 't':
+ text = true;
+ break;
+ case 'u':
+ mysql_user = optarg;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ if (!text && (compat || descriptions))
+ usage();
+
+ s5.init(5);
+ s6.init(1, 100, 13);
+ s7.init(7);
+ s8.init(10);
+ s12.init(1, 100, 13);
+ s13.init(4, 0, 99, 10);
+ s14.init(9);
+ s15.init(10);
+ s16.init(2, 9);
+
+ s1
+ .name("Stat01")
+ .desc("this is statistic 1")
+ ;
+
+ s2
+ .name("Stat02")
+ .desc("this is statistic 2")
+ .prereq(s11)
+ ;
+
+ s3
+ .name("Stat03")
+ .desc("this is statistic 3")
+ .prereq(f7)
+ ;
+
+ s4
+ .name("Stat04")
+ .desc("this is statistic 4")
+ .prereq(s11)
+ ;
+
+ s5
+ .name("Stat05")
+ .desc("this is statistic 5")
+ .prereq(s11)
+ .subname(0, "foo1")
+ .subname(1, "foo2")
+ .subname(2, "foo3")
+ .subname(3, "foo4")
+ .subname(4, "foo5")
+ ;
+
+ s6
+ .name("Stat06")
+ .desc("this is statistic 6")
+ .prereq(s11)
+ ;
+
+ s7
+ .name("Stat07")
+ .desc("this is statistic 7")
+ .precision(1)
+ .flags(pdf | total)
+ .prereq(s11)
+ ;
+
+ s8
+ .name("Stat08")
+ .desc("this is statistic 8")
+ .precision(2)
+ .prereq(s11)
+ .subname(4, "blarg")
+ ;
+
+ s9
+ .name("Stat09")
+ .desc("this is statistic 9")
+ .precision(4)
+ .prereq(s11)
+ ;
+
+ s10
+ .name("Stat10")
+ .desc("this is statistic 10")
+ .prereq(s11)
+ ;
+
+ s12
+ .name("Stat12")
+ .desc("this is statistic 12")
+ ;
+
+ s13
+ .name("Stat13")
+ .desc("this is statistic 13")
+ ;
+
+ s14
+ .name("Stat14")
+ .desc("this is statistic 14")
+ ;
+
+ s15
+ .name("Stat15")
+ .desc("this is statistic 15")
+ ;
+
+ s16
+ .name("Stat16")
+ .desc("this is statistic 16")
+ .flags(total)
+ .subname(0, "sub0")
+ .subname(1, "sub1")
+ .ysubname(0, "y0")
+ .ysubname(1, "y1")
+ ;
+
+ f1
+ .name("Formula1")
+ .desc("this is formula 1")
+ .prereq(s11)
+ ;
+
+ f2
+ .name("Formula2")
+ .desc("this is formula 2")
+ .prereq(s11)
+ .precision(1)
+ ;
+
+ f3
+ .name("Formula3")
+ .desc("this is formula 3")
+ .prereq(s11)
+ .subname(0, "bar1")
+ .subname(1, "bar2")
+ .subname(2, "bar3")
+ .subname(3, "bar4")
+ .subname(4, "bar5")
+ ;
+
+ f4
+ .functor(testfunc)
+ .name("Formula4")
+ .desc("this is formula 4")
+ ;
+
+ TestClass testclass;
+ f5
+ .functor(testclass)
+ .name("Formula5")
+ .desc("this is formula 5")
+ ;
+
+ f6
+ .name("Formula6")
+ .desc("this is formula 6")
+ ;
+
+ f1 = s1 + s2;
+ f2 = (-s1) / (-s2) * (-s3 + ULL(100) + s4);
+ f3 = sum(s5) * s7;
+ f6 += constant(10.0);
+ f6 += s5[3];
+ f7 = constant(1);
+
+ check();
+ reset();
+
+ bin1.activate();
+
+ s16[1][0] = 1;
+ s16[0][1] = 3;
+ s16[0][0] = 2;
+ s16[1][1] = 9;
+ s16[1][1] += 9;
+ s16[1][8] += 8;
+ s16[1][7] += 7;
+ s16[1][6] += 6;
+ s16[1][5] += 5;
+ s16[1][4] += 4;
+
+ s11 = 1;
+ s3 = 9;
+ s8[3] = 9;
+ s15[0].sample(1234);
+ s15[1].sample(1234);
+ s15[2].sample(1234);
+ s15[3].sample(1234);
+ s15[4].sample(1234);
+ s15[5].sample(1234);
+ s15[6].sample(1234);
+ s15[7].sample(1234);
+ s15[8].sample(1234);
+ s15[9].sample(1234);
+
+ s10.sample(1000000000);
+ curTick += ULL(1000000);
+ s10.sample(100000);
+ s10.sample(100000);
+ s10.sample(100000);
+ s10.sample(100000);
+ s10.sample(100000);
+ s10.sample(100000);
+ s10.sample(100000);
+ s10.sample(100000);
+ s10.sample(100000);
+ s10.sample(100000);
+ s10.sample(100000);
+ s10.sample(100000);
+ s10.sample(100000);
+ s13[0].sample(12);
+ s13[1].sample(29);
+ s13[2].sample(12);
+ s13[3].sample(29);
+ s13[0].sample(42);
+ s13[1].sample(29);
+ s13[2].sample(42);
+ s13[3].sample(32);
+ s13[0].sample(52);
+ s13[1].sample(49);
+ s13[2].sample(42);
+ s13[3].sample(25);
+ s13[0].sample(32);
+ s13[1].sample(49);
+ s13[2].sample(22);
+ s13[3].sample(49);
+ s13[0].sample(62);
+ s13[1].sample(99);
+ s13[2].sample(72);
+ s13[3].sample(23);
+ s13[0].sample(52);
+ s13[1].sample(78);
+ s13[2].sample(69);
+ s13[3].sample(49);
+
+ s14[0].sample(1234);
+ s14[1].sample(4134);
+ s14[4].sample(1213);
+ s14[3].sample(1124);
+ s14[2].sample(1243);
+ s14[7].sample(1244);
+ s14[4].sample(7234);
+ s14[2].sample(9234);
+ s14[3].sample(1764);
+ s14[7].sample(1564);
+ s14[3].sample(3234);
+ s14[1].sample(2234);
+ s14[5].sample(1234);
+ s14[2].sample(4334);
+ s14[2].sample(1234);
+ s14[4].sample(4334);
+ s14[6].sample(1234);
+ s14[8].sample(8734);
+ s14[1].sample(5234);
+ s14[3].sample(8234);
+ s14[7].sample(5234);
+ s14[4].sample(4434);
+ s14[3].sample(7234);
+ s14[2].sample(1934);
+ s14[1].sample(9234);
+ s14[5].sample(5634);
+ s14[3].sample(1264);
+ s14[7].sample(5223);
+ s14[0].sample(1234);
+ s14[0].sample(5434);
+ s14[3].sample(8634);
+ s14[1].sample(1234);
+
+
+ s15[0].sample(1234);
+ s15[1].sample(4134);
+ curTick += ULL(1000000);
+ s15[4].sample(1213);
+ curTick += ULL(1000000);
+ s15[3].sample(1124);
+ curTick += ULL(1000000);
+ s15[2].sample(1243);
+ curTick += ULL(1000000);
+ s15[7].sample(1244);
+ curTick += ULL(1000000);
+ s15[4].sample(7234);
+ s15[2].sample(9234);
+ s15[3].sample(1764);
+ s15[7].sample(1564);
+ s15[3].sample(3234);
+ s15[1].sample(2234);
+ curTick += ULL(1000000);
+ s15[5].sample(1234);
+ curTick += ULL(1000000);
+ s15[9].sample(4334);
+ curTick += ULL(1000000);
+ s15[2].sample(1234);
+ curTick += ULL(1000000);
+ s15[4].sample(4334);
+ s15[6].sample(1234);
+ curTick += ULL(1000000);
+ s15[8].sample(8734);
+ curTick += ULL(1000000);
+ s15[1].sample(5234);
+ curTick += ULL(1000000);
+ s15[3].sample(8234);
+ curTick += ULL(1000000);
+ s15[7].sample(5234);
+ s15[4].sample(4434);
+ s15[3].sample(7234);
+ s15[2].sample(1934);
+ s15[1].sample(9234);
+ curTick += ULL(1000000);
+ s15[5].sample(5634);
+ s15[3].sample(1264);
+ s15[7].sample(5223);
+ s15[0].sample(1234);
+ s15[0].sample(5434);
+ s15[3].sample(8634);
+ curTick += ULL(1000000);
+ s15[1].sample(1234);
+
+ s4 = curTick;
+
+ s8[3] = 99999;
+
+ s3 = 12;
+ s3++;
+ curTick += 9;
+
+ s1 = 9;
+ s1 += 9;
+ s1 -= 11;
+ s1++;
+ ++s1;
+ s1--;
+ --s1;
+
+ s2 = 9;
+
+ s5[0] += 1;
+ s5[1] += 2;
+ s5[2] += 3;
+ s5[3] += 4;
+ s5[4] += 5;
+
+ s7[0] = 10;
+ s7[1] = 20;
+ s7[2] = 30;
+ s7[3] = 40;
+ s7[4] = 50;
+ s7[5] = 60;
+ s7[6] = 70;
+
+ s6.sample(0);
+ s6.sample(1);
+ s6.sample(2);
+ s6.sample(3);
+ s6.sample(4);
+ s6.sample(5);
+ s6.sample(6);
+ s6.sample(7);
+ s6.sample(8);
+ s6.sample(9);
+
+ bin2.activate();
+ s6.sample(10);
+ s6.sample(10);
+ s6.sample(10);
+ s6.sample(10);
+ s6.sample(10);
+ s6.sample(10);
+ s6.sample(10);
+ s6.sample(10);
+ s6.sample(11);
+ s6.sample(19);
+ s6.sample(20);
+ s6.sample(20);
+ s6.sample(21);
+ s6.sample(21);
+ s6.sample(31);
+ s6.sample(98);
+ s6.sample(99);
+ s6.sample(99);
+ s6.sample(99);
+
+ s7[0] = 700;
+ s7[1] = 600;
+ s7[2] = 500;
+ s7[3] = 400;
+ s7[4] = 300;
+ s7[5] = 200;
+ s7[6] = 100;
+
+ s9.sample(100);
+ s9.sample(100);
+ s9.sample(100);
+ s9.sample(100);
+ s9.sample(10);
+ s9.sample(10);
+ s9.sample(10);
+ s9.sample(10);
+ s9.sample(10);
+
+ curTick += 9;
+ s4 = curTick;
+ s6.sample(100);
+ s6.sample(100);
+ s6.sample(100);
+ s6.sample(101);
+ s6.sample(102);
+
+ s12.sample(100);
+
+ if (text) {
+ Text out(cout);
+ out.descriptions = descriptions;
+ out.compat = compat;
+ out();
+ }
+
+ if (!mysql_name.empty()) {
+ MySql out;
+ out.connect(mysql_host, mysql_user, mysql_passwd, "m5stats",
+ mysql_name, "test");
+ out();
+ }
+
+ return 0;
+}
diff --git a/src/unittest/strnumtest.cc b/src/unittest/strnumtest.cc
new file mode 100644
index 000000000..a80dd7c36
--- /dev/null
+++ b/src/unittest/strnumtest.cc
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <iostream.h>
+
+#include <string>
+#include <vector>
+
+#include "base/str.hh"
+
+using namespace std;
+
+int
+main(int argc, char *argv[])
+{
+ if (argc != 2) {
+ cout << "Usage: " << argv[0] << " <number>\n";
+ exit(1);
+ }
+
+ string s = argv[1];
+
+#define OUTVAL(valtype, type) do { \
+ valtype value; \
+ cout << "TYPE = " #valtype "\n"; \
+ if (to_number(s, value)) { \
+ cout << "Number(" << s << ") = " << dec \
+ << (unsigned long long)(unsigned type)value << "\n" \
+ << "Number(" << s << ") = " << dec \
+ << (signed long long)(signed type)value << "\n" \
+ << "Number(" << s << ") = 0x" << hex \
+ << (unsigned long long)(unsigned type)value << "\n" \
+ << "Number(" << s << ") = 0" << oct \
+ << (unsigned long long)(unsigned type)value << "\n\n"; \
+ } else \
+ cout << "Number(" << s << ") is invalid\n\n"; \
+ } while (0)
+
+ OUTVAL(signed long long, long long);
+ OUTVAL(unsigned long long, long long);
+ OUTVAL(signed long, long);
+ OUTVAL(unsigned long, long);
+ OUTVAL(signed int, int);
+ OUTVAL(unsigned int, int);
+ OUTVAL(signed short, short);
+ OUTVAL(unsigned short, short);
+ OUTVAL(signed char, char);
+ OUTVAL(unsigned char, char);
+
+ return 0;
+}
diff --git a/src/unittest/symtest.cc b/src/unittest/symtest.cc
new file mode 100644
index 000000000..5fba71736
--- /dev/null
+++ b/src/unittest/symtest.cc
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <iostream.h>
+
+#include "base/str.hh"
+#include "base/loader/symtab.hh"
+
+Tick curTick = 0;
+
+void
+usage(const char *progname)
+{
+ cout << "Usage: " << progname << " <symbol file> <symbol>" << endl;
+
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ SymbolTable symtab;
+
+ if (argc != 3)
+ usage(argv[0]);
+
+ if (!symtab.load(argv[1])) {
+ cout << "could not load symbol file: " << argv[1] << endl;
+ exit(1);
+ }
+
+ string symbol = argv[2];
+ Addr address;
+
+ if (!to_number(symbol, address)) {
+ if (!symtab.findAddress(symbol, address)) {
+ cout << "could not find symbol: " << symbol << endl;
+ exit(1);
+ }
+
+ cout << symbol << " -> " << "0x" << hex << address << endl;
+ } else {
+ if (!symtab.findSymbol(address, symbol)) {
+ cout << "could not find address: " << address << endl;
+ exit(1);
+ }
+
+ cout << "0x" << hex << address << " -> " << symbol<< endl;
+ }
+
+ return 0;
+}
diff --git a/src/unittest/tokentest.cc b/src/unittest/tokentest.cc
new file mode 100644
index 000000000..7f27d58fe
--- /dev/null
+++ b/src/unittest/tokentest.cc
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include "base/str.hh"
+
+int
+main(int argc, char *argv[])
+{
+ using namespace std;
+
+ if (argc != 3) {
+ cout << "Usage: " << argv[0] << " <string> <token>\n";
+ exit(1);
+ }
+
+ int i;
+ string test = argv[1];
+ vector<string> tokens1;
+ vector<string> tokens2;
+ char token = argv[2][0];
+
+ cout << "string = \"" << test << "\", token = \'" << token << "\'\n";
+ cout << "testing without ignore\n";
+ tokenize(tokens1, test, token, false);
+
+ if (tokens1.size()) {
+ int size = tokens1.size();
+ cout << "size = " << size << "\n";
+ for (i = 0; i < size; i++) {
+ cout << "'" << tokens1[i] << "' (" << tokens1[i].size()
+ << ")" << ((i == size - 1) ? "\n" : ", ");
+ }
+ } else {
+ cout << "no tokens" << endl;
+ }
+
+ cout << "testing with ignore\n";
+ tokenize(tokens2, test, token, true);
+
+ if (tokens2.size()) {
+ int size = tokens2.size();
+ cout << "size = " << size << "\n";
+ for (i = 0; i < size; i++) {
+ cout << "'" << tokens2[i] << "' (" << tokens2[i].size()
+ << ")" << ((i == size - 1) ? "\n" : ", ");
+ }
+ } else {
+ cout << "no tokens" << endl;
+ }
+
+ return 0;
+}
diff --git a/src/unittest/tracetest.cc b/src/unittest/tracetest.cc
new file mode 100644
index 000000000..866b67d9b
--- /dev/null
+++ b/src/unittest/tracetest.cc
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "sim/host.hh"
+#include "base/trace.hh"
+
+using namespace std;
+
+Tick curTick = 0;
+
+struct foo
+{
+ foo()
+ {
+ char foo[9] = "testing";
+ DPRINTF(Loader, "%s\n", foo);
+ }
+};
+
+int
+main()
+{
+ Trace::flags[Trace::Loader] = true;
+ Trace::dprintf_stream = &cout;
+
+ foo f;
+
+ return 0;
+}