summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Raasch <sraasch@umich.edu>2003-10-07 10:41:54 -0400
committerSteve Raasch <sraasch@umich.edu>2003-10-07 10:41:54 -0400
commit92638f9a657207ad6f0bc301597d9e1a3c1158e2 (patch)
treed4d92c89ddcc252ceefaea00513d34984043924b
parenta06eab767e186d309512950183176a57cb1be9d0 (diff)
downloadgem5-92638f9a657207ad6f0bc301597d9e1a3c1158e2.tar.xz
Import changeset
Doxyfile: LICENSE: arch/alpha/alpha_memory.cc: arch/alpha/alpha_memory.hh: arch/alpha/arguments.cc: arch/alpha/arguments.hh: arch/alpha/ev5.cc: arch/alpha/ev5.hh: arch/alpha/fake_syscall.cc: arch/alpha/faults.cc: arch/alpha/faults.hh: arch/alpha/isa_desc: arch/alpha/isa_traits.hh: arch/alpha/osfpal.cc: arch/alpha/osfpal.hh: arch/alpha/vtophys.cc: arch/alpha/vtophys.hh: arch/isa_parser.py: base/bitfield.hh: base/callback.hh: base/circlebuf.cc: base/circlebuf.hh: base/cprintf.cc: base/cprintf.hh: base/cprintf_formats.hh: base/date.cc: base/dbl_list.hh: base/endian.hh: base/fast_alloc.cc: base/fast_alloc.hh: base/fifo_buffer.cc: base/fifo_buffer.hh: base/hashmap.hh: base/inet.cc: base/inet.hh: base/inifile.cc: base/inifile.hh: base/intmath.cc: base/intmath.h: base/kgdb.h: base/misc.cc: base/misc.hh: base/mod_num.hh: base/object_file.cc: base/object_file.hh: base/pollevent.cc: base/pollevent.hh: base/random.cc: base/random.hh: base/range.hh: base/refcnt.hh: base/remote_gdb.cc: base/remote_gdb.hh: base/res_list.hh: base/sched_list.hh: base/socket.cc: base/socket.hh: base/statistics.cc: base/statistics.hh: base/str.cc: base/str.hh: base/symtab.cc: base/symtab.hh: base/trace.cc: base/trace.hh: dev/alpha_access.h: dev/alpha_console.cc: dev/alpha_console.hh: dev/console.cc: dev/console.hh: dev/disk_image.cc: dev/disk_image.hh: dev/etherbus.cc: dev/etherbus.hh: dev/etherdump.cc: dev/etherdump.hh: dev/etherint.cc: dev/etherint.hh: dev/etherlink.cc: dev/etherlink.hh: dev/etherpkt.hh: dev/ethertap.cc: dev/ethertap.hh: dev/pcireg.h: dev/simple_disk.cc: dev/simple_disk.hh: kern/tru64/tru64.hh: kern/tru64/tru64_syscalls.cc: kern/tru64/tru64_syscalls.hh: sim/async.hh: sim/base_cpu.cc: sim/base_cpu.hh: sim/cache/lzss_compression.cc: sim/cache/lzss_compression.hh: sim/cache/null_compression.hh: sim/debug.cc: sim/debug.hh: sim/eventq.cc: sim/eventq.hh: sim/exec_context.cc: sim/exec_context.hh: sim/exetrace.cc: sim/exetrace.hh: sim/host.hh: sim/hybrid_pred.cc: sim/hybrid_pred.hh: sim/intr_control.cc: sim/intr_control.hh: sim/main.cc: sim/memtest.cc: sim/memtest.hh: sim/op_class.hh: sim/param.cc: sim/param.hh: sim/pc_event.cc: sim/pc_event.hh: sim/predictor.hh: sim/prog.cc: sim/prog.hh: sim/sat_counter.cc: sim/sat_counter.hh: sim/serialize.cc: sim/serialize.hh: sim/sim_events.cc: sim/sim_events.hh: sim/sim_exit.hh: sim/sim_object.cc: sim/sim_object.hh: sim/sim_time.cc: sim/sim_time.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: sim/smt.hh: sim/static_inst.cc: sim/static_inst.hh: sim/std_types.hh: sim/system.cc: sim/system.hh: sim/universe.cc: test/Makefile: test/bitvectest.cc: test/circletest.cc: test/cprintftest.cc: test/foo.ini: test/initest.cc: test/initest.ini: test/lru_test.cc: test/nmtest.cc: test/offtest.cc: test/paramtest.cc: test/rangetest.cc: test/sized_test.cc: test/stattest.cc: test/strnumtest.cc: test/symtest.cc: test/tokentest.cc: test/tracetest.cc: util/rundiff: util/tap/Makefile: util/tap/tap.cc: util/term/Makefile: util/term/term.c: RCS to BitKeeper sim/main.cc: Initial revision sim/main.cc: Added base SMT support to SS3 distribution sim/main.cc: Corrected statistics in sim-smt Added "cnt_*" statistics to sim-smt and sim-outorder Added execution tracing to sim-outorder sim/main.cc: Numerous minor fixes. Implemented Ideal and Random fetch policies. Numerous new statistics. sim/main.cc: A few minor bug fixes to collapsing RUU & "ideal" fetch policy. sim/main.cc: Snapshot of MICRO99 work in progress. Lots of SMT stuff, EIO fixes, etc. sim/main.cc: -> New fetch stage: - Fetch a block at a time - Execute in fetch -> Removed execute from ruu_dispatch() -> Cleaned up sim/main.cc: Added build time-stamp to top of simulation log sim/main.cc: Corrected error in priority rotation routine Added -max:mult option Modified makefile to use egcs compiler Added the -t option bkdwn.pl sim/main.cc: Added memory usage display Fixed #define for number of RS_LINKs sim/main.cc: Should be able to build other simulators (sim-fast, sim-eio, etc.) using "make -f Makefile.orig" (for Alpha at least, not quite for PISA). sim/main.cc: More SMT vs. non-SMT cleanup: 'make sim-X' now works for most X. sim/main.cc: Changed function of Fetch/Decode/Dispatch pipe: a) Fetch only if room in fetch queue b) Decode only if pipe advanced as a result of dispatching a packet c) Dispatch a packet only if: 1) Room for all insns in RUU 2) Room for all insns in LSQ 3) Room for all insns in INT Register File 4) Room for all insns in FP Register File Added ROB structure a) Instruction is placed in RUU & ROB at dispatch b) Instruction is removed from RUU at writeback (except stores) c) Instruction is removed from ROB at commit Added support for counting physical register usage (INT and FP) a) subtract from "free" count at dispatch b) add back when instruction is removed from ROB Added "my_index" field to RUU_station (simplifies reverse-lookups) Removed all remaining ptrace stuff RUU & LSQ now dump squashed instructions instead of marking them squashed - No cost! Reworked commit stage to use ROB instea sim/main.cc: - Added sc_dist1 stat type as a user-transparent special case of distribution with unit-size buckets: saves an unnecessary divide on every sample - Minor changes to compile as C++ code base/fast_alloc.cc: base/fast_alloc.hh: Major reorganization. Split sim-smt.c into multiple files, compile with C++, split ROB & RUU structures, numerous small formatting and performance changes. sim/eventq.cc: sim/eventq.hh: - Replaced SimpleScalar event queue code with smt_eventq.{cc,hh} - Eliminated unused cache:flush option - Initialize bpred history regs and BTB and RAS entries to provide repeatable results - Added reset_spec_state() function: cleans up interface to spec_state.c sim/eventq.cc: sim/eventq.hh: Major reorganization of memory-system code and interface. base/fast_alloc.cc: sim/eventq.cc: sim/eventq.hh: Moved C++ files to .cc/.hh, compile C files with C compiler. base/dbl_list.hh: Initial check-in: doubly-linked list template class. sim/eventq.hh: Added when_created and when_scheduled time-tags for debugging base/fast_alloc.hh: Plug memory leak sim/eventq.cc: Runahead_Prefetch memory-system support, including miss notification events in cache. sim/eventq.cc: sim/eventq.hh: Merged branch "mt-frontend" into trunk of CVS tree Changes include: Multi-threaded Fetch & Decode Correct functionality of branch misprediction fixup (MT only) Improved stats base/intmath.cc: base/intmath.h: Integer math functions. base/fast_alloc.cc: base/fast_alloc.hh: Remove carriage returns. base/intmath.h: Add Min/Max template functions sim/prog.cc: sim/prog.hh: Adding smt-safe and smt-fast. These are functional simulators based on sim-safe and sim-fast. Despite their names, they do not actually don't handle multithreaded programs yet. The runfile functionality was pulled out of sim-smt.cc into its own files. This allows all three simulators to use runfiles. NOTE: There is a lot of duplicated code in these three simulators that should probably be separated out. The macro type definitions in engin.hh are similar to the definitions in smt-safe.cc and smt-fast.cc sim/prog.cc: Add support for loading a kernel with simplescalar. Also add skeleton for loading a disk image to boot from with simplescalar. Hook for loading palcode is in place, but not implemented. Initial parameters passed to kernel at boot time are not passed properly. sim/prog.cc: Only support loading kernel/disk image if we're running FULL_SYSTEM sim/prog.cc: Make loading PAL a separate operation. Also separate kernel loading and disk loading so that it can only be done in FULL_SYSTEM. Finally, we need to also load the console image file. I'm not sure what's in there, maybe some stuff from SRM, but it's needed for proper execution. dev/alpha_console.cc: dev/alpha_console.hh: Console device implementation from simos. This is a simple device that supports the necessary console functions for booting. sim/prog.cc: sim/prog.hh: Separate the kernel loader and the program loader for simplicity since they don't share much code. arch/alpha/alpha_memory.hh: Add this somewhat gross hack to take care of the fact that alpha has the this load locking and conditional store mechanism. sim/prog.cc: Enable asids again. This makes multithreaded programs work again. I guess you could say that this was an accidental commit. Sorry sim/main.cc: Clean up Simplescalar copyright notice. sim/prog.cc: Allow '-' for stdout as well as stdin in run file. dev/alpha_console.cc: dev/alpha_console.hh: sim/prog.cc: arch/alpha/alpha_memory.hh: Replace the interface to the memory system. Basically this change goes away from the model of passing an address, and a number of bytes and getting/setting data. This change rather creates a memory_request packet (a simple struct) that bundles all of the necessary information together to pass into the memory system when making a request. This makes the function call syntax consistent even when you have virtual to physical translation and when you have strange flags like locked, or physical that you need to pass to your memory system. It has the added benefit of allowing the layers to pass data to each other, possibly skipping layers in between. This was necessary for the whacked out behavior that store conditional has on alpha. In addition, the entire memory system is now consistent in that it will return an alignment fault due to an unaligned access. This is necessary to properly model a full alpha system, but changes the behavior of bogus bad path loads and stores that access unaligned data. Because base/fast_alloc.cc: base/fast_alloc.hh: Major enhancement of FastAlloc debug code (uncomment #define in fast_alloc.hh to enable). Can now dump summary of in-use objects by type and address/type of oldest n objects (thank you RTTI!). Should be easier to identify memory leaks now. base/res_list.hh: file res_list.hh was initially added on branch segmented_iq. sim/sat_counter.hh: file sat_counter.hh was initially added on branch segmented_iq. sim/std_types.hh: file std_types.hh was initially added on branch segmented_iq. base/fast_alloc.hh: base/res_list.hh: sim/sat_counter.hh: sim/eventq.cc: sim/eventq.hh: sim/prog.cc: sim/std_types.hh: Merged branch "segmented_iq" -> Objectized the IQ and LSQ -> Implemented Standard, Sezned, and Segmented IQ's -> Major fixes to wrong-path execution (primarily involving data dependencies) base/res_list.hh: g++ is braindead, so I cannot pull template functions out into a .cc file. Instead, pull large functions out of the class definition and inline them. This leads to a much more readable class definition. In addition, since these functions are inlined, youseems to be what is intended anyway. sim/prog.cc: Move some variables to smt_prog so that targets other than sim-smt can use them. sim/main.cc: remove the dlite debugger (for smt at least) dev/alpha_console.cc: sim/eventq.cc: sim/main.cc: I knew I had done this for a reason Change 64 bit types back to long for alpha and replace all instances of stuff like %lld to use FMT64d and the like. The reason this is necessary is because TRU64 does not understand what %lld is and will print out "ld" instead of actually printing the number. So, PLEASE use the FMTxxx stuff instead of sticking %lld, %llx, %016llx and such into the code. sim/main.cc: Don't want FMT64d for things declared 'long': this doesn't work when FMT64d evaluates to "%lld". Just use "%ld" instead. dev/console.cc: dev/console.hh: dev/disk_image.cc: dev/disk_image.hh: dev/pcireg.h: dev/simple_disk.cc: dev/simple_disk.hh: Add several initial devices for full alpha system simulation. Many of these devices are based on SimOS devices dev/alpha_console.cc: dev/alpha_console.hh: Update the alpha_console to take advantage of the simple disk interface sim/eventq.cc: sim/eventq.hh: Make it so you can service events that will happen in the future base/trace.cc: base/trace.hh: This is a simple tracing facility. The idea is that there is a bitvector where each bit represents something that you may want to trace. The end result is that you can at runtime turn on and off different tracing statements in the code so that you only see messages for things that you care about. This is only currently used in the devices framework, but I would like to see it eventually replace the debug, warn, and info functions. sim/intr_control.hh: Initial abstraction for a processor and interrupt controller arch/alpha/alpha_memory.cc: arch/alpha/alpha_memory.hh: Add full support for the SYSTEM_EV5 model in smt-safe. With this model, the user should be able to boot Tru64 unix. Several aspects of the memory subsystem were changed to accomidate this ability: - The C memory access functions no longer return an md_fault_type. - The prot_* functions no longer take a memrequest, and no longer return an md_fault type. They now take a single address and a size. This is because the prot_* functions don't need translation abilities, etc. - The prot_* functions will by default fail to work unless they are specifically implemented for the class that you want to use them with. - The unaligned parameter to the READ_* and WRITE_* function calls was added back so that exceptions that occur on STQ_U, LDQ_U, etc get the proper faulting address. - The memory controller now supports adding an arbitrary number of objects at arbitrary memory ranges so that a variety of devices can be accomidated. - The physical_memory class now not only emulates a specific amount of memor base/trace.cc: Check for existence of environment variable dev/console.cc: Temporary fix to get this to compile under Linux. sim/main.cc: Flush stdout before dumping stats. sim/exec_context.cc: sim/exec_context.hh: sim/exetrace.cc: sim/exetrace.hh: sim/main.cc: sim/prog.cc: sim/prog.hh: arch/alpha/alpha_memory.cc: arch/alpha/alpha_memory.hh: arch/alpha/fake_syscall.cc: Pull per-cpu variables into cpu_t object as first step toward multiprocessor support. Also encapsulated execution context into a single object. Program loading code also significantly reorganized. Syscall redirection to host machine temporarily broken (must use EIO files for now). arch/alpha/fake_syscall.cc: sim/eventq.cc: sim/exec_context.cc: sim/exetrace.cc: sim/main.cc: sim/prog.cc: Update source tree to deal with shuffling of files and renaming of files. Maybe a tiny bit of style here and there for kicks too. sim/prog.cc: Fix more stuff for reorg. arch/alpha/alpha_memory.cc: arch/alpha/alpha_memory.hh: arch/alpha/fake_syscall.cc: base/dbl_list.hh: base/fast_alloc.cc: base/fast_alloc.hh: base/intmath.cc: base/intmath.h: base/res_list.hh: base/trace.cc: base/trace.hh: dev/alpha_console.cc: dev/alpha_console.hh: dev/console.cc: dev/console.hh: dev/disk_image.cc: dev/disk_image.hh: dev/pcireg.h: dev/simple_disk.cc: dev/simple_disk.hh: sim/main.cc: sim/eventq.cc: sim/eventq.hh: sim/exec_context.cc: sim/exec_context.hh: sim/exetrace.cc: sim/exetrace.hh: sim/intr_control.hh: sim/prog.cc: sim/prog.hh: sim/sat_counter.hh: sim/std_types.hh: Some style changes remove all of the $Log$ crap add $Id$ strings to the top of all files. arch/alpha/alpha_memory.cc: Convert memory request objects to have a bitvector of flags. sim/sat_counter.hh: Minor bug-fixes to statistics & options Saturating counter wasn't initializing properly arch/alpha/fake_syscall.cc: Compile on OpenBSD base/fast_alloc.cc: dev/console.cc: dev/disk_image.cc: sim/eventq.cc: sim/eventq.hh: sim/exec_context.hh: sim/exetrace.cc: sim/exetrace.hh: sim/intr_control.hh: sim/prog.cc: sim/sat_counter.hh: Move extern "C" statements out of C++ files and into the C headers with #ifdef __cplusplus guarding the extern. base/str.cc: base/str.hh: My lame old reference counting string class. It's really not too bad. base/intmath.cc: removed unused variable sim/main.cc: add option -inifile to load the config file base/inifile.cc: base/inifile.hh: sim/main.cc: rename configfile to inifile base/intmath.h: Functions to determine if a character is hex, dec, oct. Convert hex to int base/str.cc: base/str.hh: Add a tokenize function. Fix a bug in the CopyRight function Add a const iterator Add a string to number function that will deal with hex, decimal, octal, positive numbers and a few suffixes. Complete with bounds checking and syntax checking base/inifile.cc: base/inifile.hh: Cope with fix in CopyRight function from the String class. Add a find default which whill check for a Default= parameter. Add #include guards dev/alpha_console.cc: style. change assertion sim/sat_counter.hh: Added instruction-type identification methods to dyn_inst Continued work on the segmented IQ: - Stats - Seg0 load mechanisms - "short" dump function - free_slots_last_cycle model improvement Added stats to sat_counter sim/main.cc: Parse .ini file for options in main.cc. sim/main.cc: Reindent following style guide. sim/sat_counter.hh: Updates to the segmented IQ sim/hybrid_pred.hh: Initial check-in sim/predictor.hh: Initial check-in of predictor Mods to predictor stats sim/hybrid_pred.hh: sim/predictor.hh: sim/sat_counter.hh: Class heirarchy fixes sim/predictor.hh: sim/sat_counter.hh: Now the predictors actually work! sim/sat_counter.hh: Final fixes to the SaturatingCounterPred Corrections to the LRP and HMP sim/sat_counter.hh: Bug fixes and predictor mods to segmented IQ during ISCA-2002 work Dumping of queue contents is a little more flexible for debugging arch/alpha/fake_syscall.cc: sim/prog.cc: Updated fake syscall support (for most common syscalls) so we can once again run straight binaries (not just EIO files). sim/sat_counter.hh: Final updates (for now) to the Segmented IQ Cleaning up the fetch stage Speed improvements to the Saturating Counter Predictor Object sim/prog.cc: sim/prog.hh: Fix parameter bug in process_t::dup_fd (causing stdio fd's not to get remapped correctly). base/str.hh: Add forward decl of class ostream base/inifile.cc: base/inifile.hh: Rename members to conform to common style. base/inifile.cc: Oops... looks like CPP_PIPE doesn't work. sim/main.cc: sim/sat_counter.hh: sim/sim_object.cc: sim/sim_object.hh: New configuration scheme based on .ini files and hierarchical descriptions. Currently in a transitional state: only sim_smt CPU, IQ, Cache, Bus, and Mem objects are configured this way. Old mmodel.{hh,cc} completely gone. base/inifile.cc: Fix pipe directionality for Linux: CPP_PIPE works again. sim/sim_object.cc: Updates for INI-file parameters for Seznec and Segmented IQ models Fixed naming of IQ classes sim/sim_object.cc: sim/sim_object.hh: - Minor revisions to ParamContext, SimObjectBuilder, etc. to allow creation of SimObjects outside of configuration hierarchy. - Encapsulated magic boilerplate for object creation in macros to simplify usage and make future changes like this simpler. arch/alpha/fake_syscall.cc: sim/exec_context.cc: sim/exec_context.hh: sim/prog.cc: sim/prog.hh: Rename process_t --> Process, eio_process_t -> EioProcess, live_process_t -> LiveProcess base/str.cc: base/str.hh: flesh out string class base/str.cc: This time commit the right file. base/str.cc: fix Tokenize for the case where the last string is only a single character sim/sim_object.cc: Instantiate Param<String>::showValue(). sim/sim_object.cc: sim/sim_object.hh: - Auto-register global parameter contexts for non-SimObject parameters - added ParamContext::parseAllContexts() - Finish and test enum params (SimpleEnumParam, MappedEnumParam) - Add vector-valued parameters: VectorParam<T>, SimObjectVectorParam, SimpleEnumVectorParam, MappedEnumVectorParam - Factor parsing & displaying functions to share code between scalar and vector parameter objects - Fix bug where a SimObjectClass constructor could be called before the static SimObjectClass::classMap constructor - Add "help" functions to dump parameter descriptions (ParamContext::describeAllContexts() and SimObjectClass::describeAllClasses()) sim/main.cc: Dump out config file parameters on '-h' cmd-line argument. sim/sim_object.cc: sim/sim_object.hh: - Add showType() method to display parameter type as string for help - Change EnumParam types to include specific enum type (avoids casting) sim/sim_object.hh: Minor updates for statistics, new compilers, etc. Moved some options into new options model base/inifile.cc: base/inifile.hh: sim/exetrace.cc: sim/exetrace.hh: sim/main.cc: sim/param.cc: sim/param.hh: sim/prog.cc: sim/prog.hh: sim/sim_object.cc: sim/sim_object.hh: Eliminated old SimpleScalar options package from sim_smt, shifting everything over to new parameter objects fed by .ini-style configuration files. Parameters can be set on command line using '--<sec>:<param>=<value>'. All other cmd-line options are assumed to be config file names, except '-h' prints help msg. Got rid of *_reg_options(), *_check_options(), *_uninit() calls. Moved more initialization into constructors; remaining code is now automagically executed by providing checkParams() and cleanup() methods on ParamContext-derived objects. (See exetrace.cc, for example.) Runfile is gone; processes are initialized as simulation objects. Split parameter code out of sim_object.{cc,hh} into param.{cc,hh}. Moved a bunch of CPU object methods from sim_smt.cc to cpu.cc. smt_reg_stats calls now need to know number of threads. Can be done by explicit argument to global function, or (for backward compatibility) calling CPU object method with same parameters as old global function. Renamed "SimControl" par base/circlebuf.cc: base/circlebuf.hh: Add a circular buffer class that holds string data. You can set the size of the buffer, and basically keep writing to it, and later read the last size bytes from the buffer. kinda like tail -f test/Makefile: test/bitvectest.cc: test/circletest.cc: test/foo.ini: test/initest.cc: test/initest.ini: test/strnumtest.cc: test/tokentest.cc: Add a little bit of test framework and a bunch of initial tests test/paramtest.cc: Move the param test thing to the new test framework, though it doesn't compile right now since I couldn't figure it out base/inifile.cc: Disable pipes for cpp: hangs if cpp output is bigger than kernel pipe buffer. sim/sim_object.cc: Check for accidental redefinition of SimObject class names. base/str.cc: Support exponents in StringToNumber. It should be noted, that while StringToNumber does bounds checking, the bounds checking has not been mathmatically proven, so it could have mistakes. base/range.hh: Simple range class that will parse a range and provides comparison operators base/trace.hh: New tracing options test/Makefile: test/rangetest.cc: add a new test for the Range class sim/exetrace.cc: sim/exetrace.hh: sim/main.cc: Create an ExecutionTrace class that encapsulates the old exe_trace stuff. Convert the last of the old options stuff to the new params and get rid of the old options files. Get rid of the old range files. arch/alpha/fake_syscall.cc: Stupid linuxisms sim/main.cc: sim/sim_object.cc: Output config info to cerr instead of cout. sim/main.cc: Load default.ini if the file exists test/Makefile: test/bitvectest.cc: test/circletest.cc: test/initest.cc: test/paramtest.cc: test/rangetest.cc: test/strnumtest.cc: test/tokentest.cc: Add Id tags sim/sim_object.cc: Bug fix to allow use of "default=" in ini-files sim/prog.cc: Fix for wacky compiler bug base/inifile.cc: Modified some ROB statistic labels to make them more uniform Re-implimented rob-caps arch/alpha/vtophys.cc: arch/alpha/vtophys.hh: Add support for doing virtual to physical translation using the in-memory page table base/kgdb.h: base/remote_gdb.cc: base/remote_gdb.hh: Basic support for remote debugging base/pollevent.cc: base/pollevent.hh: A class abstraction for poll base/socket.cc: base/socket.hh: Support for tcp server sockets base/symtab.cc: base/symtab.hh: simple symbol table loaded from a preprocessed file dev/alpha_access.h: dev/alpha_console.hh: split alpha access into a separate file so that building console code is simpler dev/disk_image.cc: dev/disk_image.hh: use a string for the disk image file name instead of a char * arch/alpha/alpha_memory.cc: Make the MCSR segment check more explicit rearrange base/trace.cc: Make trace stuff use new parameter stuff base/trace.hh: Fix DPRINTF and DPRINTFN macros Add a few new trace flags sim/exetrace.cc: sim/exetrace.hh: Add more features to the exetrace stuff. Make use of the symbol table support. base/remote_gdb.cc: fix DPRINTFs dev/alpha_console.cc: dev/console.cc: dev/console.hh: Change the console framework to use the new pollevent stuff. This adds support for a console that can be attached and detached at runtime via a tcp connection (telnet). There is also a circular buffer integrated into the console so that upon connection, any missed console text is output to the console. In the future, this should easily allow for multiple system consoles to be attached. base/inifile.cc: base/str.hh: Move the string hash function base/symtab.cc: base/symtab.hh: sim/exetrace.cc: Add support to lookup symbols by name, and take advantage of that support for looking up symbols for panic and badaddr base/str.cc: base/str.hh: change to new formatting. naming convention still dosn't match new style dev/console.cc: dev/console.hh: Fix console code so that typed characters are properly handled. When clearing interrupts, be explicit with regards to which ones. arch/alpha/vtophys.cc: a tad bit of error checking sim/exetrace.cc: sim/exetrace.hh: EXE-Trace extensions Disabled "good_mem" memory layer... this still needs to be properly removed base/kgdb.h: Add more kgdb commands base/trace.hh: Tracing for ISP sim/exec_context.cc: sim/exec_context.hh: sim/exetrace.cc: sim/exetrace.hh: sim/prog.cc: sim/prog.hh: Update to BTB functionality Fixed numerous statistics Fixed path of store instructions so that they _all_ go through issue stage Updates to exetrace functionality sim/eventq.cc: sim/eventq.hh: Replaced every-cycle termination checks in sim_main() with events. Added per-thread instruction-count-based event queues to handle termination based on committed instruction count. These are now specified via parameters to the FullCPU object (max_insts_any_thread and max_insts_all_threads) rather than global parameters under the [max] context. Also replaced break_cycle check with DebugBreakEvent. Some cleanup of eventq.{cc,hh}. sim/prog.hh: Don't die if included under FULL_SYSTEM: just skip contents. sim/base_cpu.cc: sim/base_cpu.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: Added SimpleCPU object to do sim_safe type simulation in sim_smt. Created abstract base class BaseCPU as common parent of (detailed) CPU and SimpleCPU. sim/exec_context.cc: sim/exec_context.hh: sim/prog.cc: sim/prog.hh: Register Process object stats using SimObject reg_stats() method rather than indirectly via Thread end exec_context objects. sim/base_cpu.cc: sim/base_cpu.hh: sim/main.cc: sim/sim_object.cc: sim/sim_object.hh: Changes to eliminate the global 'the_cpu' pointer to allow for mutliple CPUs/systems. Specifically: - Add findMaxThreadsPerCPU() and tickAll() static methods to BaseCPU class. - Added generic printExtraOutput() method for all SimObjects, to dump output at the end of simulation that is not covered by stats. Use this hook on CPU object to call dump_floss_reasons(). sim_aux_stats() is now obsolete. - printExtraOutput() takes an ostream& rather than a FILE*, so dump_floss_reasons() had to be converted to C++ I/O. - Fixed a bug in floss_reasons.cc where an additional mem_access_result_t item (MA_NOT_PREDICTED) did not have a corresponding entry in mem_access_result_item_descr. This resulted in "(null)" being printed with sprintf I/O (which no one had noticed, apparently), but caused a segfault using streams. sim/exec_context.hh: sim/main.cc: sim/prog.cc: sim/prog.hh: sim/sat_counter.hh: sim/simple_cpu.cc: Rename many stats to include config hierarchy path, so results from different CPUs/systems can be distinguished. Move stats.c/h into C++... renamed to stats.cc/hh. Added overloads of most stat registration functions to allow 'string' rather than 'char *' stat names & formulas... no more sprintf needed! sim/base_cpu.cc: sim/base_cpu.hh: Add sim_num_insn stats as per-CPU and total number of simulated instructions so we can continue to calculate sim_inst_rate. sim/simple_cpu.cc: Fix sim_num_insn stat for SimpleCPU. sim/simple_cpu.cc: sim/simple_cpu.hh: Move global memory interface objects into SimpleCPU object. Made read/write functions SimpleCPU members for easier access to same. Can now do multiple systems in non-FULL_SYSTEM mode. sim/param.hh: sim/sim_object.cc: sim/sim_object.hh: SimObjects now look in the .ini database first using the object instance name (e.g., sys.cpu0) *then* using the configuration class name (e.g., DetailedCPU). This makes it easier to use a common description but override a few simple things like the workload. base/remote_gdb.cc: dev/console.cc: dev/disk_image.cc: Make ConsoleListener & GDBListener explicitly print which ports they're listening on. arch/alpha/alpha_memory.cc: arch/alpha/ev5.cc: arch/alpha/ev5.hh: arch/alpha/fake_syscall.cc: arch/alpha/vtophys.hh: base/remote_gdb.cc: base/symtab.cc: base/symtab.hh: dev/alpha_console.cc: dev/alpha_console.hh: dev/console.cc: sim/exec_context.cc: sim/exec_context.hh: sim/exetrace.cc: sim/exetrace.hh: sim/main.cc: sim/prog.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: Cleanup of full-system global variables, primarily in simple_cpu.cc, to allow multi-system simulations. (Multiple systems not yet yested though.) Also changes to build sim_smt in full-system mode (though with only SimpleCPU and not the full timing CPU for now). Still to do: minimize changes in SimpleCPU code between full-system and application modes... way too many ifdefs there. Much of the full-system stuff moved into SimpleCPU should be put in a new System object to allow multiprocessor simulations. Converted last remaining modules from C to C++ (mostly in /old). Renamed all .c files to .cc and a few .h files to .hh. Renamed architecture-specific files in arch/$TARGET from $TARGET.{cc,hh,def} to machine.{cc,hh,def} to get rid of pointless intermediate files in object directory. Split exo-specific definitions out of machine.hh into machine_exo.h. Specifics: In machine.def, null resource descriptors must be FUClamd_NA (and not NA) to pass C++ type checking. Enhanced error checking/reporting in bas base/range.hh: Use the templated type for intermediate storage. Added "valid" flag and method to the user can determine if the range parse or assignment was successful. sim/eventq.cc: sim/eventq.hh: Modifications to properly count commited instructions... [no impacts] test/Makefile: test/offtest.cc: New test test/foo.ini: test/initest.cc: add Another piece to the test arch/alpha/ev5.hh: Properly do alternate mode arch/alpha/alpha_memory.cc: arch/alpha/ev5.cc: sim/simple_cpu.cc: arch/alpha/ev5.cc: arch/alpha/isa_traits.hh: base/hashmap.hh: formatting arch/alpha/alpha_memory.cc: C style comment -> C++ style arch/alpha/alpha_memory.cc: more formatting arch/alpha/alpha_memory.cc: Add ALT_MODE support to the tlb lookup and make mode handling more sane test/Makefile: test/symtest.cc: Add a test for the symboltable base/symtab.cc: Avoid some temporary objects base/trace.cc: add a hexdump like dump function for dumping memory base/trace.hh: Add more trace flags Add DUMP which does a hexdump with semantics like DPRINTF flush standard out after a debugging print or dump dev/simple_disk.cc: Add some debugging dumps sim/param.cc: sim/param.hh: sim/sim_object.cc: Because of order of construction, call a function that will return a ParamList that will construct it as soon as it is needed dev/pcireg.h: sim/simple_cpu.cc: sim/simple_cpu.hh: Flesh out the pci configuration space support. Add configuration file support for vendor ID and device ID. Clean up debugging sim/simple_cpu.cc: sim/simple_cpu.hh: Don't execute pmap_scavenge_boot. rename console_panic_addr to panic_addr. change some warn()s to DPRINTF() base/pollevent.cc: base/pollevent.hh: Don't poll every cycle. Use SIGIO to kick a poll off. Make it possible to disable events sim/exetrace.cc: sim/exetrace.hh: sim/simple_cpu.cc: Completely rework the exetrace stuff. Make a clas that holds all of the trace data for a particular cycle. Add a N entry trace log so that one can dump the last N cycles leading up to some sort of crash. When printing a branch instruction, print the target symbol if available instead of the address dev/console.cc: dev/console.hh: sim/simple_cpu.cc: Make console code deal with not being polled every cycle sim/simple_cpu.cc: Don't interrupt while in PAL base/remote_gdb.cc: base/remote_gdb.hh: constify some functions. fix some buffer handling. add some debugging help sim/param.cc: Initialize paramList to NULL sim/exetrace.cc: sim/exetrace.hh: sim/simple_cpu.cc: Rework the execution trace stuff again. Merge the cycle log and the exetrace into one class. Stick the TraceData in the dyn_inst_t class. Put the read_foo and write_foo functions in the dyn_inst_t class. This gets rid of the memaccess namespace. sim/exetrace.cc: sim/exetrace.hh: sim/simple_cpu.cc: Don't worry about which thread to trace right now. Fix that later. Add better support for merged logging and tracing. Make sure that there is a place to put data when there is no log. Make tracing work for non-system. sim/exetrace.hh: tracing() method must not return true if not initialized sim/base_cpu.cc: sim/main.cc: Many fixes to statistics (especially distributions) Many renamed statistics (added CPU name to all except cache stuff) dev/alpha_access.h: dev/alpha_console.cc: dev/alpha_console.hh: dev/console.cc: dev/console.hh: dev/disk_image.cc: dev/disk_image.hh: dev/simple_disk.cc: dev/simple_disk.hh: sim/intr_control.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: style fixes: Make class names follow the ClassName style Indenting based on four spaces sim/param.cc: Added pipetracing (The trace output _should_ be compatible with the original Simplescalar output, making their visualization tools available to us and providing us with a more detailed debugging tool than exetrace) base/trace.hh: Separate disk and disk data add tlaser uart arch/alpha/alpha_memory.cc: arch/alpha/ev5.cc: Make this use C++ instead of void * voodoo base/symtab.cc: base/symtab.hh: sim/exetrace.cc: sim/exetrace.hh: constify sim/param.hh: SimObjects are always pointers. Make this clear, and add the -> operator sim/prog.hh: fix comment dev/pcireg.h: Don't depend on order of #includes sim/exetrace.cc: Make logging work without tracing arch/alpha/alpha_memory.cc: arch/alpha/alpha_memory.hh: dev/alpha_console.cc: dev/alpha_console.hh: dev/console.cc: dev/console.hh: dev/disk_image.cc: dev/disk_image.hh: dev/simple_disk.cc: dev/simple_disk.hh: sim/intr_control.cc: sim/intr_control.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: Turn all of the devices and system stuff into SimObjects. Add many extra parameters to have config file flexibility base/sched_list.hh: file sched_list.hh was initially added on branch clustering. dev/console.cc: dev/disk_image.cc: Don't assume variables are initiaized to be zero sim/simple_cpu.cc: don't forget to dump the trace data if we're tracing arch/alpha/ev5.cc: arch/alpha/ev5.hh: sim/simple_cpu.cc: remove md_done_hwrei which was a hack that helped me make the trace output look like what I was able to get out of SimOS. Since we're more advanced than them, it's not needed sim/simple_cpu.cc: Try to make the trace more representative of what's going on. (Mainly around disruptions.) sim/simple_cpu.cc: Disable this code since it uses a hardcoded address. This may be more useful in the future though. sim/simple_cpu.cc: base/statistics.hh: oops base/trace.hh: style base/trace.hh: add tracing to interrupts sim/simple_cpu.cc: Removed old access call in CPUMemInterface and added MemREqs to the pipeline. sim/prog.cc: Give main memory a name to fix statistics. sim/main.cc: sim/serialize.cc: sim/serialize.hh: sim/sim_object.cc: sim/sim_object.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: Added basic infrastructure to do checkpointing. Simple test in SimpleCPU. base/trace.hh: Added support for checkpoint/serialization Added Serilize to list of know flags sim/param.cc: sim/serialize.hh: Added support for checkpoint/serialization Added Serilize to list of know flags Now add implicit SimObjects to the ConfigHierarchy so they can be unserialized. sim/serialize.hh: sim/simple_cpu.cc: Added WH64 implementation and dependencies Added WH64 implementation, and added the ability to do stores of more than 4 bytes, and sett loads to 8 bytes. base/inifile.hh: base/str.hh: Use functors for the hash functions for the hashtable class. Pulled up from the pisa branch with a few modifications. sim/eventq.cc: sim/eventq.hh: sim/serialize.cc: sim/serialize.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: Updated to Hierarchical naming Infrastructure for checkpointing. base/inifile.cc: base/inifile.hh: base/trace.hh: sim/exec_context.hh: sim/exetrace.cc: sim/main.cc: sim/param.cc: sim/param.hh: sim/simple_cpu.cc: test/Makefile: - Merge PISA branch onto HEAD - Tag before merge: HEAD_PRE_BR_PISA_MERGE - Tag after merge: HEAD_POST_BR_PISA_MERGE - Similar tags on PISA branch - Add port to SimpleScalar/PISA - New PISA instructions: itouch spill reload map unmap - Add prefetch implementation - Prefetch cache - Cache buffer (victim/prefetch buffers) - Prefetch queue - itouch instruction - Add functional SLAT implementation sim/main.cc: Make this work in non Linux base/remote_gdb.cc: sim/base_cpu.hh: sim/simple_cpu.cc: Make FULL_SYSTEM work again after the pisa merge. Random cleanups. sim/main.cc: sim/memtest.cc: sim/memtest.hh: Removed rules to make SIM_MEMTEST, added memtest.cc to smt source list Renamed sim_memtest to memtest. Memtest now extends BaseCPU and can be dropped into sim_smt. Still need to add the ability to stop it running without a manual ctrl-C though. Memtest currently does not test copies, just reads and writes. The multiple MSHR/Cache changes broke copying along the way. Just touched main to help debug (needed to give a set random seed). Its back to normal. sim/main.cc: undo erik's mistaken commit arch/alpha/alpha_memory.cc: arch/alpha/alpha_memory.hh: arch/alpha/vtophys.cc: base/circlebuf.cc: base/circlebuf.hh: base/inifile.cc: base/inifile.hh: base/pollevent.cc: base/pollevent.hh: base/range.hh: base/remote_gdb.cc: base/str.cc: base/str.hh: base/symtab.cc: base/symtab.hh: base/trace.cc: base/trace.hh: dev/alpha_console.cc: dev/alpha_console.hh: dev/console.cc: dev/console.hh: dev/disk_image.cc: dev/disk_image.hh: dev/simple_disk.cc: dev/simple_disk.hh: sim/base_cpu.cc: sim/base_cpu.hh: sim/eventq.cc: sim/eventq.hh: sim/exec_context.cc: sim/exetrace.cc: sim/exetrace.hh: sim/hybrid_pred.hh: sim/intr_control.cc: sim/intr_control.hh: sim/main.cc: sim/memtest.cc: sim/memtest.hh: sim/param.cc: sim/param.hh: sim/prog.cc: sim/prog.hh: sim/serialize.cc: sim/serialize.hh: sim/sim_object.cc: sim/sim_object.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: test/bitvectest.cc: test/foo.ini: test/initest.cc: test/initest.ini: test/paramtest.cc: test/rangetest.cc: test/strnumtest.cc: test/symtest.cc: test/tokentest.cc: - Get rid of my String class, the Vector class, the bitvector class, and my doubly linked list class. - Convert tokenize, to_number (formerly StringToNumber) and eat_white to function on stl strings. - Change most cases of char * and const char * to string, or const string & - Some formatting and style nits, but not too many. sim/param.cc: test/bitvectest.cc: use resize, not reserve to change the size of the actual vector base/str.hh: fix to_lower dev/console.cc: better tracing sim/memtest.cc: sim/memtest.hh: Added support for CoherenceTest Fixed small error that was leading to a fixed address being used half of the time. sim/exetrace.cc: sim/exetrace.hh: Improvements to EXE-Trace: Displays thread number (optionally) Doesn't display 'count' field (optionally) 'Extended' output lines up nicely sim/memtest.cc: Fixed a print warning in memtest.cc sim/exetrace.hh: sim/main.cc: sim/serialize.cc: sim/serialize.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: - Merge SLAT changes - Add stats to prefetch cache to track cycles lost due to each miss address - Get simple_cpu and FULL_SYSTEM to compile again. I'm not sure these will run correctly (simple_cpu should) but it is an improvement over what's currently available. Split the engine files into generic, cpu-specific and isa-specific files to isolate the various parts of the engine code. This is quite hackish in places due to machine.def (e.g. see comments in execute.cc). Further cleanup is warranted but it compiles and passes smt-test. Later commits will remove unused code. base/trace.hh: sim/param.cc: sim/sim_object.cc: add a new DTRACE macro that tests a trace variable if tracing is on, or evaluates to fals if tracing is off. Avoids #if TRACING_ON/#endif add an option for wheter or not you want the parameter stuff dumped while the simulator is starting sim/exetrace.cc: sim/exetrace.hh: Make the execution trace print the way it did before steve's last change. Also, pass the flags in a more intelligent manner rather than adding new function parameters all over the place. sim/exetrace.hh: sim/simple_cpu.hh: make exetrace work in FULL_SYSTEM after dave's last changes. Exetrace could probably be improved more to remove most of the #ifdef FULL_SYSTEM junk. Not today though base/trace.hh: new trace flags dev/alpha_console.cc: size was too big dev/pcireg.h: new device ID for simos ethernet device dev/disk_image.cc: dev/simple_disk.cc: dev/simple_disk.hh: be smarter about using stl strings sim/pc_event.cc: sim/pc_event.hh: PC based event system sim/simple_cpu.cc: Make all existing pc based stuff use the new pc based events base/trace.cc: base/trace.hh: sim/param.cc: sim/sim_object.cc: If we're not tracing, print out the configuration junk. If we are tracing, the configuration printing is default sim/exetrace.cc: - Fix bogus references to omitCount and includeTnum. base/kgdb.h: base/remote_gdb.cc: base/remote_gdb.hh: TONS of improvements to remote kernel debugging. - Use the pc based events stuff to simulate hardware breakpoints. - Implement the set/clear breakpoint/watchpoint function, though only breakpoints are implemented right now. Both software and hardware breakpoints are implemented as hardware breakpoints. - Fix numerous bugs in single stepping, and make temporary breakpoints use hardware breakpoints instead of software breakpoints. - Add tons of debugging stuff to help with future remote debugger debugging. (No, that was not an accidental doubling.) - Implement part of the query variable function. - Remove old cruft that we don't need. - Improve comments dev/disk_image.cc: dev/disk_image.hh: Copy on write disk support This code uses a hash table to implement copy on write support to disk image blocks. There is also support to write out the table and load it back in. dev/simple_disk.cc: This class uses std::string sim/simple_cpu.hh: don't need these base/circlebuf.cc: base/circlebuf.hh: Add some size information so we can keep track of wheter or not the buffer is empty arch/alpha/vtophys.cc: simplify base/object_file.cc: base/object_file.hh: initial framework for sucking in an object file and figuring out some stuff for it. Support for ecoff and a header for elf. There is nothing for relocations, but the symbol information is available so an external program is no longer required for that. base/symtab.cc: base/symtab.hh: Update some of the symbol table stuff to add support for manual insertion of symbols. This is used by the object file code so that we can read the table from the object file and stick it into the more efficient symtab test/Makefile: test/nmtest.cc: test program for using the symbol table code. Basically allows one to look up a symbol in an object file dev/console.cc: dev/console.hh: Clean up the console code, add an input buffer queue to avoid leaving data in the socket buffer. This allows us to preprocess data as it comes in for things such as telnet support. There is some minimal telnet support in here but it isn't working very well, and isn't enabled by default sim/simple_cpu.cc: sim/simple_cpu.hh: Make the various pc based events part of the CPU object instead of being global sim/simple_cpu.cc: sim/simple_cpu.hh: Do the badaddr stuff far more intelligently. Basically, what we do now is first determine if the address goes to any proper device. If not, the address is bad. If so, ask the device whether the address is any good or not. The default case is that a device will say that all of its addresses are good, but there are some devices that don't follow this paradigm. dev/alpha_console.cc: dev/alpha_console.hh: sim/intr_control.cc: sim/intr_control.hh: sim/universe.cc: Make the tick frequency a global parameter and have all devices work from that Also, make the timer interrupt delay parameterizeable (and make the default shorter). This should make boot happen a little faster base/refcnt.hh: Simple reference counting class. Could be replaced by boost shared_ptr some day. Classes that are reference counted must have exported functions incref() and decref() for manipulating the reference count. This doesn't have the convenience of shared_ptr where the shared classes can be used unmodified, but it also means that the refcnt pointer (the pointer in this code) is the size of a normal pointer for this system. dev/etherbus.cc: dev/etherbus.hh: dev/etherpkt.hh: Initial hack at a ethernet device model and an ethernet bus model. Known to be broken at this point arch/alpha/alpha_memory.cc: sim/simple_cpu.cc: Memory system enhancements: - Functional implementation of load-locked/store-conditional in main_memory object (the functional memory object for non-full-system mode). This code should eventually be extracted out and applied to both main_memory and physical_memory so that it works in full-system mode as well. Moved lock_flag & lock_addr from system registers to control registers so they're available in non-full-system mode. - Moved Alpha unaligned access handling back into machine.def. (It was a flag on the mem request and handled in the memory system, but that approach appears to be unnecessarily complicated.) - Cleanup of AlphaMemoryRequest: down from five constructors to one; Erik's full-word flags are now bits in Nate's flag word. - Eliminate obsolete memory.h functions, and some unused memory_object functions. arch/alpha/vtophys.cc: base/remote_gdb.cc: sim/prog.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: Renamed SimpleCPU::(read|write)_(byte|half|word|qword) to just read & write, overloaded on the type of the 'data' argument. Merged the full-system and non-full-system implementations of these eight original functions into two common template functions. To support this, also renamed (read|write)[1248] on memory_object and derivatives to just read & write, again overloaded on the type of the 'data' argument. Many of these functions could now be condensed into a few template functions (though with a level of indirection so that the interface can remain virtual). I did not do that though. sim/exec_context.hh: sim/pc_event.hh: - Eliminate static SLAT variables when building FULL_SYSTEM base/remote_gdb.cc: sim/simple_cpu.cc: sim/simple_cpu.hh: make it easier to drop into the remote debugger from within the local debugger dev/pcireg.h: Instead of having each pci device define its own sim object to represent the configuration space, just define one TlaserPciDev type and change the configuration regs as needed. base/range.hh: Fix bugs in range parsing code. sim/eventq.hh: Uncomment inlined event check (not sure why it was commented out to begin with). base/str.hh: - Add some missing #includes. - Remove some prefetching stats to shorten log lengths. - Fix perfect cache to work with new coherence mechanism (or at least not fail when there is no coherence protocol). base/range.hh: Consider whether a range object is valid or not when doing range tests. Reorganization & minor documentation of range comparison code. sim/exetrace.hh: Bug fix related to previous commit on range.hh. test/nmtest.cc: Add ability to do lookups by address dev/etherbus.cc: base/statistics.cc: fix sim/simple_cpu.cc: make it so we can change the boot flag sim/simple_cpu.cc: Bit more debugging info base/circlebuf.cc: Must initialize the size dev/console.cc: sim/simple_cpu.cc: better debugging base/remote_gdb.cc: Don't panic if the execution context isn't the same, just don't execute the breakpoint since it probably belongs to another instance sim/memtest.cc: Removed bcopy_in & bcopy_out (needless aliases for prot_write & prot_read, respectively). Made prot_read & prot_write public methods (not protected). Had to change some char arrays to byte_t to keep compiler happy. Renamed strcpy_in and strcpy_out to writeString and readString, respectively, to reduce confusion about the direction they operate. Also some reformatting for style. sim/main.cc: Move some more old simplescalar I/O from stdio to C++ streams. Some reformatting for style in main.cc as well. base/inifile.cc: base/inifile.hh: Pass -D, -U, and -I args to cpp for ini-file processing. Should make use of #defines in .ini files much handier, once we get our parser up to dealing with the resulting whitespace issues. Some reformatting for style as well. sim/main.cc: Pass -D, -U, and -I args to cpp for ini-file processing. Should make use of #defines in .ini files much handier, once we get our parser up to dealing with the resulting whitespace issues. sim/exetrace.cc: sim/exetrace.hh: sim/simple_cpu.cc: Changes to exetrace code to make it somewhat less schizophrenic so that it works under non-full-system SimpleCPU. (Previous code assumed either full-system+simple CPU or non-full-system+detailed CPU.) Also removed a lot of unused code in simple_cpu.cc. base/trace.hh: Added trace flags to display all syscalls or common syscall-related warnings (which are suppressed by default). arch/alpha/fake_syscall.cc: sim/exec_context.cc: sim/exec_context.hh: sim/prog.cc: sim/prog.hh: sim/simple_cpu.cc: Syscall emulation (non-full-system) support for multithreaded apps compiled using Tru64 5.1's pthreads library. More specifically, you can now associate multiple processors with a single LiveProcess object (via their workload parameters). Only one processor will be active initially. The additional processors will be assigned to handle new "virtual processor" threads as they are created by the pthreads user library. Functionality is limited, as we do *not* emulate any kernel scheduling: once a VP thread is created, it is permanently bound to a simulated CPU. However, most of the SPLASH-2 benchmarks seem to run on both uni- and dual-processor targets. Includes total rewrite of syscall emulation (fake_syscall.cc). Only syscalls that have been needed thus far have been re-implemented in the new framework. Others will be moved over on demand. base/trace.cc: Better dump function sim/simple_cpu.cc: The active field of exe_ctx is not used in FULL_SYSTEM sim/eventq.cc: dev/etherbus.cc: more debugging sim/memtest.cc: Added support for mem_cmd.cc Transitioned from enum mem_cmd to class MemCmd sim/eventq.hh: sim/param.hh: sim/serialize.hh: sim/sim_object.hh: test/sized_test.cc: - Fix PISA syscalls to use new memory interface. - Make prefetching a real SimObject and port existing prefetchers to the new framework. base/inet.cc: base/inet.hh: Move functions for networking into a separate file sim/exec_context.cc: sim/simple_cpu.cc: sim/simple_cpu.hh: Add basic support for a quiesce instruction. - Suspend the current thread on quiesce - Resume on interrupt Add an arm instruction that doesn't do anything yet sim/simple_cpu.cc: Added FULL_SYSTEM wrapper to use of "proc" in tick(). Nate, please check to make sure I didn't break it. base/inifile.hh: Added include of vector base/trace.hh: - Create a ScsiDevice base class that represents all of the functions that a SCSI device might want to implement - Clean up the ScsiDisk class: remove unneeded junk and give better names - Create a ScsiNone class that is used when a given target has no device sim/main.cc: Always use the same random seed to make the memory tester repeatable. As the comment says, someday we should make this a parameter. (Do we still need "mysrand()" and "myrand()"?) sim/memtest.cc: sim/memtest.hh: - Get rid of CoherenceTest... MemTest is just as capable. - Lots of new parameters for MemTest. sim/pc_event.cc: Don't execute a pc event twice dev/disk_image.cc: Add a config node of the copy on write disk image base/trace.hh: dev/disk_image.cc: More debugging base/trace.hh: Major update in dma code. - Separate the io callback into a read callback and a write callback - Fix the write callback so that the proper data is written back to the disk and data is copied to the proper place in the data buffer - Use sim_freq for the tick frequency. (There is still no delay) - Remove a bunch of unnecessary code - Make code more concise and remove old cruft - More Debugging (of course) - Formatting fixes - mprotect hack to make sure that dma buffer is not overwritten sim/exec_context.cc: sim/exec_context.hh: Fix broken assertion in main_memory::checkLockedAddrList(). Check for lots of failed store-conditionals and print deadlock warning message. arch/alpha/fake_syscall.cc: Use actual number of CPUs allocated to process (not const 2!). A few additional syscalls for pthreads support (not quite there yet though). sim/prog.cc: sim/prog.hh: Use actual number of CPUs allocated to process (not const 2!). arch/alpha/alpha_memory.cc: arch/alpha/alpha_memory.hh: arch/alpha/ev5.cc: arch/alpha/ev5.hh: arch/alpha/fake_syscall.cc: base/remote_gdb.cc: base/remote_gdb.hh: sim/exec_context.cc: sim/exec_context.hh: sim/exetrace.cc: sim/exetrace.hh: sim/pc_event.cc: sim/pc_event.hh: sim/prog.cc: sim/prog.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: exec_context_t -> ExecContext spec_exec_context_t -> SpecExecContext dev/disk_image.cc: quell warnings base/trace.hh: remove more warnings sim/exec_context.cc: sim/exec_context.hh: sim/prog.cc: sim/prog.hh: sim/simple_cpu.cc: remove the Process object from FULL_SYSTEM since it doesn't really make any sense sim/simple_cpu.cc: move SIM_OBJECT junk to the end like other files sim/simple_cpu.cc: sim/simple_cpu.hh: Make it so we can use a memory hierarchy in FULL_SYSTEM SimpleCPU arch/alpha/fake_syscall.cc: sim/base_cpu.cc: sim/base_cpu.hh: sim/exec_context.cc: sim/exec_context.hh: sim/prog.cc: sim/prog.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: - Add pointer from execution context to the CPU it's running on. - Just pass execution context pointer to the syscall emulation code, instead of a bunch of individual field arguments. - A few more exec_context_t -> ExecContext changes for non-full-system. - Rudimentary thread scheduling for non-full-system support of pthreads apps. Hopefully this won't go much farther. sim/exec_context.cc: Oops... fix minor bug from merge. arch/alpha/fake_syscall.cc: sim/base_cpu.cc: sim/base_cpu.hh: sim/exec_context.cc: sim/exec_context.hh: sim/prog.cc: sim/prog.hh: sim/simple_cpu.cc: - We really don't want to build a thread scheduler in the simulator... rip all that out, and replace with some basic synchronization primitives implemented as syscalls. Non-full-system MP apps thus need to be compiled specially to use these primitives, but it's plenty good enough to get SPLASH-2 up and running. These primitives block by suspending the execution context (for efficient simulation). Studies that care about synch operation costs should use user-level LL/SC-based primitives instead. - Implement more than two states (active vs. !active) for an ExecContext. arch/alpha/alpha_memory.cc: arch/alpha/alpha_memory.hh: arch/alpha/fake_syscall.cc: arch/alpha/vtophys.cc: base/circlebuf.cc: base/fast_alloc.cc: base/inifile.cc: base/inifile.hh: base/object_file.cc: base/object_file.hh: base/range.hh: base/remote_gdb.cc: base/res_list.hh: base/socket.cc: base/str.cc: base/str.hh: base/symtab.cc: base/symtab.hh: base/trace.cc: dev/alpha_console.cc: dev/alpha_console.hh: dev/console.cc: dev/console.hh: dev/disk_image.cc: dev/disk_image.hh: dev/etherbus.cc: dev/etherbus.hh: dev/simple_disk.hh: sim/base_cpu.cc: sim/base_cpu.hh: sim/eventq.cc: sim/exetrace.cc: sim/exetrace.hh: sim/hybrid_pred.hh: sim/intr_control.cc: sim/intr_control.hh: sim/main.cc: sim/memtest.cc: sim/memtest.hh: sim/param.cc: sim/param.hh: sim/pc_event.hh: sim/prog.cc: sim/prog.hh: sim/sat_counter.hh: sim/serialize.cc: sim/serialize.hh: sim/sim_object.cc: sim/simple_cpu.cc: sim/simple_cpu.hh: sim/universe.cc: First pass at compiling with gcc 3.x. Lots of "std::" in header files, "using namespace std" in source files. (Note policy of not putting "using" statements in headers or before includes in sources.) Still not able to compile with gcc 3.2. Errors: - Can't create an ifstream from a file descriptor anymore (breaks IniFile). - "`class MSHR::MSHRegister' is private" errors in mshr.cc and prefetch_cache.cc: not clear why since it's in the public part of the class declaration. - cpu.cc:879: can't match a reference and 0 (specifically "no match for `bool ? SimObjectParam<PipeTrace*>& : int' operator") - pipetrace.cc: "invalid conversion from `int' to `std::_Ios_Fmtflags'" Warnings: - strstream now deprecated... needs some rewriting in sat_counter.hh and hybrid_pred.hh (need to get all that code out of the headers anyway) - trace.hh macro problem: cpp now says 'pasting "::" and "Event" does not give a valid preprocessing token' - major "implicit typename" issues in base/sized.hh base/trace.hh: Token pasting not necessary. Quiets g++ 3.2 warning base/inifile.cc: base/inifile.hh: Make this compile in g++ 3.2 base/remote_gdb.hh: dev/etherbus.hh: dev/pcireg.h: dev/simple_disk.cc: Make this stuff g++ 3.2 happy base/inifile.cc: Make this still compile in g++ 2.95 arch/alpha/alpha_memory.cc: arch/alpha/alpha_memory.hh: dev/alpha_console.cc: dev/alpha_console.hh: sim/serialize.hh: sim/simple_cpu.cc: Added serialization for simple FULL_SYSTEM objects. Working on the hard ones sim/simple_cpu.cc: Make this code actually compile. Fix style while we're at it sim/base_cpu.cc: Fixes to recent updates to maintain gcc 3.2 compatibility (mostly more std:: in header files). test/Makefile: SS -> M5 base/cprintf.cc: base/cprintf.hh: test/Makefile: test/cprintftest.cc: printf replacement that uses C++ io streams and is typesafe Any type that overloads operator<< for use with streams will work with this structure. The format string is backwards compatible with printf style format strings, but the types are not checked, for example, %s doesn't verify that the type being printed is a string, %d doesn't verify that the type being printed is an integer. Instead, the various formats just set up the proper io stream manipulators for printing. So, %#s doesn't mean anything different from %s, but %#x does mean something different from %x. If the type you are printing does't care about the #, then nothing changes. base/cprintf.hh: test/cprintftest.cc: Fix case where there is only a format string, and no arguments base/cprintf.hh: base/cprintf_formats.hh: std:: base/trace.cc: base/trace.hh: Make the tracing stuff use cprintf base/cprintf.cc: Save and restore iostream state dev/etherbus.cc: Rewrite the dma engine support so that it can interact with the dma_interface to the timing memory model. This way, all of the timing of the dma transfers themselves can come from the memory system. Simos copyright removed since this code shares nothing with Simos sim/hybrid_pred.hh: sim/predictor.hh: sim/sat_counter.hh: Fixes to stat names in segmented IQ Changes from strstream to stringstream to remove warnings dev/etherbus.cc: dev/etherbus.hh: dev/etherint.hh: Separate the interface to the bus from the device sim/simple_cpu.cc: Move progress message from SimpleCPU::tick() to new ProgressEvent. (Much more efficient, and available independent of CPU model.) dev/console.cc: dev/console.hh: Added [DoEvents] default so command line --DoEvents:do_events=1 turns on events for all busses Added serlization function headers (not implemented yet). sim/eventq.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: Added [DoEvents] default so command line --DoEvents:do_events=1 turns on events for all busses Added serlization function headers (not implemented yet). Added EventQueue::nextEventTime(), returns time head is scheduled, or sim_cycle if empty. Added support for uniprocessor SimpleCPU with timing memory. arch/alpha/fake_syscall.cc: base/remote_gdb.cc: sim/exec_context.hh: sim/prog.cc: sim/simple_cpu.cc: Get rid of redundant ExecContext PC field. sim/main.cc: Add -n option to suppress loading default.ini. Added a little more help to the help message. sim/main.cc: Oops... make sure we still load it when we don't say '-n'. sim/main.cc: Minor formatting. sim/exetrace.cc: sim/exetrace.hh: Merge full-system & non-full-system exetrace code. base/cprintf.cc: base/cprintf.hh: Previous two commits were (somewhat) broken... this is the real one test/cprintftest.cc: more testing base/remote_gdb.cc: base/remote_gdb.hh: dev/alpha_console.cc: dev/alpha_console.hh: sim/base_cpu.cc: sim/base_cpu.hh: sim/exec_context.cc: sim/exec_context.hh: sim/pc_event.cc: sim/pc_event.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: sim/system.cc: sim/system.hh: Moved a lot of full-system variables out of SimpleCPU so that they can (eventually) be used with the detailed CPU model. Several fields moved into the ExecContext, while a few others moved into a new System object (which replaces the old Kernel object, for now at least). sim/exetrace.cc: sim/pc_event.cc: sim/pc_event.hh: sim/simple_cpu.cc: arch/alpha/alpha_memory.cc: arch/alpha/alpha_memory.hh: dev/alpha_console.cc: dev/alpha_console.hh: - Many g++ 3.2 fixes - Added Makefile magic to allow a comprehensive build of all simulator variants on all archtectures. 'make all' or 'make TARGET=<arch> all_flavors' - Added container adaptors and associative_table. Don't use these quite yet -- they are very expensive to compile. Am currently converting them over to boost::mpl. They are used by the new BHGP prefetcher. - Moved md_sysreg_t reg_t entries to isa_traits. PISA does not have these sorts of registers. - Moved ipr accesses to theISAEngineTraits because they are not generally applicable. These are #ifdef FULL_SYSTEM in the simulator code -- eventually this should get worked into the traits structure. base/fifo_buffer.cc: base/fifo_buffer.hh: Initial add of this incredibly usefull utility object arch/alpha/ev5.cc: arch/alpha/vtophys.cc: arch/alpha/vtophys.hh: base/remote_gdb.cc: sim/exec_context.cc: sim/exec_context.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: sim/system.cc: Implement some interval statistics for full system mode. Create a callpal function that is called when a callpal occurs so it's easier to manipulate the statics. Rework the vtophys stuff to make it a bit cleaner. arch/alpha/ev5.cc: arch/alpha/ev5.hh: Keep track of all callpals in the interval stats base/res_list.hh: base/sched_list.hh: sim/eventq.cc: sim/eventq.hh: sim/exetrace.cc: sim/exetrace.hh: sim/hybrid_pred.hh: sim/main.cc: sim/predictor.hh: sim/prog.cc: sim/sat_counter.hh: TA DA!!!! The giant, huge, amazing, i-hope-i-never-have-to-do-that-again, CLUSTERING MERGE!!!! \ base/fifo_buffer.hh: sim/exetrace.hh: Minor adjustments for GCC 3 compatibility Turn ptrace features back on arch/alpha/alpha_memory.cc: arch/alpha/alpha_memory.hh: arch/alpha/ev5.cc: arch/alpha/fake_syscall.cc: arch/alpha/vtophys.cc: arch/alpha/vtophys.hh: base/remote_gdb.hh: dev/alpha_console.cc: dev/simple_disk.cc: dev/simple_disk.hh: sim/exec_context.cc: sim/exec_context.hh: sim/exetrace.hh: sim/memtest.cc: sim/memtest.hh: sim/prog.cc: sim/prog.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: sim/system.cc: sim/system.hh: Get rid of almost all old-style object names. This commit is equivalent to running the following script on the current head: #! /bin/sh find \( -name '*.cc' -o -name '*.hh' \) -exec perl -pi -e '\ s/\bmemory_object\b(?!\.hh)/FunctionalMemory/g;\ s/\bvirtual_memory\b(?!\.hh)/VirtualMemory/g;\ s/\bmain_memory\b(?!\.hh)/MainMemory/g;\ s/\bphysical_memory\b(?!\.hh)/PhysicalMemory/g;\ s/\bspec_memory\b(?!\.hh)/SpeculativeMemory/g;\ s/\bMemObj\b(?!\.hh)/TimingMemObj/g;\ s/\bmemory_translation\b(?!\.hh)/AddressTranslator/g;\ s/\balpha_tlb\b(?!\.hh)/AlphaTlb/g;\ s/\balpha_itb\b(?!\.hh)/AlphaItb/g;\ s/\balpha_dtb\b(?!\.hh)/AlphaDtb/g;\ s/\bmemory_controller\b(?!\.hh)/MemoryController/g;\ s/\bstorebuffer_t\b(?!\.hh)/StoreBuffer/g;\ s/\bstorebuffer_entry_t\b(?!\.hh)/StoreBufferEntry/g;\ s/\bcreate_vector_t\b(?!\.hh)/CreateVector/g;\ s/\bcv_spec_state\b(?!\.hh)/CreateVecSpecState/g;\ s/\bspec_state_list\b(?!\.hh)/SpecStateList/g;\ s/\bdyn_inst_t\b(?!\.hh)/DynInst/g;' {} \; arch/alpha/fake_syscall.cc: sim/exec_context.hh: sim/memtest.hh: sim/simple_cpu.cc: Renamed files to better match new object names: base_memory.{cc,hh} --> functional_memory.{cc,hh} mem_obj.{cc,hh} --> timing_mem_obj.{cc,hh} sim/exec_context.cc: sim/exec_context.hh: sim/prog.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: Detailed CPU now compiles in full-system mode (but doesn't run, so I didn't add it to the makefile). SLAT code is now protected by '#ifdef USE_SLAT', since it's not currently compatible with full-system mode. Also, slat.cc is not compiled by default. We will need a makefile option to do '-DUSE_SLAT' and add slat.cc to the source list. CPU::Thread object is gone; these are now just bare SpecExecContexts. Changed all remaining {read,write}_{byte,half,word,qword} sets of methods to just read/write template methods, where possible. sim/system.cc: sim/system.hh: Make the system boot flag a paramter arch/alpha/ev5.hh: sim/intr_control.hh: The ethernet device was interrupting on the wrong interrupt line. Line 0x17 is too high (it's higher than the clock interrupt) and it doesn't correspond with the spl protection in the driver source. To solve this, we hack in support to support multiple interrupts at a single level and have scsi and ethernet share the same interrupt level. dev/etherbus.cc: dev/etherint.hh: Make the bus call back to the ethernet interface when the transfer is complete. This allows the interface to do the next request in the transmit buffer if there is one. dev/etherbus.cc: dev/etherbus.hh: dev/etherdump.cc: dev/etherdump.hh: Add etherdump object which accepts packets and spits them out in tcpdump format for analysis with tcpdump and ethereal. Make the etherbus support the dump object dev/etherint.cc: make the ethernet interface a SimObject that you can refer to dev/etherint.hh: dev/etherlink.cc: dev/etherlink.hh: Add a different connection type between ethernet interfaces. The ether link is a unidirectional fixed bandwidth link. To simulate a full duplex 100MB/s ethernet, you need two etherlinks. It's just much easier to simulate a full duplex link this way. Maybe encapsulate this into another bidirectional link sometime. sim/exec_context.hh: sim/main.cc: sim/simple_cpu.cc: sim/system.cc: Add a halted state to the simulator and only actually exit the simulator when all systems have halted. While we're at it, remove an if statement from the common code path in SimpleCPU::tick sim/exec_context.hh: sim/simple_cpu.cc: IntervalStatsObject -> IntervalStats test/Makefile: Make this work again base/cprintf.hh: #include guard arch/alpha/alpha_memory.cc: arch/alpha/vtophys.cc: base/remote_gdb.cc: dev/alpha_console.cc: dev/console.cc: dev/disk_image.cc: dev/etherbus.cc: dev/simple_disk.cc: sim/eventq.cc: sim/pc_event.cc: sim/simple_cpu.cc: since cprintf properly deals with 64-bit types, stop using FMT* as much as possible base/circlebuf.cc: base/inet.cc: base/inet.hh: base/object_file.cc: base/res_list.hh: convert some stdio stuff to use cprintf/c++ streams dev/console.cc: dev/console.hh: convert some stdio stuff to use cprintf/c++ streams better use of format strings sim/exec_context.hh: sim/exetrace.cc: sim/exetrace.hh: - Make SLAT work with new execution context - Temporarily fix include file problems (circular includes) arch/alpha/alpha_memory.cc: arch/alpha/ev5.cc: arch/alpha/fake_syscall.cc: sim/eventq.hh: sim/hybrid_pred.hh: sim/main.cc: True and false are keywords in C++, don't use TRUE and FALSE This can be done with the following script: #!/bin/sh for each in `find . \( -name '*.cc' -o -name '*.hh' \)`; do perl -pi -e '\ s/\bFALSE\b/false/g;\ s/\bTRUE\b/true/g;' $each done base/cprintf.cc: base/cprintf.hh: test/Makefile: test/cprintftest.cc: Add support for 'terminators' to cprintf. This is esentially a special manipulator that can cause some sort of event to occur when the stream is outputted. (Will be used for panic, fatal, etc.) base/cprintf.cc: base/cprintf.hh: Another cleanup fo the cprintf stuff. This should make it much easier to do panic, etc. sim/simple_cpu.cc: Rename sim_num_refs to SIM:num_refs to match Steve's new naming in the detailed CPU stats. base/cprintf.cc: base/cprintf.hh: Get rid of the reference counting and the pass by value, and come up with a way to remove all of the temporary variables that are created, and only create one. Should make the compiler's burden much less sim/pc_event.hh: quell warning arch/alpha/alpha_memory.cc: arch/alpha/alpha_memory.hh: arch/alpha/ev5.cc: arch/alpha/ev5.hh: arch/alpha/fake_syscall.cc: arch/alpha/vtophys.cc: arch/alpha/vtophys.hh: base/inet.cc: base/inet.hh: base/object_file.cc: base/object_file.hh: base/remote_gdb.cc: base/remote_gdb.hh: base/trace.cc: base/trace.hh: dev/alpha_access.h: dev/alpha_console.cc: dev/alpha_console.hh: dev/console.cc: dev/console.hh: dev/disk_image.cc: dev/disk_image.hh: dev/etherpkt.hh: dev/simple_disk.cc: dev/simple_disk.hh: sim/exetrace.hh: sim/memtest.cc: sim/memtest.hh: sim/pc_event.cc: sim/serialize.cc: sim/serialize.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: sim/system.cc: Change byte_t etc. to C99 standard int8_t etc. Other than old/host.h, all other changes were produced by this script: #! /bin/sh find \( -name '*.cc' -o -name '*.hh' -o -name '*.c' -o -name '*.h' -o -name 'machine.def' \) -exec perl -pi -e '\ s/\bbyte_t\b(?!\.hh)/uint8_t/g;\ s/\bsbyte_t\b(?!\.hh)/int8_t/g;\ s/\bhalf_t\b(?!\.hh)/uint16_t/g;\ s/\bshalf_t\b(?!\.hh)/int16_t/g;\ s/\bword_t\b(?!\.hh)/uint32_t/g;\ s/\bsword_t\b(?!\.hh)/int32_t/g;\ s/\bqword_t\b(?!\.hh)/uint64_t/g;\ s/\bsqword_t\b(?!\.hh)/int64_t/g;\ s/\bbool_t\b(?!\.hh)/bool/g;\ s/\bdfloat_t\b(?!\.hh)/double/g;\ s/\bsfloat_t\b(?!\.hh)/float/g;' {} \; sim/simple_cpu.cc: Assume preprocessor can do ANSI '##' token pasting. arch/alpha/fake_syscall.cc: base/misc.cc: base/misc.hh: base/pollevent.cc: base/sched_list.hh: base/socket.cc: base/symtab.cc: dev/console.cc: dev/disk_image.cc: dev/simple_disk.cc: sim/base_cpu.cc: sim/eventq.cc: sim/intr_control.hh: sim/main.cc: sim/memtest.cc: sim/param.cc: sim/serialize.cc: sim/sim_object.cc: sim/simple_cpu.cc: Get closer to removing all FMT64 junk and myfprintf stuff Make panic, flatal, warn use cprintf. Start moving away from the old/misc.(cc|h) files. dev/simple_disk.cc: Get rid of some FMT junk dev/etherdump.cc: dev/pcireg.h: u_int* -> uint* dev/etherdump.cc: sys/time.h instead of time.h arch/alpha/ev5.cc: sim/exec_context.cc: sim/exec_context.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: Do some clean up in the manner that the interval stats object is created Also, use the interval stats range when doing my full-system istats. Finally, don't make the interval stats part of the exec_context since it makes little sense to do so. We're only going to have one interval stats object (at least for now.) base/mod_num.hh: Initial addition of a "modulo-number" class sim/eventq.cc: sim/eventq.hh: convert some stdio to iostream sim/eventq.cc: sim/eventq.hh: sim/main.cc: sim/sim_events.cc: sim/sim_events.hh: sim/simple_cpu.cc: Move some common events into a new sim_events file. Rearrange some other things to move towards having only events in the main loop. sim/eventq.hh: Change protections base/pollevent.cc: base/pollevent.hh: proper destruction dev/console.cc: don't panic on connection error. detach. sim/eventq.cc: sim/eventq.hh: Clean up event queue and add support for priorities sim/eventq.cc: sim/main.cc: sim/memtest.cc: sim/serialize.cc: sim/sim_events.cc: sim/sim_events.hh: Get rid of sim_exit_now and make it an event. Get rid of sim_dump_stats and make it an event. Main loop is now reduced to servicing the event queue, ticking the CPUs, and incrementing sim_cycle sim/simple_cpu.hh: formatting nits base/cprintf.hh: dev/etherdump.cc: dev/etherdump.hh: sim/eventq.hh: sim/sim_events.cc: - ANSI/ISO C++ fixes - Improve SLAT efficiency - Add build_test rule to compile across all archs and options. This builds one simulator from each combination including the optimized Alpha simulator to run smt-test. Please run this before committing. base/misc.cc: make warnings less verbose sim/eventq.hh: Generic function that will delay the calling of a member function until a specified cycle. Has problems if you use it with gcc 2.95, but 3.2 compiles it ok. dev/etherbus.cc: Better debugging dev/etherbus.cc: dev/etherint.cc: dev/etherint.hh: dev/etherlink.cc: dev/etherlink.hh: Rework the EtherInt class to represent a generic Ethernet interface. Any object that wishes to connect to another device and pass ethernet packets must export an ethernet interface. This makes it possible to connect any two objects that have ethernet interfaces. For example, one EtherDev can connect directly to another etherdev, or the two EtherDevs can each attach to one of the interfaces on an EtherLink to get a fixed bandwidth. dev/ethertap.cc: dev/ethertap.hh: util/tap/Makefile: util/tap/tap.cc: The ethertap device and ethertap utility allow a simulator to connect to a real physical ethernet. Currently, the tap utility only works on OpenBSD, but that should be easily fixed. dev/ethertap.cc: dev/ethertap.hh: better bounds checking base/cprintf.hh: change function names in cprintf base/trace.cc: base/trace.hh: Make DPRINTF work more like panic, fatal, warn, etc. Also make it possible to redirect trace output to a file instead of stdout. dev/etherlink.cc: dev/etherlink.hh: Make EtherLink::Link Serializeable arch/alpha/alpha_memory.cc: base/remote_gdb.cc: base/res_list.hh: base/trace.cc: base/trace.hh: dev/console.cc: dev/disk_image.cc: dev/etherbus.cc: dev/etherlink.cc: dev/ethertap.cc: dev/simple_disk.cc: sim/eventq.cc: sim/eventq.hh: sim/pc_event.cc: sim/serialize.cc: sim/simple_cpu.cc: rework DPRINTF to automatically print the cycle and get the name of the object from which it was called. Additionally, while we're at it change 0x%x -> %#x dev/disk_image.cc: sim/pc_event.cc: sim/serialize.cc: dont use c_str() if we don't have to base/trace.cc: Only delete the stream if we created it base/trace.cc: base/trace.hh: Expose ostream to which tracing statements are sent via DebugOut() dev/console.cc: carriage return not necessary arch/alpha/arguments.cc: arch/alpha/arguments.hh: Add support for accessing function arguments from a kernel function. The class behaves somewhat like a random access iterator so that the user can access any argument desired, but to get at the data, the user uses the casting operators to get at the data pointed to by the arguments sim/pc_event.cc: sim/pc_event.hh: inline sim/pc_event.cc: sim/pc_event.hh: sim/system.cc: sim/system.hh: create a pc based event that traps kernel printfs for debugging statements arch/alpha/arguments.hh: rename to CopyData and use void * to avoid compiler problems sim/pc_event.cc: Make Kernel::Printf take AlphaArguments as a parameter so that a user may add initial arguments to another version of the kernel function and then pass an offset arguments class to the function for printing the data. Also, while we're at it, remove the printing of the cycle. That can be done by the caller. base/trace.hh: sim/pc_event.cc: sim/pc_event.hh: sim/system.cc: sim/system.hh: Separate the printf event from the debugging printf event. The kernel will call the debugging printf event m5printf. There is also a raw version m5printfr that indicates to the simulator that it shouldn't print any extra information in the context of this debuggin printf because it would screw up fromatting. sim/pc_event.cc: symmetry arch/alpha/arguments.cc: arch/alpha/arguments.hh: plug huge leak arch/alpha/arguments.hh: Add std:: to list arch/alpha/arguments.hh: make the execution context available dev/etherlink.cc: formatting, typeo, paranoia sim/system.cc: sim/system.hh: enable the mbuf dump code sim/pc_event.cc: sim/pc_event.hh: Add a pc event for the kernel mbuf dump function arch/alpha/fake_syscall.cc: sim/main.cc: I can see no good reason at all for doing setjmp/longjmp arch/alpha/arguments.cc: arch/alpha/arguments.hh: reference count the argument data so that the data doesn't disappear before we're done using it. sim/main.cc: move all signal stuff into main.cc sim/sim_events.cc: Move termination and progress event initialization to sim_events sim/debug.cc: sim/debug.hh: sim/main.cc: sim/pc_event.cc: sim/simple_cpu.cc: Move some of the debug break stuff to its own file Use SIGTRAP to initiate a break and set up the simulator to ignore the signal. This will make gdb automatically stop in these functions, but won't interfere with normal simulator workings. sim/sim_events.cc: Id string sim/sim_events.cc: make g++ 3 happy base/cprintf.cc: base/cprintf.hh: base/misc.cc: base/misc.hh: base/trace.cc: base/trace.hh: - Rename debug rule to dbg so it doesn't interfere with debug.cc. - Reorganize build_test so it generates dependencies correctly. - Remove HashTable from spec_memory and replace with SGI's hash_map extension. - Put cprintf/ArgList in namespace cp so it doesn't interfere with g++ 2.95 std::deque (comma operator gives problems -- this is a g++ 2.95 bug). - Fix FP register decode in dispatch. PISA registers > 31 were being counted as FP registers and using up all of the FP hpysical registers. The code in commit correctly identified FP registers so the bogus FP physical register usage was never cleared, locking up the machine. This is why the SLAT didn't work correctly. Added isa_traits::isFloatingPointRegister and ::isIntegerRegister to do this tracking in a machine-independent way. sim/sim_events.cc: simple way to dump stats on specified cycles sim/eventq.hh: Re-insert assignment of description string into event sim/eventq.cc: If event is the head in remove() return arch/alpha/fake_syscall.cc: Clustering changes.... - clusters can share data using the ClusterSharedInfo structure - Pulled the register info file from the segmented IQ --> dispatch stage (this info can be used by the dispatch stage and any IQ model) - Segmented IQ's share the chain-info-table now base/misc.hh: - Add m5_assert() macro to print the sim_cycle if the assert fails. - Add simple_trace, simple_trace_data and simple_trace_start parameters to generate a sim-safe-like trace for easy comparison with simplescalar results. Needed for PISA debugging. sim/sim_events.hh: remove extra space sim/main.cc: Fix dump() for floss-reasons Segfault can now dump core sim/simple_cpu.cc: sim/simple_cpu.hh: Get rid of obsolete call from misguided thread scheduling experiment. arch/alpha/ev5.cc: arch/alpha/ev5.hh: add new alpha instructions for starting and ending intervals dev/disk_image.cc: dev/disk_image.hh: Make the copy-on-write disk image use hash_map base/callback.hh: Generic callback class and callback queue for random use sim/main.cc: sim/sim_events.cc: sim/sim_exit.hh: Move exit stuff into it's own file. Make an exit callback queue so that generic callbacks can be invoked upon simulator exit dev/disk_image.cc: give a mode that makes sense dev/disk_image.cc: dev/disk_image.hh: Rework the object implementation of the copy-on-write disk image. - Allow a child name and an initial table size to both be specified - Add a read only flag that determines if changes to the image are written back to disk. - If the flag is not read only, and there is no initial image to open, that's ok, just create an initial empty table. - If the table is to be written back to disk, schedule an ExitCallback to write the image back when the simulator exits. base/callback.hh: make this work in g++ 3 base/misc.cc: base/pollevent.cc: base/pollevent.hh: base/trace.hh: sim/pc_event.cc: sim/universe.cc: declare sim_cycle in one place arch/alpha/alpha_memory.cc: dev/alpha_console.cc: more sim_cycle cleanup sim/eventq.hh: fix priority handling in the event queue: if an event is scheduled with a priority once, then don't overwrite the priority if it is subsequently scheduled without a priority dev/console.cc: send a carriage return/newline pair to the output manually since cprintf and friends would interpret this and send out endl dev/console.cc: dev/console.hh: add option to save console output to a file sim/simple_cpu.cc: sim/simple_cpu.hh: Rework cache interface to avoid trying to loop inside of tick(). Should work much more cleanly with timing memory now (even for multiprocessor systems). sim/simple_cpu.cc: a whole bunch of cleanup foo sim/eventq.cc: events can't be scheduled in the past anymore sim/eventq.cc: sim/eventq.hh: create doEventLoop(), this continually cycles through the event queue consuming events until there are none left dev/console.hh: Make this work in g++ 3 sim/sim_events.cc: sim/sim_events.hh: Make the act of ticking all cpus an event. Automatically schedule it every cycle sim/debug.cc: sim/main.cc: sim/sim_events.cc: rearrange code to get rid of sim_smt.cc sim/main.cc: oops. bring back the SIM:cycle stat arch/alpha/ev5.cc: sim/simple_cpu.cc: move the break_ipl check to the point where the IPL is actually set sim/debug.cc: Make the debug break event first in any given cycle sim/simple_cpu.cc: sim/simple_cpu.hh: Split I-cache and D-cache stall cycles out from idle cycles in statistics. sim/prog.hh: - Replace SLAT maps with hash_maps - Add hash<> specializations for md_addr_t, counter_t, etc. - Increase max file descriptors from 15 to 100 (parser00 was running out) sim/simple_cpu.cc: A few baby steps toward full-system detailed CPU. ev5_trap() now sets both PC & NPC (not just NPC). base/misc.cc: base/trace.cc: New memory model Doxyfile: Configuration file for doxygen. Generates documentation in /n/zizzer/z/m5docs. To generate docs, run "doxygen Doxyfile" in the root directory of your copy of the head. To comment your code you use a javadoc like syntax, a cstyle comment with 2 stars at the front (/**). For example /** Everything before the first period is a brief description. This is a detailed description. @param <name> description of parameter to function @retval <name/type> description of function return value. @sa (for see also) generate links to other class/enum/member/etc. */ You should start your files out with a comment like: /** @file Brief description of the file. Detailed description if needed. */ See TimingMemobj.hh for more examples. dev/ethertap.cc: Make this work on OpenBSD sim/main.cc: sim/sim_events.cc: sim/sim_events.hh: sim/sim_exit.hh: Make it possible to set an exit code for the exit event. Also, make exit_now not visible to the rest of the simulator so that people will know to create an exit event. Finally, don't include callback.hh since we don't have to. sim/sim_events.cc: use the SimExitEvent to make sure that we exit at the end of the cycle arch/alpha/fake_syscall.cc: don't use exit_now() create a SimExitEvent() arch/alpha/ev5.cc: arch/alpha/ev5.hh: Add an instruction that causes M5 to exit, allowing processes running under simulation to cause the simulation to terminate sim/simple_cpu.cc: in full system mode, don't panic on an unknown opcode dev/disk_image.cc: dev/disk_image.hh: convert stdio to streams sim/system.cc: remove uneeded include base/cprintf.cc: %p is an integer (more or less) sim/system.cc: sim/serialize.cc: missing include dev/disk_image.cc: cast to correct types for proper interface usage base/circlebuf.cc: base/intmath.h: base/remote_gdb.cc: base/res_list.hh: In c++, we use std::min, std::max, true, and false, not ano of the other junk sim/sim_events.cc: make a local copy of the data since the object can get deleted dev/alpha_console.cc: dev/alpha_console.hh: Added parameter for number of CPUs to console, defualt=1 sim/sim_events.cc: sim/simple_cpu.cc: sim/system.cc: sim/system.hh: use cprintf. general cleanup remove unneeded c_str() calls. base/cprintf.cc: make %% work base/cprintf.cc: handle %% better test/cprintftest.cc: better testing arch/alpha/alpha_memory.cc: convert to use iostream and cprintf instead of stdio and fprintf base/cprintf.cc: more accurately implement formatting for floating point numbers test/cprintftest.cc: more tests base/inifile.cc: base/inifile.hh: base/symtab.cc: base/symtab.hh: dev/disk_image.hh: sim/base_cpu.cc: test/Makefile: convert everything to use hash_map instead of my old hash table junk base/hashmap.hh: base/inifile.hh: dev/disk_image.hh: since people don't agree on where hash_map belongs, pull it into the m5 namespace and include hashmap.hh whenever a hashtable is needed sim/memtest.cc: Move Cache only calls (block_size, hit_latency, etc.) out of TimingMemObject and into CPUMemInterface. Changes to everywhere they were called on a TimingMemObj. sim/param.hh: Fix handling of operator[] for EnumVectorParam classes. Also fix some line wrapping problems caused by adding 'std::'. base/trace.cc: base/trace.hh: Extend trace facility to either print immediately to an ostream or maintain a circular buffer of trace entries (dumpable from debugger by calling dumpTrace()). Also change flags to use SimpleEnumVectorParam so we can just give a list of names instead of a big hex value. sim/exetrace.cc: sim/exetrace.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: Integrate execution trace code into new trace facility. Eliminates the need for a separate execution trace log. Enable instruction tracing using --trace:flags=InstExec. base/misc.cc: Dump trace buffer in panic(). arch/alpha/ev5.cc: arch/alpha/ev5.hh: sim/simple_cpu.cc: set up an annotations.hh file where inline annotation functions that do nothing exist. This allows people to hack in annotations all in one file arch/alpha/ev5.cc: arch/alpha/ev5.hh: intervals are really annotations arch/alpha/ev5.cc: Factor out more annotations arch/alpha/ev5.cc: sim/simple_cpu.cc: Make an Annotate namespace, and add a DumpStats method to it dev/disk_image.cc: sim/main.cc: sim/sim_events.cc: sim/sim_exit.hh: Normalize exit-related function names. Move exitNow() prototype to simexit.hh. base/misc.cc: base/trace.cc: base/trace.hh: sim/eventq.cc: sim/eventq.hh: sim/exetrace.cc: sim/exetrace.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: Minor cleanup on new tracing code: - namespace cleanup - fix bug in Trace::Log::dump - added new RawDumpRecord to put raw data in trace buffer (call Trace::rawDump, was Trace::dump) - added --trace:flags=All to set all trace flag bits - added --trace:dump_on_exit option to dump trace buffer on normal exit - DPRINTF now requires 'const char *' for format (not string) so it doesn't go away by the time buffer is dumped sim/sat_counter.hh: sim/serialize.hh: foo(void) --> foo() This commit is equivalent to doing the following in the sim directory: perl -pi -e 's/\(void\)/()/' *.cc *.hh sim/base_cpu.hh: sim/eventq.cc: sim/hybrid_pred.cc: sim/hybrid_pred.hh: sim/memtest.cc: sim/predictor.hh: sim/sat_counter.cc: sim/sat_counter.hh: Move dump() and reg_stats() implementations out of header files. Clean up #includes. sim/exec_context.hh: sim/exetrace.cc: sim/exetrace.hh: sim/main.cc: Clean up identification and handling of prefetches and no-ops. Added is_data_prefettch() method to DynInst. (One of these days we'll have to change all those functions to isFoo() style.) Changes nop count statistic... we were only counting Alpha UNOPs before, not all Alpha NOP forms. sim/pc_event.cc: sim/simple_cpu.cc: - Strip opt binaries after build - Update Makefile for new source files - Fix BHGP prefetcher to use compressed addresses - Fix FULL_SYSTEM compile problems (missing header includes) base/inifile.cc: Make it possible to override variables in the inifile and on the command line sim/simple_cpu.cc: sim/simple_cpu.hh: - Make the SLAT useable with SimpleCPU for quick and easy debugging. This required refactoring some of the traits classes which should make them marginally more independent. - Fix bogus assert in the SLAT code. Alias load/store values should only be assumed equivalent in non-spec mode. sim/simple_cpu.cc: - Must send the saved address to the SLAT for all memory operations because execution could have overwritten the base register. sim/simple_cpu.cc: sim/simple_cpu.hh: Added Parameter for CPU identification number in Full System Primary CPU ID is 0, which is the default value Modified to start all CPU's in Halted status except the primary CPU dev/alpha_console.cc: Added comments to code for needed implementation in order to boot second CPU dev/alpha_console.cc: sim/exec_context.cc: sim/exec_context.hh: sim/simple_cpu.cc: sim/system.cc: sim/system.hh: Added array of Execution Contexts to system.hh Used when trying to launch another CPU Added cpu_id to Full System ExecContext Fixed the launch in alpha_console.cc to access the correct exe_ctx dev/alpha_console.cc: sim/simple_cpu.cc: Fixed initializtion and launch of the second processor Added a gdb-alpha debug port for non-primary processor Cleaned up the .ini file of unneeded disk images sim/simple_cpu.cc: Add cpu_id (see Ron's recent commit) to full-system detailed CPU. base/trace.cc: Fix bug in calling dumpTrace() on partially filled trace buffer. test/Makefile: test/lru_test.cc: - Replace BHGP associative table with something simpler. - Add lru_test to test out new AssociativeTable class. Doxyfile: Only create documentation for documnented classes dev/alpha_access.h: dev/alpha_console.cc: dev/alpha_console.hh: cleanup and formatting sim/simple_cpu.cc: Fix bus queueing delay and idle stats. Slight change to one scheduling case. Set req->time in SimpleCPU so delays are correctly computed. sim/simple_cpu.cc: Don't do an icache fetch if we had an ITLB miss. arch/alpha/alpha_memory.cc: dev/alpha_console.cc: sim/serialize.cc: sim/serialize.hh: Replace include of inifile.hh in serialize.hh with forward decl of class IniFile. Requires adding explicit include of inifile.hh in several .cc files. sim/eventq.hh: Get rid of needless include of inifile.hh. sim/main.cc: base/inifile.cc: base/inifile.hh: Check for unreferenced parameters to detect obsolete settings and typos. A warning for an unreferenced parameter section can be suppressed by adding a 'unref_section_ok=y' parameter to the section. Warnings for any unreferenced parameters within a section can be suppressed by adding a 'unref_entries_ok=y' parameter to the section. (The value doesn't matter; the presence of the parameter is all that is tested.) By default any unreferenced parameter or parameter section warnings will cause the simulator to terminate. Use the '-u' command-line option to suppress this behavior (at your own risk!). dev/alpha_access.h: dev/alpha_console.cc: dev/alpha_console.hh: dev/console.cc: dev/console.hh: dev/disk_image.cc: dev/disk_image.hh: dev/etherbus.cc: dev/etherbus.hh: dev/etherdump.cc: dev/etherdump.hh: dev/etherint.hh: dev/etherlink.cc: dev/etherlink.hh: dev/etherpkt.hh: dev/ethertap.cc: dev/ethertap.hh: dev/pcireg.h: dev/simple_disk.cc: dev/simple_disk.hh: sim/eventq.hh: sim/serialize.hh: sim/sim_object.hh: Add some Doxygen comments. Mostly putting in markers for the file and classes Also some minor formatting fixes here and there arch/alpha/ev5.cc: Reindent to 4 spaces (plus a few other very minor formatting changes). arch/alpha/alpha_memory.cc: arch/alpha/alpha_memory.hh: Reindent. sim/eventq.hh: Don't even bother with the description unless TRACING_ON is defined. Not a big deal at this point, since TRACING_ON is currently hardcoded to 1 in base/trace.hh. base/remote_gdb.cc: base/trace.hh: sim/eventq.cc: sim/eventq.hh: sim/system.cc: Clarify debugging defines: - DEBUG is either defined or not, but is not given a value. It should be tested with #ifdef. - TRACING_ON is always defined, either with a 0 or 1 value. It should always be tested with #if. Automatically set TRACING_ON value according to whether DEBUG is defined. Added -Wundef to warnings to catch '#if DEBUG' cases. (Yes, '#if DEBUG' does the right thing if DEBUG is not defined, but the same is not true for '#ifdef TRACING_ON' if TRACING_ON is defined to 0.) In the long run, perhaps the uses of TRACING_ON outside of the trace package itself should be converted to use DEBUG. sim/pc_event.cc: Looks like a lot of device code has never been compiled w/o TRACING_ON set; fix up several warnings (mostly unused variables). sim/pc_event.cc: Oops... needs to compile w/o FULL_SYSTEM too. base/trace.hh: sim/main.cc: sim/param.cc: sim/param.hh: sim/sim_object.cc: Fix up parameter printing controls. Parameters are always printed by default; new command-line parameter '-q' turns this off. Old system was broken in two ways: there was no way to turn off printing in the optimized binary, and controlling printing with a trace flag bit (specified as an .ini parameter) meant that parameters parsed *before* trace:flags never got printed. Also added code to print the names of unspecified parameters as comments in the output. base/remote_gdb.cc: base/trace.hh: A couple more changes to get full-system to compile w/o tracing. sim/simple_cpu.hh: sim/simple_cpu.cc: - Add stats for simple SLAT profiling sim/simple_cpu.cc: Extend HAVE_TSL protection so it can compile without TSL base/trace.cc: Need to update flag strings to match enum... yuck. sim/system.cc: sim/system.hh: Build global list of system objects. Add gdb-callable printSystems() function so we can find system object pointers from inside debugger. sim/eventq.cc: sim/simple_cpu.cc: base/pollevent.cc: base/pollevent.hh: Move pollQueue handling into main event loop so it works regardless of the CPU model. arch/alpha/ev5.cc: Protect IPRs etc. from being modified on misspeculated paths. arch/alpha/ev5.hh: Eliminate some unused macros. arch/alpha/alpha_memory.cc: Don't update IPRs for TLB misses on misspeculated instructions. Set req.flags PHYSICAL and UNCACHEABLE bits as appropriate based on results of translation. sim/param.cc: Move ConfigHierarchy::Node definition into separate file so it can be included only where necessary. arch/alpha/fake_syscall.cc: arch/alpha/vtophys.cc: arch/alpha/vtophys.hh: base/circlebuf.cc: base/circlebuf.hh: base/cprintf.hh: base/fifo_buffer.cc: base/fifo_buffer.hh: base/inifile.cc: base/inifile.hh: base/misc.hh: base/mod_num.hh: base/pollevent.cc: base/remote_gdb.cc: base/sched_list.hh: base/socket.cc: base/socket.hh: base/str.cc: base/str.hh: base/symtab.cc: dev/alpha_access.h: dev/etherint.cc: sim/base_cpu.cc: sim/base_cpu.hh: sim/debug.cc: sim/hybrid_pred.cc: sim/hybrid_pred.hh: sim/param.cc: sim/param.hh: sim/pc_event.cc: sim/predictor.hh: sim/sat_counter.cc: sim/sim_object.cc: sim/simple_cpu.hh: test/cprintftest.cc: test/lru_test.cc: test/nmtest.cc: test/offtest.cc: test/sized_test.cc: test/symtest.cc: util/tap/tap.cc: Add CVS Id tags dev/alpha_console.cc: dev/alpha_console.hh: Get rid of pmask field in MemReq; move address mask into devices by adding to common base class FunctionalMemory. base/inifile.cc: Don't complain if "unref_section_ok" or "unref_entries_ok" are not referenced. base/inifile.cc: Add functionality to "unref_entries_ok": Now, the RHS is parsed for a list of unreferenced entries, only these will be "OK" Note that this will not be needed very often... base/trace.cc: sim/exetrace.cc: Make trace cycle number position and format consistent between DPRINTF trace records and exetrace records. sim/debug.cc: Add "debug" parameter context for global debug options. Add parameter "debug:break_cycles" to set DebugBreakEvent(s) from ini file/command line. sim/pc_event.cc: sim/system.hh: sched_break_pc() now sets a breakpoint on *all* systems. Use sched_break_pc_sys() to set a breakpoint on just one system. sim/debug.cc: sim/pc_event.cc: base/cprintf_formats.hh: using namespace std dev/alpha_console.cc: sim/exec_context.cc: sim/exec_context.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: arch/alpha/fake_syscall.cc: sim/prog.cc: use accessor functions to set/get status to prepare to not call SimpleCPU::tick if there is nothing to do sim/simple_cpu.cc: no more simplescalar here base/trace.hh: Only set TRACING_ON according to DEBUG if it hasn't already been set on the command line. base/trace.cc: If compiled with TRACING_ON=0, give an error if the user tries to turn on tracing. sim/main.cc: Get rid of do-nothing segfault handler... if you get a segfault in an exit handler, you end up with an infinite recursion. arch/alpha/alpha_memory.cc: arch/alpha/alpha_memory.hh: arch/alpha/ev5.cc: arch/alpha/ev5.hh: sim/exec_context.cc: sim/exec_context.hh: sim/pc_event.cc: sim/simple_cpu.cc: sim/simple_cpu.hh: Full-system detailed CPU almost almost there. Big reorganization of virtual address translation code, so we can tell an access is uncached soon enough to suppress it if it's on the wrong path: translation is its own step now, not hidden inside the (former) VirtualMemory object. Also a few other changes to avoid bad things on misspeculated paths. This commit results in *very* small changes in IPCs and MSIPCs (a few tenths of a percent max on the tests) because some wrong-path instructions get handled a little differently. sim/main.cc: Put quotes around args with spaces when echoing command line. sim/pc_event.cc: Process PC Events just before fetching the relevant instruction instead of just after the previous instruction. Keeps us from missing events when we take off on misspeculated paths. ** Detailed CPU now gets to single-user prompt!! ** sim/base_cpu.hh: sim/eventq.hh: sim/main.cc: sim/sim_events.cc: sim/sim_events.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: get rid of the TickAllEvent and make it so each cpu has its own tick event. In the process, the implementation of the virtual functin tick() got moved into a non virtual function _tick() so that the tick event could be CPU specific and you wouldn't pay the virtual function call overhead. This is another step towards being able to not tick a cpu if it has nothing to do sim/base_cpu.hh: sim/simple_cpu.hh: Now that tick is called via an event, we no longer need a virtual function sim/base_cpu.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: clean up the tick event stuff and get rid of the TickEvent template class and just make one for each class since you may want a different process() function anyway base/trace.cc: base/trace.hh: sim/base_cpu.hh: sim/pc_event.cc: sim/pc_event.hh: Fix up branch predictor's return address stack when we do a SkipFuncEvent. Since there's no easy way to figure out what thread ID we're on from the SkipFuncEvent, we just fix thread 0's RAS... will need to fix this when we get SMT full-system up. Also: - Moved RAS tracing stuff to DPRINTFs; added BranchPredRAS trace flag. - Made BadAddrEvent derive from SkipFuncEvent to eliminate code duplication. base/trace.cc: sim/eventq.cc: sim/eventq.hh: sim/serialize.cc: Create a flags bitvector in the event to store flags. Holds what used to be squashed and scheduled, and also contains a new flag for auto delete. The auto delete flag will make the eventq responsible for calling delete on an event. This makes 'delete this' unnecessary in the process() function. This is most beneficial for events that get squashed since process() never gets called, and one might want to have the data reclaimed. To use the autodelete functionality with squash, a few events were cleaned up and reorganized sim/exec_context.cc: sim/exec_context.hh: sim/pc_event.cc: sim/simple_cpu.cc: Add thread_num field to ExecContext so it knows which CPU thread context it represents. Need this for the SkipFuncEvent RAS fixup, but seems generally useful. dev/etherdump.cc: use time.h instead of sys/time.h sim/simple_cpu.cc: sim/simple_cpu.hh: move the tick schedule() to where it's needed dev/alpha_console.cc: dev/alpha_console.hh: sim/base_cpu.cc: sim/base_cpu.hh: sim/exec_context.cc: sim/exec_context.hh: sim/intr_control.cc: sim/intr_control.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: get rid of the processor SimObject and move all of the interrupt stuff into BaseCPU since it really is part of the CPU anyway sim/exec_context.hh: fix store conditional sim/exec_context.hh: clean up conditional store so that it's more understandable sim/base_cpu.cc: sim/base_cpu.hh: move interrupt set/clear routines into the .cc file and make them virtual so that CPUs derived from BaseCPU can modify the behaviour of the interrupt routine. base/trace.cc: base/trace.hh: New trace flags generation via perl script. Now if you want to add a flag you just type it once (in the script) and all the C++ is generated automagically. Also supports "compound" flags that can be specified on the command line and map to multiple regular flags. Switched trace flags from 64-bit bitmap to vector<bool> for scalability. base/trace.cc: comment out the offending assign since it is commented as not needed base/trace.cc: Get rid of useless code. sim/base_cpu.cc: sim/base_cpu.hh: change variable name to avoid confusion arch/alpha/ev5.cc: sim/simple_cpu.cc: Remove a bunch of istats stuff and insert some annotations for where they were. sim/debug.cc: add a function to force stats to be dumped from the debugger sim/base_cpu.hh: sim/exec_context.cc: sim/exec_context.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: Don't schedule tickEvent until it is known that there will be something to do test/Makefile: Make tests compile again test/Makefile: Make the whole build process for tests a bit simpler util/tap/Makefile: make this build again, clean stuff up sim/exec_context.cc: sim/simple_cpu.cc: make stuff compile when not FULL_SYSTEM sim/main.cc: Add the name of the execution host to the output sim/main.cc: Don't free() data returned by getenv. besides, free() is a function, not an operator like sizeof sim/eventq.cc: That assertion should have never been committed sim/simple_cpu.cc: don't tick here sim/eventq.cc: the squashed flag should be cleared once the event has actually been processed sim/simple_cpu.cc: we can get here with a dcache miss as well. sim/simple_cpu.cc: only schedule the event if it is not already scheduled. arch/alpha/fake_syscall.cc: Zero out syscall arg buffer to avoid copying garbage into simulator space. sim/exec_context.hh: Translation in non fullsystem mode. And use the FALRU class to implement FA LRU caches. sim/base_cpu.hh: sim/exec_context.cc: sim/simple_cpu.cc: sim/simple_cpu.hh: Reorganize code a bit so that multiple CPUs can properly work with the new tick as event stuff. arch/alpha/arguments.hh: base/cprintf.hh: base/refcnt.hh: dev/etherpkt.hh: Make a refcounted base class that contains the refcounting stuff and make everything use it sim/main.cc: don't print out the host if we didn't find one dev/alpha_console.cc: dev/alpha_console.hh: s/memreq/MemReq/ base/trace.cc: Add support to echo trace output (DPRINTF etc.) to cerr as well as the trace buffer. From gdb, call "echoTrace(1)" to enable, or "echoTrace(0)" to disable. As a side effect, semantics of setting both trace:bufsize and trace:file are different now (will buffer and send to file, where old version would just buffer), but I doubt anyone ever did that anyway. See comments in file for more details. sim/base_cpu.cc: sim/base_cpu.hh: sim/debug.cc: sim/eventq.cc: sim/eventq.hh: sim/memtest.cc: sim/memtest.hh: sim/sim_events.cc: sim/sim_events.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: Revamp event debug/tracing structure. - virtual const char *description() method replaces description string constructor argument. Lets us associate a fixed description string with each class of events with basically no overhead. - virtual void trace(char *action) method lets event subclasses customize tracing DPRINTF call to put in additional information. Currently only used by WritebackEvent (to print sequence number of associated instruction). dev/etherbus.cc: dev/etherbus.hh: dev/etherlink.cc: dev/etherlink.hh: dev/ethertap.hh: Fix up full-system events for new debug structure. base/trace.cc: Looks like g++ 3 doesn't like "string = bool ? string : char*". sim/simple_cpu.cc: the caches currently won't completion events for UNCACHEABLE accesses, so don't send any. Warning, this is a HACK! dev/etherdump.cc: sim/main.cc: cleanup includes, and remove some #ifdef cruft for BFD sim/sim_exit.hh: Added GDB-callable exitNow() using char * sim/sim_events.hh: Need to include eventq.hh here. test/Makefile: There are no OPT_FLAGS arch/alpha/fake_syscall.cc: dev/etherdump.cc: sim/eventq.cc: sim/main.cc: sim/memtest.cc: sim/serialize.cc: sim/sim_events.cc: sim/sim_time.hh: sim/simple_cpu.cc: sim/system.cc: Get rid of sim.h & sim_smt.hh. Most of what was in those was obsolete anyway. Move needed externs into universe.hh & stats.hh, plus new header file sim_time.hh. sim/memtest.cc: sim/memtest.hh: Update memtest cpu to new tickEvent stuff base/remote_gdb.cc: Adding returns to make insure happy. sim/simple_cpu.cc: Rework Interporcessor Interrupts to properly signal second CPU, and unsuspend it sim/intr_control.hh: Fix clock interrupt to signal both proccesors correctly in MP system sim/system.cc: Fix seg fault in single proccesor mode from last commit, MP now boots with 2 CPUs sim/simple_cpu.cc: sim/system.cc: sim/system.hh: Changes to genaralize the interupt scheme to variable number of proccessors base/misc.cc: only dump the trace buffer if tracing is turned on base/str.cc: properly deal with the case where there is only one string in the list base/cprintf.cc: base/cprintf.hh: Add csprintf() to print to a string (sort of like sprintf()) base/cprintf.cc: be consistent about resetting parameters to original values base/cprintf.cc: cleanup base/statistics.cc: base/statistics.hh: Finally commit my new stats package and stop tinkering with it. This new stats package has support for all sorts of stuff. Documentation will appear in the code in a future commit. test/Makefile: test/stattest.cc: add tests for the statistics package. This exercises all sorts of different capabilities of the stats package and can be used for examples. util/rundiff: rundiff utility Normal diff reads in all of both input files and tries to generate a minimal diff, for super long trace files, this is bad because it takes forever and you run out of memory. rundiff is designed to scan the input files and compare only 2000 lines at a time. This way memory won't run out and a user can use fifos for input files. sim/exetrace.cc: Print all reg results as 0x%016x. arch/alpha/fake_syscall.cc: base/misc.cc: base/misc.hh: base/pollevent.cc: base/pollevent.hh: base/statistics.hh: base/trace.cc: base/trace.hh: dev/alpha_console.cc: dev/etherbus.cc: dev/etherdump.cc: dev/etherdump.hh: dev/etherlink.cc: dev/etherlink.hh: dev/ethertap.cc: sim/base_cpu.cc: sim/base_cpu.hh: sim/debug.cc: sim/eventq.cc: sim/eventq.hh: sim/exec_context.hh: sim/exetrace.hh: sim/hybrid_pred.hh: sim/main.cc: sim/memtest.cc: sim/memtest.hh: sim/pc_event.cc: sim/prog.hh: sim/sat_counter.hh: sim/serialize.cc: sim/sim_events.cc: sim/sim_events.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: sim/universe.cc: test/nmtest.cc: test/stattest.cc: test/symtest.cc: Global variable renaming. Basically equivalent to the following perl: s/\btick_t\b/Tick/g; s/\bsim_cycle\b/curTick/g; s/\bcounter_t\b/Counter/g; s/\bsim_freq\b/ticksPerSecond/g; dev/console.cc: dev/etherbus.cc: dev/etherdump.cc: dev/etherlink.cc: dev/ethertap.cc: Get rid of some explicit externs (use header files!). dev/ethertap.cc: Include for panic(). arch/alpha/alpha_memory.cc: sim/exec_context.hh: Various bug fixes. Charge all writebacks to thread 0 sim/eventq.cc: sim/eventq.hh: sim/main.cc: rework the event loop a bit so that we can prepare for dealing with asynchronous events properly. arch/alpha/alpha_memory.cc: arch/alpha/alpha_memory.hh: base/refcnt.hh: dev/alpha_console.cc: dev/alpha_console.hh: sim/exec_context.hh: sim/memtest.cc: sim/memtest.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: Initial move to reference counting MemReq objects. Switched to STL containers for storage in the memory hierarchy. sim/exec_context.hh: Fix LL/SC and got 1-6 CPUs working by fixing clock interrupt sim/simple_cpu.cc: Add the IIC as a selectable cache tag. Fix translation for now with a quick hack. sim/exec_context.hh: Put detection logic on failed Store Conditionals to help detect deadlock situations util/term/Makefile: util/term/term.c: Whittle down netcat to the bare minimum to connect to another machine and add the proper stuff to do some terminal handling to make this utility sufficient for connecting to m5 to get a console util/term/Makefile: add an install target base/pollevent.cc: sim/async.hh: sim/main.cc: Don't create events in signal handlers since it really isn't safe. I'm not positive if some bugs I've seen were caused by this, but we may as well be safe base/pollevent.cc: base/pollevent.hh: dev/console.cc: dev/console.hh: sim/async.hh: sim/main.cc: - clean up the pollevent stuff and just do the poll whenever requested since we will request it with the proper frequency - add an alarm to poll once every second in addition to waiting for sigio - remove all of the telnet crap since I'm never planning on implementing it - fix detaching and re-attaching of consoles base/pollevent.cc: base/pollevent.hh: sim/main.cc: only handle/raise SIGALRM if we're polling sim/memtest.cc: sim/cache/lzss_compression.hh: sim/cache/null_compression.hh: Initial check in of Compression stuff and IIC subblocking. base/remote_gdb.cc: Get rid of needless extern. arch/alpha/alpha_memory.cc: arch/alpha/alpha_memory.hh: arch/alpha/ev5.cc: arch/alpha/ev5.hh: arch/alpha/fake_syscall.cc: dev/alpha_console.cc: dev/alpha_console.hh: sim/exec_context.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: Rename fault type and fault codes as follows: s/md_fault_type/Fault/g; s/md_fault_none/No_Fault/g; s/md_fault_mcheck/Machine_Check_Fault/g; s/md_fault_opdec/Unimplemented_Opcode_Fault/g; s/md_fault_alignment/Alignment_Fault/g; s/md_fault_overflow/Integer_Overflow_Fault/g; s/md_fault_reset/Reset_Fault/g; s/md_fault_arith/Arithmetic_Fault/g; s/md_fault_interrupt/Interrupt_Fault/g; s/md_fault_ndtb_miss/Ndtb_Miss_Fault/g; s/md_fault_pdtb_miss/Pdtb_Miss_Fault/g; s/md_fault_dtb_fault/Dtb_Fault_Fault/g; s/md_fault_dtb_acv/Dtb_Acv_Fault/g; s/md_fault_itb_miss/Itb_Miss_Fault/g; s/md_fault_itb_fault/Itb_Fault_Fault/g; s/md_fault_itb_acv/Itb_Acv_Fault/g; s/md_fault_fen/Fen_Fault/g; s/md_fault_pal/Pal_Fault/g; s/md_fault_NUM/Num_Faults/g; Also changed 'enum md_fault_type' to just 'Fault' where possible. sim/exec_context.cc: sim/exec_context.hh: Add a constructor to specify a memory without a process sim/eventq.hh: clean up a bit. When events are resecheduled or removed from the schedule, they are no longer squashed. (Only scheduled events can be squashed.) sim/simple_cpu.hh: check to see if the tick event was squashed. If it was squashed, then it must be rescheduled since squashed events are scheduled. sim/exec_context.cc: sim/exec_context.hh: This new constructor is only for non FULL_SYSTEM base/statistics.cc: base/statistics.hh: test/stattest.cc: Remove unused variable dumpStats -> dump initStats -> init use const string & instead of const char * make Base constructor explicit more consistent formatting widths sim/main.cc: sim/sim_events.cc: make the new stats package useable in the simulator base/statistics.cc: base/statistics.hh: test/stattest.cc: create two standard stats that are to be used for calculations: elapsedTicks - is the number of ticks that has elapsed during this simulation. Currently, this is just curTick, but this may change when we have checkpointing. elapsedSeconds - is the number of simulated seconds that have elapsed during the simulation. Currently, this is just elapsedTicks / ticksPerSecond. sim/main.cc: Need to initialize stats much sooner so that SimObject constructors can register statistics base/statistics.cc: - use the stat_print_descriptions variable that the old stats package provides this is just a quick hack for now. When the old stats package goes away, we'll move this. - Fix the sorting algorithm so it works as I had intended - Make the output field widths equivalent to the old stats package base/statistics.cc: clean up memory sim/sim_events.cc: sim/sim_events.hh: Use autodelete sim/sim_events.cc: oops. didn't mean to commit this part util/tap/Makefile: call it m5tap instead of ethertap sim/exec_context.hh: Get rid of a couple of unnecessary forward class declarations. sim/memtest.cc: sim/memtest.hh: Adds compression to the memory hierarchy as well as using ExecContext to access memory. Added a few related config files. base/cprintf.cc: Default fill char is space, regardless of what stream fill char is. sim/exetrace.cc: Convert some of the hairier format things to ccprintf. base/statistics.cc: try getting the sorting a bit better arch/alpha/arguments.hh: base/refcnt.hh: base/statistics.hh: dev/etherpkt.hh: s/refcounted/RefCounted/ s/refcnt/RefCountingPtr/ arch/alpha/fake_syscall.cc: Zero out register files for newly created threads to make non-full-system MP runs deterministic. sim/exetrace.cc: Don't trace the results of NOPs or prefetches (for easier comparison with traces from new decoder). sim/exetrace.cc: Don't trace branch link values written back to R31 either. Also put a ifdef TARGET_ALPHA around this hack. sim/exetrace.cc: Need another ifdef TARGET_ALPHA... arch/alpha/alpha_memory.cc: arch/alpha/alpha_memory.hh: arch/alpha/arguments.cc: arch/alpha/ev5.cc: arch/alpha/ev5.hh: arch/alpha/fake_syscall.cc: arch/alpha/vtophys.cc: arch/alpha/vtophys.hh: base/object_file.hh: base/remote_gdb.cc: base/remote_gdb.hh: base/symtab.cc: base/symtab.hh: dev/alpha_console.cc: dev/simple_disk.cc: dev/simple_disk.hh: sim/base_cpu.cc: sim/base_cpu.hh: sim/exec_context.cc: sim/exec_context.hh: sim/exetrace.hh: sim/memtest.cc: sim/memtest.hh: sim/pc_event.cc: sim/pc_event.hh: sim/prog.cc: sim/prog.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: sim/system.cc: sim/system.hh: test/nmtest.cc: test/symtest.cc: Massive renaming to (almost) eliminate all md_* and MD_* names in preparation for total exorcism of machine.def. Most of the changes in this commit were performed with the following perl script (perl -pi <script> <files>). A small amount of manual fixup was needed to (mostly getting rid of the Addr typedefs in the various memory objects now that the former md_addr_t has that name). # rename machine-dependent types and constants (will be moving into ISA traits object) s/md_addr_t/Addr/g; s/md_intreg_t/IntReg/g; s/md_gpr_t/IntRegFile/g; s/md_fpreg_t/FloatReg/g; s/md_fpr_t/FloatRegFile/g; s/md_ctrlreg_t/MiscReg/g; s/md_ctrl_t/MiscRegFile/g; s/md_ipr_t/InternalProcReg/g; s/md_anyreg_t/AnyReg/g; s/md_inst_t/MachInst/g; s/regs_t/RegFile/g; # manually fix declaration in old/regs.h and a few forward decls s/struct RegFile/RegFile/g; s/MD_NUM_IREGS/NumIntRegs/g; s/MD_NUM_FREGS/NumFloatRegs/g; s/MD_NUM_CREGS/NumMiscRegs/g; s/MD_IPR_NUM/NumInternalProcRegs/g; s/MD_TOTAL_REGS/TotalNumRegs/g; s/MD_REG_ZERO/ZeroReg/g; base/statistics.hh: test/stattest.cc: Create a functor() wrapper for the stats package. This wrapper makes it possible to write an actual function or functor that is evaluated in a Formula base/statistics.hh: test/stattest.cc: Implement operator += for formulas. This allows us to build a formula without knowing all variables involved at compile time sim/sim_object.cc: sim/sim_object.hh: Make a different regStats pass for the new stats package base/statistics.cc: base/statistics.hh: sim/main.cc: Move simulator specific stuff to its own file. rename elapsedFoo to simFoo so it's clear we're talking about what's been simulated. Use the functor method to get the time. sim/base_cpu.cc: sim/base_cpu.hh: sim/main.cc: sim/simple_cpu.cc: sim/simple_cpu.hh: Convert instruction counting to new stats package. Convert the rest of SimpleCPU to new stats Do a bit of cleanup while we're at it base/cprintf.cc: attempt to deal with the badbit problem sim/base_cpu.hh: sim/simple_cpu.cc: no need for reg_stats to be pure virtual base/statistics.cc: base/statistics.hh: sim/simple_cpu.hh: test/stattest.cc: change names of stat classes so they are simpler base/statistics.cc: no unregestering stats base/statistics.cc: base/statistics.hh: sim/main.cc: test/stattest.cc: make it so that none of the constructors for the various stats objects take any parameters so that users may put them in arrays and stuff. Instead provide initialization functions for the objects that needed parameters, and provide a way to verify that all statistics that need initialization do get initialized. sim/cache/lzss_compression.hh: Compression fixes. Added trivial data support to the IIC. Set the max write size in the compressed memory to 1024 bytes sim/memtest.cc: sim/memtest.hh: Added 'percent_uncacheable' option to MemTest base/statistics.cc: base/statistics.hh: keep track of more data in distributions use a struct to pass data to the display function take underflow and overflow out of the array base/statistics.cc: support for printing vector totals sim/memtest.cc: sim/memtest.hh: Fix uncacheables to go to their own memory space. sim/memtest.cc: Change default percentage of uncacheables to 10% base/statistics.cc: base/statistics.hh: Correctly calculate vector totals. When a formula operates on vectors, it is incorrect to do calculate the formula for each vector element, and then sum the final formula vector. The correct way is to sum the individual vectors at the leaves of the expression tree. And then perform the calculation as if it were on scalar values. Assume we have vectors A, and B, and X = A * B The old way would have been: total(X) = total(A * B) The new way is total(X) = total(A) * total(B) Per thread miss rates are and example of something that would be calculated incorrectly. If you were to sum all of the miss rates, you could get a number greater than one. Calculating the overall miss rate should just be overall misses / overall accesses base/statistics.cc: base/statistics.hh: Create a #define STAT_DISPLAY_COMPAT that makes the new stat package output match the old one. arch/isa_parser.py: arch/alpha/alpha_memory.cc: arch/alpha/alpha_memory.hh: arch/alpha/arguments.cc: arch/alpha/ev5.cc: arch/alpha/ev5.hh: arch/alpha/fake_syscall.cc: arch/alpha/isa_desc: arch/alpha/isa_traits.hh: arch/alpha/vtophys.cc: arch/alpha/vtophys.hh: base/bitfield.hh: base/circlebuf.hh: base/object_file.hh: base/remote_gdb.cc: base/symtab.hh: dev/alpha_console.cc: dev/console.cc: sim/base_cpu.cc: sim/base_cpu.hh: sim/exec_context.cc: sim/exec_context.hh: sim/exetrace.cc: sim/exetrace.hh: sim/main.cc: sim/op_class.hh: sim/pc_event.cc: sim/pc_event.hh: sim/prog.cc: sim/prog.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: sim/static_inst.cc: sim/static_inst.hh: sim/system.cc: sim/system.hh: New ISA description system. No more machine.def! Instructions are now decoded into StaticInst objects, and all static instruction properties (including execution behavior) are associated with those objects. Extended documentation in progress. Currently supports Alpha only; PISA will not compile. Use END_OF_MACHINE_DOT_DEF tag to extract previous version. arch/isa_parser.py: Make it more obvious that you shouldn't edit decoder.cc, and harder to do so accidentally. arch/alpha/isa_desc: base/statistics.cc: sim/exec_context.hh: make stuff compile in g++ 3.x fix some bad formatting Doxyfile: Put generated docs in local directory docs/doxygen. Don't bother generating LaTeX, and a few other minor tweaks. arch/isa_parser.py: arch/alpha/isa_desc: - Decouple isa_desc operand types from C++ types. - Handle signed operand writebacks. - Add a few comments to suppress doxygen warnings on decoder.cc. sim/static_inst.cc: sim/static_inst.hh: Add some basic decode cache hash-table stats dumping (ifdef'd out). sim/static_inst.cc: Make it compile w/gcc3. sim/static_inst.cc: ostream doesn't seem to exist in 2.95 arch/alpha/alpha_memory.cc: arch/alpha/alpha_memory.hh: TLB statistics arch/alpha/ev5.cc: always pass the execution context to an annotation arch/alpha/ev5.cc: revert a bunch of crap from the last commit that I didn't want yet. arch/isa_parser.py: make it so that the ext source directory is grabbed from the right place arch/alpha/alpha_memory.cc: arch/alpha/ev5.cc: arch/alpha/isa_desc: arch/alpha/vtophys.cc: base/remote_gdb.cc: dev/alpha_console.cc: sim/exec_context.hh: sim/simple_cpu.cc: get rid of MD_IPR_foo and call it IPR_foo add some comments to describe what the various PALtemp registers do formatting sim/base_cpu.cc: sim/base_cpu.hh: sim/exec_context.cc: sim/exec_context.hh: sim/simple_cpu.cc: Keep a list of execution contexts in BaseCPU Provide a mechanism to register per execution context statistics. base/socket.cc: base/remote_gdb.cc: dev/console.cc: dev/ethertap.cc: don't panic if accept fails sim/simple_cpu.cc: sim/simple_cpu.hh: keep track of fraction of cycles that are idle base/statistics.hh: make proxy nodes work better in formulas. (Now totals should work). sim/op_class.hh: Document OpClass enum. sim/op_class.hh: Need to document file for file members (enum, globals, etc.) to be extracted arch/alpha/faults.cc: arch/alpha/faults.hh: arch/alpha/isa_traits.hh: Move Fault into its own file, and provide a function to get the string name of a fault arch/alpha/ev5.cc: arch/alpha/ev5.hh: arch/alpha/osfpal.cc: arch/alpha/osfpal.hh: move PAL code defines and such into their own file. Also provide a function to get the name of a PAL code arch/alpha/osfpal.cc: make this actually compile and add it to the makefile kern/tru64/tru64.hh: dummy class for differentiating Tru64 kern/tru64/tru64_syscalls.cc: kern/tru64/tru64_syscalls.hh: Stuff on tru64 system calls arch/alpha/ev5.cc: arch/alpha/isa_desc: sim/exec_context.cc: sim/exec_context.hh: Add a bunch of full system statistics base/statistics.cc: base/statistics.hh: sim/sim_events.cc: support for printing stats to a file. For now we will continue to print to standard out so that the whole regression thing doesn't break. While we're at it, move the Stat param context to the new stats package sim/exec_context.hh: sim/main.cc: sim/simple_cpu.cc: sim/simple_cpu.hh: Today saw the wholesale slaughter of greened's code. When we asked the accused, Erik Hallnor, why he did it he responded, 'Because I was bored. And the underlying prefetch cache was soon to be 2 generations out of date.' sim/base_cpu.hh: sim/exec_context.cc: added a std::vector and using namespace std arch/alpha/fake_syscall.cc: Avoid conflicts with #defines in headers arch/alpha/fake_syscall.cc: I think this is what steve had in mind. base/endian.hh: get rid of the simplescalar endianness junk and make it a bit simpler base/cprintf.cc: base/cprintf.hh: base/cprintf_formats.hh: base/statistics.cc: test/cprintftest.cc: Break out the cprintf formatting stuff into per-type formatting so that we can do special formatting based on type. This makes %c work correctly for integer types. It also allows me to add a workaround for string format widths. Finally, it allows me to accept stringstream directly as an argument without having to use the .str() member. Doxyfile: Update Doxyfile to new version of doxygen and to use the newly install graphviz package. Doxyfile: Remove . from the file paths, instead of .. base/cprintf.cc: base/cprintf_formats.hh: base/statistics.cc: test/cprintftest.cc: Fix printing of strings. Seems that I just can't do what I want with templates. They're too smart for they're own good. Fix format field widths for floating point numbers. Remove some .str()'s that are no longer needed because cprintf supports them. base/statistics.cc: base/statistics.hh: test/stattest.cc: Make internal design a bit more consistent. Re-work Bins and Vectors and how they work together to remove a level of indirection. base/statistics.cc: base/statistics.hh: revert that last change base/statistics.cc: base/statistics.hh: test/stattest.cc: let's try this again. This time we'll make DistStat classes initialize their bins. Also add a test for this base/statistics.hh: Proxy -> VectorProxy Doxyfile: Don't hide undocumented classes. This helps when tracking includes through the new graphs. Doxyfile: Make things run faster until documentation errors are gone sim/prog.cc: sim/simple_cpu.cc: Change declarations to match defenitions. dev/alpha_access.h: dev/alpha_console.cc: dev/alpha_console.hh: dev/console.cc: dev/console.hh: dev/disk_image.cc: dev/disk_image.hh: dev/etherbus.cc: dev/etherbus.hh: dev/etherdump.cc: dev/etherdump.hh: dev/etherint.hh: dev/etherlink.cc: dev/etherlink.hh: dev/etherpkt.hh: dev/ethertap.cc: dev/ethertap.hh: dev/pcireg.h: dev/simple_disk.cc: dev/simple_disk.hh: sim/eventq.hh: sim/serialize.hh: sim/sim_object.hh: sim/simple_cpu.cc: Removal of 1200 doxygen warnings. The 600 left are mostly from StaticInstBase and decoder.cc. I basically un-documented the partially documented code by changing /** to /*. arch/alpha/ev5.cc: Add FULL_SYSTEM protection to match header file. Doxyfile: dev/alpha_console.hh: dev/etherint.hh: dev/simple_disk.hh: sim/simple_cpu.cc: sim/static_inst.hh: sim/cache/null_compression.hh: Down to 464 warnings, all in static_inst.hh or decoder.cc. Punt on the template instantiation thing by making them invisible to doxygen. arch/alpha/alpha_memory.cc: base/statistics.cc: base/statistics.hh: sim/simple_cpu.cc: test/stattest.cc: New way of specifying information about printing stats. old way: stat.setFormat(name, ...); new way: stat .name(...) .desc(...) .prereq(...) . . ; This allows you to specify any information about the stats, and do it in any order. It also cleans up the kinda crufty setFormat interfaces. LICENSE: This is the M5 license as agreed upon by the original M5 authors, and blessed by the University of Michigan technology transfer office. OK by Doug Hockstad <dhocksta@umich.edu> base/statistics.hh: missing_math is only for stats, so move it into its own place base/statistics.cc: test/stattest.cc: Fix stats sorting base/statistics.cc: base/statistics.hh: test/stattest.cc: Fix description printing stuff. Add a flag to the test script to turn descriptions on/off base/str.hh: wrapper to convert values to strings via stringstream base/statistics.hh: nitpick base/statistics.cc: base/statistics.hh: test/stattest.cc: Rework the printing of statistics to make the PrintOne function not need to know about the stats themselves. Also remove the overloading of function names for getting and setting parameters. base/statistics.cc: duh base/statistics.cc: Changes for _name issues base/statistics.cc: base/statistics.hh: Reorganize the base Stat class a bit and clean up handling of data base/statistics.cc: base/statistics.hh: Rework the stat printing stuff a bit so that the formatting parts need to know as little as possible about the type of stat being printed. base/statistics.hh: maybe not all vector stats will be registered in the future. (VectorProxies) base/statistics.hh: test/stattest.cc: VectorDistribution stat. To be used for per-thread distributions. Still need to implement total and zero() arch/alpha/isa_traits.hh: sim/static_inst.hh: don't use stdint.h, use either inttypes.h or host.h sim/main.cc: unneeded arch/alpha/isa_desc: only linux seems to support the rounding mode stuff right now base/statistics.hh: test/stattest.cc: VectorStandardDeviation and VectorAverageDeviation base/statistics.cc: just make sure the size is correct base/statistics.hh: use pointers internally instead of references arch/alpha/faults.cc: base/bitfield.hh: sim/cache/lzss_compression.hh: sim/cache/null_compression.hh: sim/op_class.hh: sim/sim_time.hh: sim/static_inst.cc: sim/static_inst.hh: test/stattest.cc: consistent $Id$ tags test/bitvectest.cc: test/circletest.cc: test/cprintftest.cc: test/initest.cc: test/lru_test.cc: test/nmtest.cc: test/offtest.cc: test/paramtest.cc: test/rangetest.cc: test/sized_test.cc: test/stattest.cc: test/strnumtest.cc: test/symtest.cc: test/tokentest.cc: arch/isa_parser.py: arch/alpha/alpha_memory.cc: arch/alpha/alpha_memory.hh: arch/alpha/arguments.cc: arch/alpha/arguments.hh: arch/isa_parser.py: arch/alpha/faults.cc: arch/alpha/faults.hh: arch/alpha/isa_traits.hh: arch/alpha/osfpal.cc: arch/alpha/osfpal.hh: arch/alpha/vtophys.cc: arch/alpha/vtophys.hh: util/tap/tap.cc: base/bitfield.hh: base/callback.hh: base/circlebuf.cc: base/circlebuf.hh: base/cprintf.cc: base/cprintf.hh: base/cprintf_formats.hh: base/date.cc: base/dbl_list.hh: base/endian.hh: base/fifo_buffer.cc: base/fifo_buffer.hh: base/hashmap.hh: base/inet.cc: base/inet.hh: base/inifile.cc: base/inifile.hh: base/intmath.cc: base/intmath.h: base/misc.cc: base/misc.hh: base/mod_num.hh: base/object_file.cc: base/object_file.hh: base/pollevent.cc: base/pollevent.hh: base/range.hh: base/refcnt.hh: base/remote_gdb.hh: base/res_list.hh: base/sched_list.hh: base/socket.cc: base/socket.hh: base/statistics.cc: base/statistics.hh: base/str.cc: base/str.hh: base/symtab.cc: base/symtab.hh: base/trace.cc: base/trace.hh: dev/alpha_access.h: dev/alpha_console.cc: dev/alpha_console.hh: dev/disk_image.cc: dev/disk_image.hh: dev/etherbus.cc: dev/etherbus.hh: dev/etherdump.cc: dev/etherdump.hh: dev/etherint.cc: dev/etherint.hh: dev/etherlink.cc: dev/etherlink.hh: dev/etherpkt.hh: dev/ethertap.cc: dev/ethertap.hh: dev/pcireg.h: dev/simple_disk.cc: dev/simple_disk.hh: kern/tru64/tru64.hh: kern/tru64/tru64_syscalls.cc: kern/tru64/tru64_syscalls.hh: sim/cache/null_compression.hh: sim/async.hh: sim/debug.cc: sim/debug.hh: sim/eventq.cc: sim/eventq.hh: sim/exetrace.cc: sim/exetrace.hh: sim/intr_control.cc: sim/intr_control.hh: sim/memtest.cc: sim/memtest.hh: sim/op_class.hh: sim/param.cc: sim/param.hh: sim/pc_event.cc: sim/pc_event.hh: sim/predictor.hh: sim/sat_counter.cc: sim/sat_counter.hh: sim/serialize.cc: sim/serialize.hh: sim/sim_events.cc: sim/sim_events.hh: sim/sim_exit.hh: sim/sim_object.cc: sim/sim_object.hh: sim/sim_time.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: sim/static_inst.cc: sim/static_inst.hh: sim/std_types.hh: sim/system.cc: sim/system.hh: sim/universe.cc: sim/exec_context.cc: sim/exec_context.hh: license base/date.cc: move test/stattest.cc: remove dave's scary container stuff sim/base_cpu.cc: sim/base_cpu.hh: sim/simple_cpu.cc: rename the exec context list xc to contexts arch/alpha/alpha_memory.cc: arch/alpha/alpha_memory.hh: arch/alpha/fake_syscall.cc: dev/alpha_console.cc: sim/exec_context.hh: sim/memtest.cc: sim/prog.cc: sim/prog.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: sim/system.cc: sim/system.hh: s/exe_ctx/xc/g sim/base_cpu.cc: Can't assume that context[0] exists. sim/cache/lzss_compression.cc: sim/cache/lzss_compression.hh: Our compression code free and clear. arch/alpha/fake_syscall.cc: base/range.hh: base/statistics.hh: sim/param.cc: sim/sim_object.cc: Changes to build with g++-3.3. Mostly added a bunch of includes of assert.h (not sure why older versions didn't need this). Also fixed up a couple other new warnings. arch/alpha/alpha_memory.cc: arch/alpha/alpha_memory.hh: arch/alpha/ev5.cc: arch/alpha/fake_syscall.cc: arch/alpha/isa_traits.hh: arch/alpha/vtophys.cc: arch/alpha/vtophys.hh: dev/alpha_console.hh: dev/console.cc: dev/console.hh: dev/disk_image.cc: dev/etherdump.cc: dev/simple_disk.cc: sim/simple_cpu.cc: sim/system.cc: sim/system.hh: a little style sim/eventq.cc: sim/main.cc: sim/prog.cc: sim/simple_cpu.cc: sim/smt.hh: smt.h -> smt.hh add license base/statistics.hh: missing_math.hh isn't really needed I guess arch/alpha/arguments.hh: arch/alpha/fake_syscall.cc: arch/alpha/isa_traits.hh: base/hashmap.hh: base/inet.cc: base/inet.hh: base/misc.cc: base/pollevent.cc: base/socket.cc: base/statistics.hh: base/symtab.cc: base/symtab.hh: base/trace.hh: dev/alpha_console.hh: dev/etherlink.hh: dev/etherpkt.hh: sim/eventq.hh: sim/exec_context.hh: sim/exetrace.hh: sim/host.hh: sim/main.cc: sim/param.hh: sim/serialize.hh: sim/sim_object.cc: sim/simple_cpu.cc: sim/static_inst.hh: sim/universe.cc: test/stattest.cc: Get rid of simplescalar host.h file and create our own host.hh file that has less junk. (with our license.) While we're at it, we consolidate all of the hashtable junk into one file hashmap.hh. (use this file if you need a hash_map.) Doxyfile: Avoid infinite recursion on build/src link. arch/alpha/isa_desc: sim/static_inst.hh: Add comments to get rid of doxygen warnings (and occasionally, as an accidental side effect, make the code more maintainable). Doxyfile: Turn off information messages and route error messages to stderr. arch/isa_parser.py: arch/alpha/isa_desc: sim/static_inst.hh: - Add some comments clarifying the semantics of StaticInst flags. - Make minor tweaks to the ISA description code to make corner cases consistent with the above comments :-). - Get rid of insn_counting code... instruction mix doesn't really change through the pipeline, and the overall mix can already be derived from existing stats. Plus it keeps changing when the ISA flags change even though the pipeline doesn't care. sim/hybrid_pred.cc: sim/hybrid_pred.hh: So said Steve Raasch:xi "I know that the following files should be under our license" base/fast_alloc.cc: base/fast_alloc.hh: David Wood said I could have my own code back :-). sim/sim_object.cc: sim/sim_object.hh: create a regFormulas pass that will go AFTER the regStats pass. sim/base_cpu.cc: sim/base_cpu.hh: sim/debug.cc: sim/eventq.cc: sim/exec_context.hh: sim/exetrace.cc: sim/exetrace.hh: sim/hybrid_pred.cc: sim/hybrid_pred.hh: sim/intr_control.hh: sim/main.cc: sim/memtest.cc: sim/memtest.hh: sim/op_class.hh: sim/param.cc: sim/param.hh: sim/pc_event.hh: sim/predictor.hh: sim/prog.cc: sim/prog.hh: sim/sat_counter.cc: sim/sat_counter.hh: sim/serialize.cc: sim/serialize.hh: sim/sim_object.hh: sim/sim_time.hh: sim/simple_cpu.hh: sim/smt.hh: sim/static_inst.cc: sim/static_inst.hh: sim/std_types.hh: sim/system.cc: style police base/statistics.cc: base/statistics.hh: test/stattest.cc: initial cut at a 2d vector stat base/statistics.cc: base/statistics.hh: Added a std:: and removed an unused bool arch/alpha/fake_syscall.cc: sim/base_cpu.cc: sim/base_cpu.hh: sim/prog.cc: sim/prog.hh: Steve Reinhardt says "I wrote these myself from scratch" base/date.cc: I probably changed this to a string in the first place, but it should be a const char * sim/main.cc: make this compile again base/random.cc: base/random.hh: sim/main.cc: Get rid of the Simplescalar random number junk. Since I didn't realize that we didn't even use it until after I wrote a simple replacement, I figure I'll commit the replacement in case we ever need it. base/str.hh: sim/main.cc: quote may be more generally useful sim/main.cc: sim/sim_object.cc: sim/sim_object.hh: Make the old stats package a bit more self contained to prepare for future extrication sim/main.cc: sim/sim_time.cc: sim/sim_time.hh: consolidate all of the time handling stuff sim/base_cpu.cc: sim/base_cpu.hh: sim/main.cc: sim/smt.hh: instead of initializing max_threads_per_cpu in main(), we turn it into a static function and initialize it upon the first call Users of this should beware that all CPUs must be built before this function can be used. sim/main.cc: sim/universe.cc: sim_running_systems makes more sense in universe.cc sim/main.cc: this is not a simplescalar file, use our copyright say that the simulator is M5 and display our copyright cleanup change a few things here and there to use our style use endl instead of "\n" (for future portablility) sim/async.hh: sim/main.cc: sim/system.cc: sim/system.hh: sim/universe.cc: - Clean up a few simplescalar comments from main.cc that Nate missed. - Add some comments and some doxygen documentation. - Move sim_running_systems to static System::numSystemsRunning. arch/alpha/ev5.cc: Update num_running_systems to System::numSystemsRunning for full-sys too. sim/base_cpu.cc: sim/base_cpu.hh: sim/smt.hh: instead of polling all CPUs to find out the max number of threads across all CPUs, just have the CPUs themselves update the variable as they are created. arch/alpha/isa_desc: First pass at fixing cvtst... not tested. arch/alpha/ev5.cc: base/statistics.cc: base/statistics.hh: arch/alpha/isa_desc: Just use the TYPEFUNC not FULLFUNC arch/alpha/ev5.cc: base/statistics.cc: base/statistics.hh: committing from the wrong directory is a bad thing arch/alpha/isa_desc: I hope a final solution for the cmptxx issue. base/statistics.cc: All printable stats must first be initialized, so throw an assertion if they are not. This ought to help in debugging a bit. base/statistics.cc: base/statistics.hh: Two new flags: nozero, and nonan. This will supress printing stats if they are zero or NAN. For example, it will cause vector elements to be skipped if there is no value, or it will cause distribution buckets to be skipped. (or an entire scalar stat to be skipped.) This can be used in conjunction with prereq. The difference with prereq, is that prereq just checks if the other stat has ANY values, and won't selectively ignore individual vector elements. base/statistics.hh: this does not belong here arch/alpha/isa_desc: Just happened to notice small insidious bug in itofs. arch/isa_parser.py: New isa description language feature: multiple constants can be provided for a decode statement, e.g.: decode OP { 0, 1: foo(); 2, 3: bar(); } Documentation update included at no extra charge. sim/param.hh: this can be const sim/exec_context.cc: be more terse arch/alpha/isa_desc: Revamp decoding of IEEE FP instructions (opcode 0x16). I think we've got all the bases covered now. Also implemented cvtql/v & cvtql/sv (actually the same instruction from M5's perspective). arch/isa_parser.py: - If isa_desc defines the global Python variable rcs_id, echo it into the output decoder.cc. - Only print last three components of ISA description path name in output. - Add RCS id string to this file. arch/alpha/isa_desc: Add RCS id string. arch/isa_parser.py: Get it right. arch/isa_parser.py: Oone more little glitch... kern/tru64/tru64_syscalls.cc: kern/tru64/tru64_syscalls.hh: add support for mach syscalls. base/trace.cc: base/trace.hh: Some reorganization and cleanup. Add the ability to ignore trace output from certain sources. The option is --trace:ignore. It takes a space separated list of SimObjects to ignore. The SimObject is listed in the normal dotted herarchy notation. (e.g. system0.cpu0.DL1) If an object is specified, the *all* child objects are ignored as well. You can use a wildcard (*) to match any object. To ignore all trace statements from system1: --trace:ignore"system1" To ignore all DL1 statements: --trace:ignore="*.*.DL1" sim/main.cc: Try the HOST varilable if HOSTNAME isn't found sim/exetrace.cc: sim/exetrace.hh: Minor tweeks to instruction execution tracing: - add a correct-path sequence number to all instructions - add colon characters to help delimit the instruction disassembly arch/alpha/ev5.cc: Move all of the kernel statistics into the .cc file while I am still messing around with them. Add support for tracking context switches, and mode switches. More detailed tracking of ipl changes. Don't display zeroes for stats such as syscalls, ipls, faults, since zeroes are very common and there are a ton of stats. base/hashmap.hh: don't forget about the hash_multimap oh, and string is used in here base/str.cc: convert strings that represent bool values to a bool arch/alpha/alpha_memory.cc: arch/alpha/alpha_memory.hh: arch/alpha/ev5.cc: rework the tlb lookup code so that it uses a map instead of a linear search. base/statistics.cc: a tiny bit of debugging assistance arch/alpha/alpha_memory.cc: arch/alpha/alpha_memory.hh: sim/exec_context.hh: No need for these functions to be virtual. Given that, they don't need to have the same interface. This eliminates a useless check in an expensive function. arch/alpha/isa_desc: This is an quick fix for the SimpleSclar-FP-Ops-Don't-Work-Right bug The SS_COMPATIBLE_FP #define at the top of the file forces the precision to match SS. This will change the precision for ALL CPU's. Nate will be making a change shortly so that this not done for Full System arch/alpha/alpha_memory.cc: use i-> instead of (*i). (what was I thinking?) also try to do i-> only once if it can be helped. base/remote_gdb.cc: sim/simple_cpu.cc: Move remote debugger code to where it belongs clean it up a tad while we're at it. arch/alpha/isa_desc: Changes for the SS FP bug: SS-style FP done only if SS_COMPATIBLE_FP is defined in the makefile arch/alpha/isa_traits.hh: sim/memtest.cc: sim/memtest.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: sim/cache/lzss_compression.cc: sim/cache/lzss_compression.hh: The new memory hierarchy. There is still some more changes to come, but this works now. IIC compression is broken, but no one else cares. DMA coherence might be broken (no way to test atm). There are doxygen warnings that I will clear up when I can stay connected for more than 3 minutes. Doxyfile: Turn Graphics back on since we have squashed the warnings. base/misc.hh: Add #include <assert.h> for those who use m5_assert() macro. Somehow g++ 3.3 is pickier about this than 3.2. sim/exetrace.hh: sim/simple_cpu.cc: sim/std_types.hh: Style fixes... mostly changing 'struct foo_bar' to 'FooBar' for some older parts of the code. Doxyfile: Always have a detailed section. sim/host.hh: Get rid of an old simplescalar comment (plus improve some other comments). base/statistics.cc: base/statistics.hh: provide a way to get at the subdesc base/statistics.hh: Make it possible to counte a sample more than once base/statistics.cc: print the right value base/statistics.cc: base/statistics.hh: A bit of debugging support base/statistics.cc: base/statistics.hh: be more consistent base/statistics.hh: use the correct axis base/statistics.hh: remove dead code sim/main.cc: sim/param.cc: sim/param.hh: sim/sim_object.cc: Stats now sent by default to a file called "m5.stats". Get the old behavior back by saying "--stats:file=cerr" on cmd line. Parameters and config-file stuff also sent to stats file where they belong. A few informational messages are sent to both cerr and to the stats file. Default output is pretty minimal now. arch/alpha/faults.cc: base/bitfield.hh: base/random.cc: base/random.hh: sim/static_inst.cc: test/stattest.cc: Fix RCS Id strings. sim/base_cpu.hh: sim/main.cc: Check if user forgot to specify any CPUs and print a meaningful error message (not just "improperly exited event loop!"). base/statistics.cc: base/statistics.hh: Make subsequent calls to flags() add more flags instead of change them. Also add the concept of a reserved flag that the user is not allowed to set. (Basically for passing around extra parameters in the stats package.) sim/debug.cc: sim/param.cc: sim/param.hh: sim/prog.cc: sim/sim_events.cc: Check that VectorParam objects are valid before we let them be referenced. Fix up a few places where we were just referencing them w/o checking. Also some const cleanup on Param object methods. sim/sim_object.cc: sim/sim_object.hh: Print SimObject class name when complaining about missing/broekn params. base/inifile.cc: Add "-undef" to cpp flags to not define system-specific macros. (A '#define linux 1' was giving me trouble.) base/statistics.hh: add support fo subnaming in the y direction for 2d vectors. make the printing of it pretty and compatible with the old style. also, suppress printing of a total for 2d vector if they x dimension is just 1. base/statistics.cc: rework a lot of the stuff between #ifdef STAT_DISPLAY_COMPAT so it's neater and also more accurate. add support for printing subdescriptions. LICENSE: arch/alpha/alpha_memory.cc: arch/alpha/alpha_memory.hh: arch/alpha/arguments.cc: arch/alpha/arguments.hh: arch/alpha/fake_syscall.cc: arch/alpha/faults.cc: arch/alpha/faults.hh: arch/alpha/isa_traits.hh: arch/alpha/osfpal.cc: arch/alpha/osfpal.hh: arch/alpha/vtophys.cc: arch/alpha/vtophys.hh: base/bitfield.hh: base/callback.hh: base/circlebuf.cc: base/circlebuf.hh: base/cprintf.cc: base/cprintf.hh: base/cprintf_formats.hh: base/date.cc: base/dbl_list.hh: base/endian.hh: base/fast_alloc.cc: base/fast_alloc.hh: base/fifo_buffer.cc: base/fifo_buffer.hh: base/hashmap.hh: base/inet.cc: base/inet.hh: base/inifile.cc: base/inifile.hh: base/intmath.cc: base/misc.cc: base/misc.hh: base/mod_num.hh: base/object_file.cc: base/object_file.hh: base/pollevent.cc: base/pollevent.hh: base/random.cc: base/random.hh: base/range.hh: base/refcnt.hh: base/remote_gdb.hh: base/res_list.hh: base/sched_list.hh: base/socket.cc: base/socket.hh: base/statistics.cc: base/statistics.hh: base/str.cc: base/str.hh: base/symtab.cc: base/symtab.hh: base/trace.cc: base/trace.hh: dev/alpha_console.cc: dev/alpha_console.hh: dev/disk_image.cc: dev/disk_image.hh: dev/etherbus.cc: dev/etherbus.hh: dev/etherdump.cc: dev/etherdump.hh: dev/etherint.cc: dev/etherint.hh: dev/etherlink.cc: dev/etherlink.hh: dev/etherpkt.hh: dev/ethertap.cc: dev/ethertap.hh: dev/simple_disk.cc: dev/simple_disk.hh: kern/tru64/tru64.hh: kern/tru64/tru64_syscalls.cc: kern/tru64/tru64_syscalls.hh: sim/async.hh: sim/base_cpu.cc: sim/base_cpu.hh: sim/debug.cc: sim/debug.hh: sim/eventq.cc: sim/eventq.hh: sim/exec_context.cc: sim/exec_context.hh: sim/exetrace.cc: sim/exetrace.hh: sim/host.hh: sim/hybrid_pred.cc: sim/hybrid_pred.hh: sim/intr_control.cc: sim/intr_control.hh: sim/main.cc: sim/memtest.cc: sim/memtest.hh: sim/op_class.hh: sim/param.cc: sim/param.hh: sim/pc_event.cc: sim/pc_event.hh: sim/predictor.hh: sim/prog.cc: sim/prog.hh: sim/sat_counter.cc: sim/sat_counter.hh: sim/serialize.cc: sim/serialize.hh: sim/sim_events.cc: sim/sim_events.hh: sim/sim_exit.hh: sim/sim_object.cc: sim/sim_object.hh: sim/cache/lzss_compression.cc: sim/cache/lzss_compression.hh: sim/cache/null_compression.hh: sim/sim_time.cc: sim/sim_time.hh: sim/simple_cpu.cc: sim/simple_cpu.hh: sim/smt.hh: sim/static_inst.cc: sim/static_inst.hh: sim/std_types.hh: sim/system.cc: sim/system.hh: sim/universe.cc: test/bitvectest.cc: test/circletest.cc: test/cprintftest.cc: test/initest.cc: test/lru_test.cc: test/nmtest.cc: test/offtest.cc: test/paramtest.cc: test/rangetest.cc: test/sized_test.cc: test/stattest.cc: test/strnumtest.cc: test/symtest.cc: test/tokentest.cc: util/tap/tap.cc: arch/isa_parser.py: Add attribution to license. sim/cache/lzss_compression.cc: sim/cache/lzss_compression.hh: Extend the compression algorithm to handle upto 4096 byte blocks. Improve compression of single bytes that can be sign extended. sim/cache/lzss_compression.hh: Remove some todos that I've already done. sim/hybrid_pred.cc: sim/hybrid_pred.hh: sim/memtest.cc: sim/prog.cc: sim/sat_counter.cc: sim/memtest.hh: sim/predictor.hh: sim/prog.hh: sim/sat_counter.hh: the new stats package. voila. the move to bitkeeper can go on, figuring what's happening can happen later. base/trace.cc: test/Makefile: test/cprintftest.cc: test/tracetest.cc: separate the context stuff for tracing from the actual tracing facility to make it easier to test. Add a test for tracing --HG-- extra : convert_revision : 28dd3568b0714296345f8a5cba282f0b937ce725
-rw-r--r--Doxyfile1109
-rw-r--r--LICENSE25
-rw-r--r--arch/alpha/alpha_memory.cc661
-rw-r--r--arch/alpha/alpha_memory.hh126
-rw-r--r--arch/alpha/arguments.cc64
-rw-r--r--arch/alpha/arguments.hh143
-rw-r--r--arch/alpha/ev5.cc571
-rw-r--r--arch/alpha/ev5.hh104
-rw-r--r--arch/alpha/fake_syscall.cc1736
-rw-r--r--arch/alpha/faults.cc61
-rw-r--r--arch/alpha/faults.hh56
-rw-r--r--arch/alpha/isa_desc2427
-rw-r--r--arch/alpha/isa_traits.hh282
-rw-r--r--arch/alpha/osfpal.cc304
-rw-r--r--arch/alpha/osfpal.hh79
-rw-r--r--arch/alpha/vtophys.cc123
-rw-r--r--arch/alpha/vtophys.hh46
-rw-r--r--arch/isa_parser.py1446
-rw-r--r--base/bitfield.hh69
-rw-r--r--base/callback.hh56
-rw-r--r--base/circlebuf.cc187
-rw-r--r--base/circlebuf.hh59
-rw-r--r--base/cprintf.cc277
-rw-r--r--base/cprintf.hh197
-rw-r--r--base/cprintf_formats.hh354
-rw-r--r--base/date.cc29
-rw-r--r--base/dbl_list.hh165
-rw-r--r--base/endian.hh41
-rw-r--r--base/fast_alloc.cc191
-rw-r--r--base/fast_alloc.hh203
-rw-r--r--base/fifo_buffer.cc40
-rw-r--r--base/fifo_buffer.hh93
-rw-r--r--base/hashmap.hh83
-rw-r--r--base/inet.cc161
-rw-r--r--base/inet.hh37
-rw-r--r--base/inifile.cc437
-rw-r--r--base/inifile.hh111
-rw-r--r--base/intmath.cc58
-rw-r--r--base/intmath.h123
-rw-r--r--base/kgdb.h203
-rw-r--r--base/misc.cc97
-rw-r--r--base/misc.hh76
-rw-r--r--base/mod_num.hh201
-rw-r--r--base/object_file.cc173
-rw-r--r--base/object_file.hh92
-rw-r--r--base/pollevent.cc254
-rw-r--r--base/pollevent.hh89
-rw-r--r--base/random.cc79
-rw-r--r--base/random.hh100
-rw-r--r--base/range.hh260
-rw-r--r--base/refcnt.hh122
-rw-r--r--base/remote_gdb.cc1150
-rw-r--r--base/remote_gdb.hh189
-rw-r--r--base/res_list.hh756
-rw-r--r--base/sched_list.hh176
-rw-r--r--base/socket.cc114
-rw-r--r--base/socket.hh49
-rw-r--r--base/statistics.cc823
-rw-r--r--base/statistics.hh1682
-rw-r--r--base/str.cc332
-rw-r--r--base/str.hh127
-rw-r--r--base/symtab.cc133
-rw-r--r--base/symtab.hh59
-rw-r--r--base/trace.cc325
-rw-r--r--base/trace.hh218
-rw-r--r--dev/alpha_access.h79
-rw-r--r--dev/alpha_console.cc273
-rw-r--r--dev/alpha_console.hh108
-rw-r--r--dev/console.cc478
-rw-r--r--dev/console.hh147
-rw-r--r--dev/disk_image.cc427
-rw-r--r--dev/disk_image.hh130
-rw-r--r--dev/etherbus.cc128
-rw-r--r--dev/etherbus.hh79
-rw-r--r--dev/etherdump.cc138
-rw-r--r--dev/etherdump.hh60
-rw-r--r--dev/etherint.cc44
-rw-r--r--dev/etherint.hh63
-rw-r--r--dev/etherlink.cc148
-rw-r--r--dev/etherlink.hh123
-rw-r--r--dev/etherpkt.hh65
-rw-r--r--dev/ethertap.cc295
-rw-r--r--dev/ethertap.hh101
-rw-r--r--dev/pcireg.h175
-rw-r--r--dev/simple_disk.cc108
-rw-r--r--dev/simple_disk.hh60
-rw-r--r--kern/tru64/tru64.hh34
-rw-r--r--kern/tru64/tru64_syscalls.cc438
-rw-r--r--kern/tru64/tru64_syscalls.hh355
-rw-r--r--sim/async.hh49
-rw-r--r--sim/base_cpu.cc158
-rw-r--r--sim/base_cpu.hh122
-rw-r--r--sim/cache/lzss_compression.cc166
-rw-r--r--sim/cache/lzss_compression.hh100
-rw-r--r--sim/cache/null_compression.hh72
-rw-r--r--sim/debug.cc137
-rw-r--r--sim/debug.hh34
-rw-r--r--sim/eventq.cc212
-rw-r--r--sim/eventq.hh351
-rw-r--r--sim/exec_context.cc106
-rw-r--r--sim/exec_context.hh360
-rw-r--r--sim/exetrace.cc190
-rw-r--r--sim/exetrace.hh197
-rw-r--r--sim/host.hh57
-rw-r--r--sim/hybrid_pred.cc275
-rw-r--r--sim/hybrid_pred.hh203
-rw-r--r--sim/intr_control.cc59
-rw-r--r--sim/intr_control.hh61
-rw-r--r--sim/main.cc429
-rw-r--r--sim/memtest.cc324
-rw-r--r--sim/memtest.hh140
-rw-r--r--sim/op_class.hh64
-rw-r--r--sim/param.cc760
-rw-r--r--sim/param.hh757
-rw-r--r--sim/pc_event.cc231
-rw-r--r--sim/pc_event.hh215
-rw-r--r--sim/predictor.hh62
-rw-r--r--sim/prog.cc281
-rw-r--r--sim/prog.hh180
-rw-r--r--sim/sat_counter.cc270
-rw-r--r--sim/sat_counter.hh192
-rw-r--r--sim/serialize.cc353
-rw-r--r--sim/serialize.hh241
-rw-r--r--sim/sim_events.cc271
-rw-r--r--sim/sim_events.hh131
-rw-r--r--sim/sim_exit.hh41
-rw-r--r--sim/sim_object.cc280
-rw-r--r--sim/sim_object.hh261
-rw-r--r--sim/sim_time.cc152
-rw-r--r--sim/sim_time.hh84
-rw-r--r--sim/simple_cpu.cc747
-rw-r--r--sim/simple_cpu.hh280
-rw-r--r--sim/smt.hh64
-rw-r--r--sim/static_inst.cc88
-rw-r--r--sim/static_inst.hh433
-rw-r--r--sim/std_types.hh40
-rw-r--r--sim/system.cc250
-rw-r--r--sim/system.hh113
-rw-r--r--sim/universe.cc58
-rw-r--r--test/Makefile83
-rw-r--r--test/bitvectest.cc66
-rw-r--r--test/circletest.cc72
-rw-r--r--test/cprintftest.cc164
-rw-r--r--test/foo.ini7
-rw-r--r--test/initest.cc117
-rw-r--r--test/initest.ini14
-rw-r--r--test/lru_test.cc82
-rw-r--r--test/nmtest.cc75
-rw-r--r--test/offtest.cc70
-rw-r--r--test/paramtest.cc105
-rw-r--r--test/rangetest.cc104
-rw-r--r--test/sized_test.cc67
-rw-r--r--test/stattest.cc504
-rw-r--r--test/strnumtest.cc74
-rw-r--r--test/symtest.cc77
-rw-r--r--test/tokentest.cc69
-rw-r--r--test/tracetest.cc54
-rw-r--r--util/rundiff511
-rw-r--r--util/tap/Makefile67
-rw-r--r--util/tap/tap.cc415
-rw-r--r--util/term/Makefile45
-rw-r--r--util/term/term.c312
162 files changed, 38124 insertions, 0 deletions
diff --git a/Doxyfile b/Doxyfile
new file mode 100644
index 000000000..3bf57ca71
--- /dev/null
+++ b/Doxyfile
@@ -0,0 +1,1109 @@
+# Doxyfile 1.3.3
+
+# 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 (" ")
+
+#---------------------------------------------------------------------------
+# General 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, 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 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 = NO
+
+# 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
+
+# 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
+
+# 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.
+
+STRIP_FROM_PATH = .
+
+# 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 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 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 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
+# explict @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
+# reimplements.
+
+INHERIT_DOCS = 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 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
+
+# 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
+
+# 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 =
+
+# 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 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 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
+
+# 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
+
+#---------------------------------------------------------------------------
+# 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
+
+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 */CVS
+
+# 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 =
+
+# 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.
+
+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 = 5
+
+# 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 =
+
+# 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
+
+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 dir.
+
+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 optimised 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 assigments. 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. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+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 =
+
+#---------------------------------------------------------------------------
+# 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::addtions 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 superceded 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 = YES
+
+# 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 similiar 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::addtions 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
+
+# The CGI_NAME tag should be the name of the CGI script that
+# starts the search engine (doxysearch) with the correct parameters.
+# A script with this name will be generated by doxygen.
+
+CGI_NAME = search.cgi
+
+# The CGI_URL tag should be the absolute URL to the directory where the
+# cgi binaries are located. See the documentation of your http daemon for
+# details.
+
+CGI_URL =
+
+# The DOC_URL tag should be the absolute URL to the directory where the
+# documentation is located. If left blank the absolute path to the
+# documentation, with file:// prepended to it, will be used.
+
+DOC_URL =
+
+# The DOC_ABSPATH tag should be the absolute path to the directory where the
+# documentation is located. If left blank the directory on the local machine
+# will be used.
+
+DOC_ABSPATH =
+
+# The BIN_ABSPATH tag must point to the directory where the doxysearch binary
+# is installed.
+
+BIN_ABSPATH = /usr/local/bin/
+
+# The EXT_DOC_PATHS tag can be used to specify one or more paths to
+# documentation generated for other projects. This allows doxysearch to search
+# the documentation for these projects as well.
+
+EXT_DOC_PATHS =
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 000000000..8ecb95578
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,25 @@
+Copyright (c) 2000-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.
diff --git a/arch/alpha/alpha_memory.cc b/arch/alpha/alpha_memory.cc
new file mode 100644
index 000000000..34c8e7f7d
--- /dev/null
+++ b/arch/alpha/alpha_memory.cc
@@ -0,0 +1,661 @@
+/*
+ * 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.
+ */
+
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "alpha_memory.hh"
+#include "ev5.hh"
+#include "exec_context.hh"
+#include "trace.hh"
+#include "inifile.hh"
+#include "str.hh"
+
+using namespace std;
+
+///////////////////////////////////////////////////////////////////////
+//
+// Alpha TLB
+//
+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
+{
+ DPRINTF(TLB, "lookup %#x\n", vpn);
+
+ PageTable::const_iterator i = lookupTable.find(vpn);
+ if (i == lookupTable.end())
+ return NULL;
+
+ 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))
+ return pte;
+
+ ++i;
+ }
+
+ // not found...
+ return NULL;
+}
+
+
+void
+AlphaTlb::checkCacheability(MemReqPtr req)
+{
+ // in Alpha, cacheability is controlled by upper-level bits of the
+ // physical address
+ if (req->paddr & PA_UNCACHED_BIT) {
+ if (PA_IPR_SPACE(req->paddr)) {
+ // IPR memory space not implemented
+ if (!req->xc->misspeculating())
+ panic("IPR memory space not implemented! PA=%x\n", req->paddr);
+ } else {
+ // mark request as uncacheable
+ req->flags |= UNCACHEABLE;
+ }
+ }
+}
+
+
+// insert a new TLB entry
+void
+AlphaTlb::insert(Addr vaddr, AlphaISA::PTE &pte)
+{
+ 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);
+ }
+
+ Addr vpn = VA_VPN(vaddr);
+ DPRINTF(TLB, "insert @%d: %#x -> %#x\n", nlu, vpn, pte.ppn);
+
+ table[nlu] = pte;
+ table[nlu].tag = vpn;
+ table[nlu].valid = true;
+
+ lookupTable.insert(make_pair(vpn, nlu));
+ nextnlu();
+}
+
+void
+AlphaTlb::flushAll()
+{
+ 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);
+
+ if (!pte->asma) {
+ DPRINTF(TLB, "flush @%d: %#x -> %#x\n", index, pte->tag, pte->ppn);
+ pte->valid = false;
+ lookupTable.erase(i);
+ }
+
+ ++i;
+ }
+}
+
+void
+AlphaTlb::flushAddr(Addr vaddr, uint8_t asn)
+{
+ Addr vpn = VA_VPN(vaddr);
+
+ PageTable::iterator i = lookupTable.find(vpn);
+ if (i == lookupTable.end())
+ return;
+
+ 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)) {
+ DPRINTF(TLB, "flushaddr @%d: %#x -> %#x\n", index, vpn, pte->ppn);
+
+ // invalidate this entry
+ pte->valid = false;
+
+ lookupTable.erase(i);
+ }
+
+ ++i;
+ }
+}
+
+
+void
+AlphaTlb::serialize()
+{
+ nameOut();
+
+ paramOut("size", size);
+ paramOut("nlu", nlu);
+
+ stringstream buf;
+ for (int i = 0; i < size; i++) {
+ buf.str("");
+ ccprintf(buf, "pte%02d.valid", i);
+ paramOut(buf.str(), table[i].valid);
+
+ buf.str("");
+ ccprintf(buf, "pte%02d.tag", i);
+ paramOut(buf.str(), table[i].tag);
+
+ buf.str("");
+ ccprintf(buf, "pte%02d.ppn", i);
+ paramOut(buf.str(), table[i].ppn);
+
+ buf.str("");
+ ccprintf(buf, "pte%02d.xre", i);
+ paramOut(buf.str(), table[i].xre);
+
+ buf.str("");
+ ccprintf(buf, "pte%02d.xwe", i);
+ paramOut(buf.str(), table[i].xwe);
+
+ buf.str("");
+ ccprintf(buf, "pte%02d.fonr", i);
+ paramOut(buf.str(), table[i].fonr);
+
+ buf.str("");
+ ccprintf(buf, "pte%02d.fonw", i);
+ paramOut(buf.str(), table[i].fonw);
+
+ buf.str("");
+ ccprintf(buf, "pte%02d.asma", i);
+ paramOut(buf.str(), table[i].asma);
+
+ buf.str("");
+ ccprintf(buf, "pte%02d.asn", i);
+ paramOut(buf.str(), table[i].asn);
+ }
+}
+
+void
+AlphaTlb::unserialize(IniFile &db, const string &category, ConfigNode *node)
+{
+ string data;
+ stringstream buf;
+
+ db.findDefault(category,"size",data);
+ to_number(data,size);
+ db.findDefault(category,"nlu",data);
+ to_number(data,nlu);
+
+ for (int i = 0; i < size; i++) {
+ buf.str("");
+ ccprintf(buf, "pte%02d.valid", i);
+ db.findDefault(category, buf.str(), data);
+ to_number(data, table[i].valid);
+
+ buf.str("");
+ ccprintf(buf, "pte%02d.tag", i);
+ db.findDefault(category, buf.str(), data);
+ to_number(data, table[i].tag);
+
+ buf.str("");
+ ccprintf(buf, "pte%02d.ppn", i);
+ db.findDefault(category, buf.str(), data);
+ to_number(data, table[i].ppn);
+
+ buf.str("");
+ ccprintf(buf, "pte%02d.xre", i);
+ db.findDefault(category, buf.str(), data);
+ to_number(data, table[i].xre);
+
+ buf.str("");
+ ccprintf(buf, "pte%02d.xwe", i);
+ db.findDefault(category, buf.str(), data);
+ to_number(data, table[i].xwe);
+
+ buf.str("");
+ ccprintf(buf, "pte%02d.fonr", i);
+ db.findDefault(category, buf.str(), data);
+ to_number(data, table[i].fonr);
+
+ buf.str("");
+ ccprintf(buf, "pte%02d.fonw", i);
+ db.findDefault(category, buf.str(), data);
+ to_number(data, table[i].fonw);
+
+ buf.str("");
+ ccprintf(buf, "pte%02d.asma", i);
+ db.findDefault(category, buf.str(), data);
+ to_number(data, table[i].asma);
+
+ buf.str("");
+ ccprintf(buf, "pte%02d.asn", i);
+ db.findDefault(category, buf.str(), data);
+ to_number(data, table[i].asn);
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////
+//
+// 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;
+}
+
+void
+AlphaItb::fault(Addr pc, ExecContext *xc) const
+{
+ uint64_t *ipr = xc->regs.ipr;
+
+ if (!xc->misspeculating()) {
+ ipr[AlphaISA::IPR_ITB_TAG] = pc;
+ ipr[AlphaISA::IPR_IFAULT_VA_FORM] =
+ ipr[AlphaISA::IPR_IVPTBR] | (VA_VPN(pc) << 3);
+ }
+}
+
+
+Fault
+AlphaItb::translate(MemReqPtr req) const
+{
+ InternalProcReg *ipr = req->xc->regs.ipr;
+
+ if (PC_PAL(req->vaddr)) {
+ // strip off PAL PC marker (lsb is 1)
+ req->paddr = (req->vaddr & ~3) & PA_IMPL_MASK;
+ hits++;
+ return No_Fault;
+ }
+
+ // verify that this is a good virtual address
+ if (!validVirtualAddress(req->vaddr)) {
+ fault(req->vaddr, req->xc);
+ acv++;
+ return Itb_Acv_Fault;
+ }
+
+ // Check for "superpage" mapping: when SP<1> is set, and
+ // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13>.
+ if ((MCSR_SP(ipr[AlphaISA::IPR_MCSR]) & 2) &&
+ VA_SPACE(req->vaddr) == 2) {
+ // only valid in kernel mode
+ if (ICM_CM(ipr[AlphaISA::IPR_ICM]) != AlphaISA::mode_kernel) {
+ fault(req->vaddr, req->xc);
+ acv++;
+ return Itb_Acv_Fault;
+ }
+
+ req->flags |= PHYSICAL;
+ }
+
+ if (req->flags & PHYSICAL) {
+ req->paddr = req->vaddr & PA_IMPL_MASK;
+ } else {
+ // not a physical address: need to look up pte
+
+ AlphaISA::PTE *pte = lookup(VA_VPN(req->vaddr),
+ DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN]));
+
+ if (!pte) {
+ fault(req->vaddr, req->xc);
+ misses++;
+ return Itb_Fault_Fault;
+ }
+
+ req->paddr = PA_PFN2PA(pte->ppn) + VA_POFS(req->vaddr & ~3);
+
+ // check permissions for this access
+ if (!(pte->xre & (1 << ICM_CM(ipr[AlphaISA::IPR_ICM])))) {
+ // instruction access fault
+ fault(req->vaddr, req->xc);
+ acv++;
+ return Itb_Acv_Fault;
+ }
+ }
+
+ checkCacheability(req);
+
+ hits++;
+ return No_Fault;
+}
+
+///////////////////////////////////////////////////////////////////////
+//
+// 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;
+}
+
+void
+AlphaDtb::fault(Addr vaddr, uint64_t flags, ExecContext *xc) const
+{
+ uint64_t *ipr = xc->regs.ipr;
+
+ // set fault address and flags
+ if (!xc->misspeculating() && !xc->regs.intrlock) {
+ // set VA register with faulting address
+ ipr[AlphaISA::IPR_VA] = vaddr;
+
+ // set MM_STAT register flags
+ ipr[AlphaISA::IPR_MM_STAT] = (((xc->regs.opcode & 0x3f) << 11)
+ | ((xc->regs.ra & 0x1f) << 6)
+ | (flags & 0x3f));
+
+ // set VA_FORM register with faulting formatted address
+ ipr[AlphaISA::IPR_VA_FORM] =
+ ipr[AlphaISA::IPR_MVPTBR] | (VA_VPN(vaddr) << 3);
+
+ // lock these registers until the VA register is read
+ xc->regs.intrlock = true;
+ }
+}
+
+Fault
+AlphaDtb::translate(MemReqPtr req, bool write) const
+{
+ RegFile *regs = &req->xc->regs;
+ Addr pc = regs->pc;
+ InternalProcReg *ipr = regs->ipr;
+
+ if (write)
+ write_accesses++;
+ else
+ read_accesses++;
+
+ AlphaISA::md_mode_type mode =
+ (AlphaISA::md_mode_type)DTB_CM_CM(ipr[AlphaISA::IPR_DTB_CM]);
+
+ if (PC_PAL(pc)) {
+ mode = (req->flags & ALTMODE) ? (AlphaISA::md_mode_type)
+ (ALT_MODE_AM(ipr[AlphaISA::IPR_ALT_MODE]))
+ : AlphaISA::mode_kernel;
+ }
+
+ // verify that this is a good virtual address
+ if (!validVirtualAddress(req->vaddr)) {
+ fault(req->vaddr,
+ ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_BAD_VA_MASK |
+ MM_STAT_ACV_MASK),
+ req->xc);
+
+ if (write) { write_acv++; } else { read_acv++; }
+ return Dtb_Fault_Fault;
+ }
+
+ // Check for "superpage" mapping: when SP<1> is set, and
+ // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13>.
+ if ((MCSR_SP(ipr[AlphaISA::IPR_MCSR]) & 2) && VA_SPACE(req->vaddr) == 2) {
+ // only valid in kernel mode
+ if (DTB_CM_CM(ipr[AlphaISA::IPR_DTB_CM]) != AlphaISA::mode_kernel) {
+ fault(req->vaddr,
+ ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_ACV_MASK),
+ req->xc);
+ if (write) { write_acv++; } else { read_acv++; }
+ return Dtb_Acv_Fault;
+ }
+
+ req->flags |= PHYSICAL;
+ }
+
+ if (req->flags & PHYSICAL) {
+ req->paddr = req->vaddr & PA_IMPL_MASK;
+ } else {
+ // not a physical address: need to look up pte
+
+ AlphaISA::PTE *pte = lookup(VA_VPN(req->vaddr),
+ DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN]));
+
+ if (!pte) {
+ // page fault
+ fault(req->vaddr,
+ ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_DTB_MISS_MASK),
+ req->xc);
+ if (write) { write_misses++; } else { read_misses++; }
+ return (req->flags & VPTE) ? Pdtb_Miss_Fault : Ndtb_Miss_Fault;
+ }
+
+ req->paddr = PA_PFN2PA(pte->ppn) | VA_POFS(req->vaddr);
+
+ if (write) {
+ if (!(pte->xwe & MODE2MASK(mode))) {
+ // declare the instruction access fault
+ fault(req->vaddr, MM_STAT_WR_MASK | MM_STAT_ACV_MASK |
+ (pte->fonw ? MM_STAT_FONW_MASK : 0),
+ req->xc);
+ write_acv++;
+ return Dtb_Fault_Fault;
+ }
+ if (pte->fonw) {
+ fault(req->vaddr, MM_STAT_WR_MASK | MM_STAT_FONW_MASK,
+ req->xc);
+ write_acv++;
+ return Dtb_Fault_Fault;
+ }
+ } else {
+ if (!(pte->xre & MODE2MASK(mode))) {
+ fault(req->vaddr,
+ MM_STAT_ACV_MASK | (pte->fonr ? MM_STAT_FONR_MASK : 0),
+ req->xc);
+ read_acv++;
+ return Dtb_Acv_Fault;
+ }
+ if (pte->fonr) {
+ fault(req->vaddr, MM_STAT_FONR_MASK, req->xc);
+ read_acv++;
+ return Dtb_Fault_Fault;
+ }
+ }
+ }
+
+ checkCacheability(req);
+
+ if (write)
+ write_hits++;
+ else
+ read_hits++;
+
+ return No_Fault;
+}
+
+AlphaISA::PTE &
+AlphaTlb::index()
+{
+ AlphaISA::PTE *pte = &table[nlu];
+ nextnlu();
+
+ return *pte;
+}
+
+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/arch/alpha/alpha_memory.hh b/arch/alpha/alpha_memory.hh
new file mode 100644
index 000000000..06fea32e4
--- /dev/null
+++ b/arch/alpha/alpha_memory.hh
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+
+#ifndef __ALPHA_MEMORY_HH__
+#define __ALPHA_MEMORY_HH__
+
+#include <map>
+
+#include "mem_req.hh"
+#include "sim_object.hh"
+#include "statistics.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();
+ 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 & VA_UNIMPL_MASK;
+ return (unimplBits == 0) || (unimplBits == VA_UNIMPL_MASK);
+ }
+
+ static void checkCacheability(MemReqPtr req);
+
+ // Checkpointing
+ virtual void serialize();
+ virtual void unserialize(IniFile &db, const std::string &category,
+ ConfigNode *node);
+
+};
+
+class AlphaItb : public AlphaTlb
+{
+ protected:
+ mutable Statistics::Scalar<> hits;
+ mutable Statistics::Scalar<> misses;
+ mutable Statistics::Scalar<> acv;
+ mutable Statistics::Formula accesses;
+
+ protected:
+ void fault(Addr pc, ExecContext *xc) const;
+
+ public:
+ AlphaItb(const std::string &name, int size);
+ virtual void regStats();
+
+ Fault translate(MemReqPtr req) const;
+};
+
+class AlphaDtb : public AlphaTlb
+{
+ protected:
+ mutable Statistics::Scalar<> read_hits;
+ mutable Statistics::Scalar<> read_misses;
+ mutable Statistics::Scalar<> read_acv;
+ mutable Statistics::Scalar<> read_accesses;
+ mutable Statistics::Scalar<> write_hits;
+ mutable Statistics::Scalar<> write_misses;
+ mutable Statistics::Scalar<> write_acv;
+ mutable Statistics::Scalar<> write_accesses;
+ Statistics::Formula hits;
+ Statistics::Formula misses;
+ Statistics::Formula acv;
+ Statistics::Formula accesses;
+
+ protected:
+ void fault(Addr pc, uint64_t flags, ExecContext *xc) const;
+
+ public:
+ AlphaDtb(const std::string &name, int size);
+ virtual void regStats();
+
+ Fault translate(MemReqPtr req, bool write) const;
+};
+
+#endif // __ALPHA_MEMORY_HH__
diff --git a/arch/alpha/arguments.cc b/arch/alpha/arguments.cc
new file mode 100644
index 000000000..91e0576f5
--- /dev/null
+++ b/arch/alpha/arguments.cc
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+#include "arguments.hh"
+#include "exec_context.hh"
+#include "physical_memory.hh"
+#include "vtophys.hh"
+
+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->regs.floatRegFile.q[16 + number];
+ else
+ return xc->regs.intRegFile[16 + number];
+ } else {
+ Addr sp = xc->regs.intRegFile[30];
+ Addr paddr = vtophys(xc, sp + (number-6) * sizeof(uint64_t));
+ return xc->physmem->phys_read_qword(paddr);
+ }
+}
+
diff --git a/arch/alpha/arguments.hh b/arch/alpha/arguments.hh
new file mode 100644
index 000000000..c5fdb60ad
--- /dev/null
+++ b/arch/alpha/arguments.hh
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ */
+
+#ifndef __ARGUMENTS_HH__
+#define __ARGUMENTS_HH__
+
+#include <assert.h>
+
+#include "host.hh"
+#include "kernel.hh"
+#include "refcnt.hh"
+
+class ExecContext;
+
+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));
+ Kernel::CopyData(xc, buf, getArg(), sizeof(T));
+ return buf;
+ }
+
+ operator char *() {
+ char *buf = data->alloc(2048);
+ Kernel::CopyString(xc, buf, getArg(), 2048);
+ return buf;
+ }
+};
+
+#endif // __ARGUMENTS_HH__
diff --git a/arch/alpha/ev5.cc b/arch/alpha/ev5.cc
new file mode 100644
index 000000000..c1631872a
--- /dev/null
+++ b/arch/alpha/ev5.cc
@@ -0,0 +1,571 @@
+/* $Id$ */
+
+#include "alpha_memory.hh"
+#include "annotation.hh"
+#ifdef DEBUG
+#include "debug.hh"
+#endif
+#include "exec_context.hh"
+#include "sim_events.hh"
+#include "isa_traits.hh"
+#include "remote_gdb.hh"
+#include "kgdb.h" // for ALPHA_KENTRY_IF
+#include "osfpal.hh"
+
+#ifdef FULL_SYSTEM
+
+#ifndef SYSTEM_EV5
+#error This code is only valid for EV5 systems
+#endif
+
+////////////////////////////////////////////////////////////////////////
+//
+//
+//
+void
+AlphaISA::swap_palshadow(RegFile *regs, bool use_shadow)
+{
+ if (regs->pal_shadow == use_shadow)
+ panic("swap_palshadow: wrong PAL shadow state");
+
+ regs->pal_shadow = use_shadow;
+
+ for (int i = 0; i < NumIntRegs; i++) {
+ if (reg_redir[i]) {
+ IntReg temp = regs->intRegFile[i];
+ regs->intRegFile[i] = regs->palregs[i];
+ regs->palregs[i] = temp;
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// Machine dependent functions
+//
+void
+AlphaISA::init(void *mem, RegFile *regs)
+{
+ ipr_init(mem, regs);
+}
+
+void
+m5_exit()
+{
+ static SimExitEvent event("m5_exit instruction encountered");
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// alpha exceptions - value equals trap address, update with MD_FAULT_TYPE
+//
+Addr
+AlphaISA::fault_addr[Num_Faults] = {
+ 0x0000, /* No_Fault */
+ 0x0001, /* Reset_Fault */
+ 0x0401, /* Machine_Check_Fault */
+ 0x0501, /* Arithmetic_Fault */
+ 0x0101, /* Interrupt_Fault */
+ 0x0201, /* Ndtb_Miss_Fault */
+ 0x0281, /* Pdtb_Miss_Fault */
+ 0x0301, /* Alignment_Fault */
+ 0x0381, /* Dtb_Fault_Fault */
+ 0x0381, /* Dtb_Acv_Fault */
+ 0x0181, /* Itb_Miss_Fault */
+ 0x0181, /* Itb_Fault_Fault */
+ 0x0081, /* Itb_Acv_Fault */
+ 0x0481, /* Unimplemented_Opcode_Fault */
+ 0x0581, /* Fen_Fault */
+ 0x2001, /* Pal_Fault */
+ 0x0501, /* Integer_Overflow_Fault: maps to Arithmetic_Fault */
+};
+
+const int AlphaISA::reg_redir[AlphaISA::NumIntRegs] = {
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 1, 1, 1, 1, 1, 1, 1, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 1, 0, 0, 0, 0, 0, 0 };
+
+////////////////////////////////////////////////////////////////////////
+//
+//
+//
+void
+AlphaISA::ipr_init(void *mem, RegFile *regs)
+{
+ uint64_t *ipr = regs->ipr;
+
+ bzero((char *)ipr, NumInternalProcRegs * sizeof(InternalProcReg));
+ ipr[IPR_PAL_BASE] = PAL_BASE;
+}
+
+
+void
+ExecContext::ev5_trap(Fault fault)
+{
+ assert(!misspeculating());
+ kernelStats.fault(fault);
+
+ if (fault == Arithmetic_Fault)
+ panic("Arithmetic traps are unimplemented!");
+
+ AlphaISA::InternalProcReg *ipr = regs.ipr;
+
+ // exception restart address
+ if (fault != Interrupt_Fault || !PC_PAL(regs.pc))
+ ipr[AlphaISA::IPR_EXC_ADDR] = regs.pc;
+
+ if (fault == Pal_Fault || fault == Arithmetic_Fault /* ||
+ fault == Interrupt_Fault && !PC_PAL(regs.pc) */) {
+ // traps... skip faulting instruction
+ ipr[AlphaISA::IPR_EXC_ADDR] += 4;
+ }
+
+ if (!PC_PAL(regs.pc))
+ AlphaISA::swap_palshadow(&regs, true);
+
+ regs.pc = ipr[AlphaISA::IPR_PAL_BASE] + AlphaISA::fault_addr[fault];
+ regs.npc = regs.pc + sizeof(MachInst);
+
+ Annotate::Ev5Trap(this, fault);
+}
+
+
+void
+AlphaISA::intr_post(RegFile *regs, Fault fault, Addr pc)
+{
+ InternalProcReg *ipr = regs->ipr;
+ bool use_pc = (fault == No_Fault);
+
+ if (fault == Arithmetic_Fault)
+ panic("arithmetic faults NYI...");
+
+ // compute exception restart address
+ if (use_pc || fault == Pal_Fault || fault == Arithmetic_Fault) {
+ // traps... skip faulting instruction
+ ipr[IPR_EXC_ADDR] = regs->pc + 4;
+ } else {
+ // fault, post fault at excepting instruction
+ ipr[IPR_EXC_ADDR] = regs->pc;
+ }
+
+ // jump to expection address (PAL PC bit set here as well...)
+ if (!use_pc)
+ regs->npc = ipr[IPR_PAL_BASE] + fault_addr[fault];
+ else
+ regs->npc = ipr[IPR_PAL_BASE] + pc;
+
+ // that's it! (orders of magnitude less painful than x86)
+}
+
+bool AlphaISA::check_interrupts = false;
+
+Fault
+ExecContext::hwrei()
+{
+ uint64_t *ipr = regs.ipr;
+
+ if (!PC_PAL(regs.pc))
+ return Unimplemented_Opcode_Fault;
+
+ kernelStats.hwrei();
+
+ regs.npc = ipr[AlphaISA::IPR_EXC_ADDR];
+
+ if (!misspeculating()) {
+ if ((ipr[AlphaISA::IPR_EXC_ADDR] & 1) == 0)
+ AlphaISA::swap_palshadow(&regs, false);
+
+ AlphaISA::check_interrupts = true;
+ }
+
+ // FIXME: XXX check for interrupts? XXX
+ return No_Fault;
+}
+
+uint64_t
+ExecContext::readIpr(int idx, Fault &fault)
+{
+ uint64_t *ipr = regs.ipr;
+ 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_VA:
+ // SFX: unlocks interrupt status registers
+ retval = ipr[idx];
+ regs.intrlock = false;
+ 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 = dtb->index();
+
+ 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 = Unimplemented_Opcode_Fault;
+ break;
+
+ default:
+ // invalid IPR
+ fault = Unimplemented_Opcode_Fault;
+ break;
+ }
+
+ return retval;
+}
+
+#ifdef DEBUG
+// Cause the simulator to break when changing to the following IPL
+int break_ipl = -1;
+#endif
+
+Fault
+ExecContext::setIpr(int idx, uint64_t val)
+{
+ uint64_t *ipr = regs.ipr;
+
+ if (misspeculating())
+ return No_Fault;
+
+ 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_CC_CTL:
+ case AlphaISA::IPR_CC:
+ case AlphaISA::IPR_PMCTR:
+ // write entire quad w/ no side-effect
+ ipr[idx] = val;
+ break;
+
+ case AlphaISA::IPR_PALtemp23:
+ // write entire quad w/ no side-effect
+ ipr[idx] = val;
+ kernelStats.context(ipr[idx]);
+ Annotate::Context(this);
+ 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;
+ kernelStats.swpipl(ipr[idx]);
+ Annotate::IPL(this, val & 0x1f);
+ break;
+
+ case AlphaISA::IPR_DTB_CM:
+ Annotate::ChangeMode(this, (val & 0x18) != 0);
+ kernelStats.mode((val & 0x18) != 0);
+
+ 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 Unimplemented_Opcode_Fault;
+
+ 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;
+
+ dtb->flushAll();
+ break;
+
+ case AlphaISA::IPR_DTB_IAP:
+ // really a control write
+ ipr[idx] = 0;
+
+ dtb->flushProcesses();
+ break;
+
+ case AlphaISA::IPR_DTB_IS:
+ // really a control write
+ ipr[idx] = val;
+
+ dtb->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
+ dtb->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
+ itb->insert(ipr[AlphaISA::IPR_ITB_TAG], pte);
+ }
+ break;
+
+ case AlphaISA::IPR_ITB_IA:
+ // really a control write
+ ipr[idx] = 0;
+
+ itb->flushAll();
+ break;
+
+ case AlphaISA::IPR_ITB_IAP:
+ // really a control write
+ ipr[idx] = 0;
+
+ itb->flushProcesses();
+ break;
+
+ case AlphaISA::IPR_ITB_IS:
+ // really a control write
+ ipr[idx] = val;
+
+ itb->flushAddr(val, ITB_ASN_ASN(ipr[AlphaISA::IPR_ITB_ASN]));
+ break;
+
+ default:
+ // invalid IPR
+ return Unimplemented_Opcode_Fault;
+ }
+
+ // no error...
+ return No_Fault;
+}
+
+/**
+ * Check for special simulator handling of specific PAL calls.
+ * If return value is false, actual PAL call will be suppressed.
+ */
+bool
+ExecContext::simPalCheck(int palFunc)
+{
+ kernelStats.callpal(palFunc);
+
+ switch (palFunc) {
+ case PAL::halt:
+ if (!misspeculating()) {
+ setStatus(Halted);
+ if (--System::numSystemsRunning == 0)
+ new SimExitEvent("all cpus halted");
+ }
+ break;
+
+ case PAL::bpt:
+ case PAL::bugchk:
+ if (system->remoteGDB->trap(ALPHA_KENTRY_IF))
+ return false;
+ break;
+ }
+
+ return true;
+}
+
+#endif // FULL_SYSTEM
diff --git a/arch/alpha/ev5.hh b/arch/alpha/ev5.hh
new file mode 100644
index 000000000..c3330bc01
--- /dev/null
+++ b/arch/alpha/ev5.hh
@@ -0,0 +1,104 @@
+/* $Id$ */
+
+#ifndef __EV5_H__
+#define __EV5_H__
+
+#ifndef SYSTEM_EV5
+#error This code is only valid for EV5 systems
+#endif
+
+#include "isa_traits.hh"
+
+void m5_exit();
+
+////////////////////////////////////////////////////////////////////////
+//
+//
+//
+
+////////////////////////////////////////////////////////////////////////
+//
+//
+//
+
+#define MODE2MASK(X) (1 << (X))
+
+// Alpha IPR register accessors
+#define PC_PAL(X) ((X) & 0x1)
+#define MCSR_SP(X) (((X) >> 1) & 0x3)
+
+#define ICSR_SDE(X) (((X) >> 30) & 0x1)
+#define ICSR_SPE(X) (((X) >> 28) & 0x3)
+#define ICSR_FPE(X) (((X) >> 26) & 0x1)
+
+#define ALT_MODE_AM(X) (((X) >> 3) & 0x3)
+
+#define DTB_CM_CM(X) (((X) >> 3) & 0x3)
+#define DTB_ASN_ASN(X) (((X) >> 57) & 0x7f)
+#define DTB_PTE_PPN(X) (((X) >> 32) & 0x07ffffff)
+#define DTB_PTE_XRE(X) (((X) >> 8) & 0xf)
+#define DTB_PTE_XWE(X) (((X) >> 12) & 0xf)
+#define DTB_PTE_FONR(X) (((X) >> 1) & 0x1)
+#define DTB_PTE_FONW(X) (((X) >> 2) & 0x1)
+#define DTB_PTE_GH(X) (((X) >> 5) & 0x3)
+#define DTB_PTE_ASMA(X) (((X) >> 4) & 0x1)
+
+#define ICM_CM(X) (((X) >> 3) & 0x3)
+#define ITB_ASN_ASN(X) (((X) >> 4) & 0x7f)
+#define ITB_PTE_PPN(X) (((X) >> 32) & 0x07ffffff)
+#define ITB_PTE_XRE(X) (((X) >> 8) & 0xf)
+#define ITB_PTE_FONR(X) (((X) >> 1) & 0x1)
+#define ITB_PTE_FONW(X) (((X) >> 2) & 0x1)
+#define ITB_PTE_GH(X) (((X) >> 5) & 0x3)
+#define ITB_PTE_ASMA(X) (((X) >> 4) & 0x1)
+
+#define VA_UNIMPL_MASK ULL(0xfffff80000000000)
+#define VA_IMPL_MASK ULL(0x000007ffffffffff)
+#define VA_IMPL(X) ((X) & VA_IMPL_MASK)
+#define VA_VPN(X) (VA_IMPL(X) >> 13)
+#define VA_SPACE(X) (((X) >> 41) & 0x3)
+#define VA_POFS(X) ((X) & 0x1fff)
+
+#define PA_IMPL_MASK ULL(0xffffffffff)
+#define PA_UNCACHED_BIT ULL(0x8000000000)
+#define PA_IPR_SPACE(X) ((X) >= ULL(0xFFFFF00000))
+
+#define PA_PFN2PA(X) ((X) << 13)
+
+
+#define MM_STAT_BAD_VA_MASK 0x0020
+#define MM_STAT_DTB_MISS_MASK 0x0010
+#define MM_STAT_FONW_MASK 0x0008
+#define MM_STAT_FONR_MASK 0x0004
+#define MM_STAT_ACV_MASK 0x0002
+#define MM_STAT_WR_MASK 0x0001
+
+
+////////////////////////////////////////////////////////////////////////
+//
+//
+//
+
+// VPTE size for HW_LD/HW_ST
+#define HW_VPTE ((inst >> 11) & 0x1)
+
+// QWORD size for HW_LD/HW_ST
+#define HW_QWORD ((inst >> 12) & 0x1)
+
+// ALT mode for HW_LD/HW_ST
+#define HW_ALT (((inst >> 14) & 0x1) ? ALTMODE : 0)
+
+// LOCK/COND mode for HW_LD/HW_ST
+#define HW_LOCK (((inst >> 10) & 0x1) ? LOCKED : 0)
+#define HW_COND (((inst >> 10) & 0x1) ? LOCKED : 0)
+
+// PHY size for HW_LD/HW_ST
+#define HW_PHY (((inst >> 15) & 0x1) ? PHYSICAL : 0)
+
+// OFFSET for HW_LD/HW_ST
+#define HW_OFS (inst & 0x3ff)
+
+
+#define PAL_BASE 0x4000
+
+#endif //__EV5_H__
diff --git a/arch/alpha/fake_syscall.cc b/arch/alpha/fake_syscall.cc
new file mode 100644
index 000000000..ad3c86515
--- /dev/null
+++ b/arch/alpha/fake_syscall.cc
@@ -0,0 +1,1736 @@
+/*
+ * 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.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h> // for memset()
+
+#include "host.hh"
+#include "base_cpu.hh"
+#include "functional_memory.hh"
+#include "prog.hh"
+#include "exec_context.hh"
+#include "fake_syscall.hh"
+#include "sim_events.hh"
+
+#include "osf_syscalls.h"
+#include "universe.hh" // for curTick & ticksPerSecond
+
+#include "trace.hh"
+
+using namespace std;
+
+//
+// System call descriptor
+//
+class SyscallDesc {
+
+ public:
+
+ typedef int (*FuncPtr)(SyscallDesc *, int num,
+ Process *, ExecContext *);
+
+ const char *name;
+ FuncPtr funcPtr;
+ int flags;
+
+ SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0)
+ : name(_name), funcPtr(_funcPtr), flags(_flags)
+ {}
+
+ int doFunc(int num, Process *proc, ExecContext *xc) {
+ return (*funcPtr)(this, num, proc, 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(FunctionalMemory *mem) {
+ mem->access(Read, addr, bufPtr, size);
+ return true; // no EFAULT detection for now
+ }
+
+ //
+ // copy data out of simulator space (write to target memory)
+ //
+ virtual bool copyOut(FunctionalMemory *mem) {
+ mem->access(Write, 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]; }
+};
+
+
+static IntReg
+getArg(ExecContext *xc, int i)
+{
+ return xc->regs.intRegFile[ArgumentReg0 + i];
+}
+
+
+//
+// used to shift args for indirect syscall
+//
+static void
+setArg(ExecContext *xc, int i, IntReg val)
+{
+ xc->regs.intRegFile[ArgumentReg0 + i] = val;
+}
+
+
+static void
+set_return_value(ExecContext *xc, IntReg 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
+ xc->regs.intRegFile[RegA3] = 0;
+ xc->regs.intRegFile[ReturnValueReg] = return_value;
+ } else {
+ // got an error, return details
+ xc->regs.intRegFile[RegA3] = (IntReg) -1;
+ xc->regs.intRegFile[ReturnValueReg] = -return_value;
+ }
+}
+
+
+int
+getpagesizeFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ return VMPageSize;
+}
+
+
+int
+obreakFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ // change brk addr to first arg
+ process->brk_point = getArg(xc, 0);
+ return process->brk_point;
+}
+
+
+int
+ioctlFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ int fd = process->sim_fd(getArg(xc, 0));
+ unsigned req = getArg(xc, 1);
+
+ switch (req) {
+ case OSF::TIOCGETP: {
+ // get tty parameters: the main use of this call is by
+ // isatty(), which really just wants to see whether it
+ // succeeds or returns ENOTTY to determine whether this is
+ // a terminal or not. This call is in turn used by the
+ // stdio library to determine whether to do line buffering
+ // or block buffering on a specific file descriptor.
+ TypedBufferArg<OSF::sgttyb> buf(getArg(xc, 2));
+
+ if (fd < 0) {
+ // bad file descriptor
+ return -EBADF;
+ } else if (0 <= fd < 3) {
+ // stdin/stdout/stderr: make it look like a terminal
+ // so we get line buffering & not block buffering
+ buf->sg_ispeed = 0xf;
+ buf->sg_ospeed = 0xf;
+ buf->sg_erase = 0x7f;
+ buf->sg_kill = 0x15;
+ buf->sg_flags = 0x18;
+ buf.copyOut(xc->mem);
+ return 0;
+ } else {
+ // any other file descriptor: assume it's a file or
+ // pipe and not a terminal
+ return -ENOTTY;
+ }
+ break;
+ }
+
+ case OSF::TIOCISATTY:
+ if (fd < 0) {
+ // bad file descriptor
+ return -EBADF;
+ } else if (0 <= fd < 3) {
+ // stdin/stdout/stderr: make it look like a terminal
+ // so we get line buffering & not block buffering
+ return 0;
+ } else {
+ // any other file descriptor: assume it's a file or
+ // pipe and not a terminal
+ return -ENOTTY;
+ }
+ break;
+
+ default:
+ cerr << "Unsupported ioctl call: ioctl("
+ << fd << ", " << req << ", ...)" << endl;
+ abort();
+ break;
+ }
+}
+
+
+int
+openFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ string path;
+
+ if (xc->mem->readString(path, getArg(xc, 0)) != No_Fault)
+ 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.
+ DCOUT(SyscallWarnings) << "Ignoring open(" << path << ", ...)" << endl;
+ return -ENOENT;
+ }
+
+ int osfFlags = getArg(xc, 1);
+ int mode = getArg(xc, 2);
+ int hostFlags = 0;
+
+ // translate open flags
+ for (int i = 0; i < OSF::NUM_OPEN_FLAGS; i++) {
+ if (osfFlags & OSF::openFlagTable[i].osfFlag) {
+ osfFlags &= ~OSF::openFlagTable[i].osfFlag;
+ hostFlags |= OSF::openFlagTable[i].hostFlag;
+ }
+ }
+
+ // any target flags left?
+ if (osfFlags != 0)
+ cerr << "Syscall: open: cannot decode flags: " << osfFlags << endl;
+
+#ifdef __CYGWIN32__
+ hostFlags |= O_BINARY;
+#endif
+
+ // open the file
+ int fd = open(path.c_str(), hostFlags, mode);
+
+ return (fd == -1) ? -errno : process->open_fd(fd);
+}
+
+
+int
+closeFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ int fd = process->sim_fd(getArg(xc, 0));
+ return close(fd);
+}
+
+
+int
+readFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ int fd = process->sim_fd(getArg(xc, 0));
+ int nbytes = getArg(xc, 2);
+ BufferArg bufArg(getArg(xc, 1), nbytes);
+
+ int bytes_read = read(fd, bufArg.bufferPtr(), nbytes);
+
+ if (bytes_read != -1)
+ bufArg.copyOut(xc->mem);
+
+ return bytes_read;
+}
+
+int
+writeFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ int fd = process->sim_fd(getArg(xc, 0));
+ int nbytes = getArg(xc, 2);
+ BufferArg bufArg(getArg(xc, 1), nbytes);
+
+ bufArg.copyIn(xc->mem);
+
+ int bytes_written = write(fd, bufArg.bufferPtr(), nbytes);
+
+ fsync(fd);
+
+ return bytes_written;
+}
+
+
+int
+lseekFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ int fd = process->sim_fd(getArg(xc, 0));
+ uint64_t offs = getArg(xc, 1);
+ int whence = getArg(xc, 2);
+
+ off_t result = lseek(fd, offs, whence);
+
+ return (result == (off_t)-1) ? -errno : result;
+}
+
+static
+void
+copyOutStatBuf(FunctionalMemory *mem, Addr addr, struct stat *host)
+{
+ TypedBufferArg<OSF::F64_stat> tgt(addr);
+
+ tgt->st_dev = host->st_dev;
+ tgt->st_ino = host->st_ino;
+ tgt->st_mode = host->st_mode;
+ tgt->st_nlink = host->st_nlink;
+ tgt->st_uid = host->st_uid;
+ tgt->st_gid = host->st_gid;
+ tgt->st_rdev = host->st_rdev;
+ tgt->st_size = host->st_size;
+ tgt->st_atimeX = host->st_atime;
+ tgt->st_mtimeX = host->st_mtime;
+ tgt->st_ctimeX = host->st_ctime;
+ tgt->st_blksize = host->st_blksize;
+ tgt->st_blocks = host->st_blocks;
+
+ tgt.copyOut(mem);
+}
+
+int
+statFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ string path;
+
+ if (xc->mem->readString(path, getArg(xc, 0)) != No_Fault)
+ return -EFAULT;
+
+ struct stat hostBuf;
+ int result = stat(path.c_str(), &hostBuf);
+
+ if (result < 0)
+ return -errno;
+
+ copyOutStatBuf(xc->mem, getArg(xc, 1), &hostBuf);
+
+ return 0;
+}
+
+
+int
+lstatFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ string path;
+
+ if (xc->mem->readString(path, getArg(xc, 0)) != No_Fault)
+ return -EFAULT;
+
+ struct stat hostBuf;
+ int result = lstat(path.c_str(), &hostBuf);
+
+ if (result < 0)
+ return -errno;
+
+ copyOutStatBuf(xc->mem, getArg(xc, 1), &hostBuf);
+
+ return 0;
+}
+
+int
+fstatFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ int fd = process->sim_fd(getArg(xc, 0));
+
+ if (fd < 0)
+ return -EBADF;
+
+ struct stat hostBuf;
+ int result = fstat(fd, &hostBuf);
+
+ if (result < 0)
+ return -errno;
+
+ copyOutStatBuf(xc->mem, getArg(xc, 1), &hostBuf);
+
+ return 0;
+}
+
+
+//
+// We don't handle mmap(). If the target is really mmaping /dev/zero,
+// we can get away with doing nothing (since 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 an mmap to anything else.
+//
+int
+mmapFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ Addr start = getArg(xc, 0);
+ uint64_t length = getArg(xc, 1);
+ int prot = getArg(xc, 2);
+ int flags = getArg(xc, 3);
+ int fd = process->sim_fd(getArg(xc, 4));
+ int offset = getArg(xc, 5);
+
+ cerr << "Warning: ignoring syscall mmap("
+ << start << ", " << length << ", "
+ << prot << ", " << flags << ", "
+ << fd << " " << getArg(xc, 4) << ", "
+ << offset << ")" << endl;
+
+ return start;
+}
+
+
+const char *hostname = "m5.eecs.umich.edu";
+
+int
+unameFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ TypedBufferArg<OSF::utsname> name(getArg(xc, 0));
+
+ strcpy(name->sysname, "OSF1");
+ strcpy(name->nodename, hostname);
+ strcpy(name->release, "V5.1");
+ strcpy(name->version, "732");
+ strcpy(name->machine, "alpha");
+
+ name.copyOut(xc->mem);
+ return 0;
+}
+
+
+int
+gethostnameFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ int name_len = getArg(xc, 1);
+ BufferArg name(getArg(xc, 0), name_len);
+
+ strncpy((char *)name.bufferPtr(), hostname, name_len);
+
+ name.copyOut(xc->mem);
+
+ return 0;
+}
+
+
+int
+getsysinfoFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ unsigned op = getArg(xc, 0);
+ unsigned nbytes = getArg(xc, 2);
+
+ switch (op) {
+
+ case OSF::GSI_MAX_CPU: {
+ TypedBufferArg<uint32_t> max_cpu(getArg(xc, 1));
+ *max_cpu = process->numCpus;
+ max_cpu.copyOut(xc->mem);
+ return 1;
+ }
+
+ case OSF::GSI_CPUS_IN_BOX: {
+ TypedBufferArg<uint32_t> cpus_in_box(getArg(xc, 1));
+ *cpus_in_box = process->numCpus;
+ cpus_in_box.copyOut(xc->mem);
+ return 1;
+ }
+
+ case OSF::GSI_PHYSMEM: {
+ TypedBufferArg<uint64_t> physmem(getArg(xc, 1));
+ *physmem = 1024 * 1024; // physical memory in KB
+ physmem.copyOut(xc->mem);
+ return 1;
+ }
+
+ case OSF::GSI_CPU_INFO: {
+ TypedBufferArg<OSF::cpu_info> infop(getArg(xc, 1));
+
+ infop->current_cpu = 0;
+ infop->cpus_in_box = process->numCpus;
+ infop->cpu_type = 57;
+ infop->ncpus = process->numCpus;
+ int cpumask = (1 << process->numCpus) - 1;
+ infop->cpus_present = infop->cpus_running = cpumask;
+ infop->cpu_binding = 0;
+ infop->cpu_ex_binding = 0;
+ infop->mhz = 667;
+
+ infop.copyOut(xc->mem);
+ return 1;
+ }
+
+ case OSF::GSI_PROC_TYPE: {
+ TypedBufferArg<uint64_t> proc_type(getArg(xc, 1));
+ *proc_type = 11;
+ proc_type.copyOut(xc->mem);
+ return 1;
+ }
+
+ case OSF::GSI_PLATFORM_NAME: {
+ BufferArg bufArg(getArg(xc, 1), nbytes);
+ strncpy((char *)bufArg.bufferPtr(),
+ "COMPAQ Professional Workstation XP1000",
+ nbytes);
+ bufArg.copyOut(xc->mem);
+ return 1;
+ }
+
+ case OSF::GSI_CLK_TCK: {
+ TypedBufferArg<uint64_t> clk_hz(getArg(xc, 1));
+ *clk_hz = 1024;
+ clk_hz.copyOut(xc->mem);
+ return 1;
+ }
+
+ default:
+ cerr << "getsysinfo: unknown op " << op << endl;
+ abort();
+ break;
+ }
+
+ return 0;
+}
+
+int
+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.
+ return 100;
+}
+
+int
+getuidFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ // Make up a UID.
+ return 100;
+}
+
+int
+getrlimitFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ unsigned resource = getArg(xc, 0);
+ TypedBufferArg<OSF::rlimit> rlp(getArg(xc, 1));
+
+ switch (resource) {
+ case OSF::RLIMIT_STACK:
+ // max stack size in bytes: make up a number (2MB for now)
+ rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
+ break;
+
+ default:
+ cerr << "getrlimitFunc: unimplemented resource " << resource << endl;
+ abort();
+ break;
+ }
+
+ rlp.copyOut(xc->mem);
+ return 0;
+}
+
+// 1M usecs in 1 sec, for readability
+static const int one_million = 1000000;
+
+// seconds since the epoch (1/1/1970)... about a billion, by my reckoning
+static const unsigned seconds_since_epoch = 1000000000;
+
+//
+// helper function: populate struct timeval with approximation of
+// current elapsed time
+//
+static void
+getElapsedTime(OSF::timeval *tp)
+{
+ int cycles_per_usec = ticksPerSecond / one_million;
+
+ int elapsed_usecs = curTick / cycles_per_usec;
+ tp->tv_sec = elapsed_usecs / one_million;
+ tp->tv_usec = elapsed_usecs % one_million;
+}
+
+
+int
+gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ TypedBufferArg<OSF::timeval> tp(getArg(xc, 0));
+
+ getElapsedTime(tp);
+ tp->tv_sec += seconds_since_epoch;
+
+ tp.copyOut(xc->mem);
+
+ return 0;
+}
+
+
+int
+getrusageFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ int who = getArg(xc, 0); // THREAD, SELF, or CHILDREN
+ TypedBufferArg<OSF::rusage> rup(getArg(xc, 1));
+
+ if (who != OSF::RUSAGE_SELF) {
+ // don't really handle THREAD or CHILDREN, but just warn and
+ // plow ahead
+ DCOUT(SyscallWarnings)
+ << "Warning: getrusage() only supports RUSAGE_SELF."
+ << " Parameter " << who << " ignored." << endl;
+ }
+
+ getElapsedTime(&rup->ru_utime);
+ 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->mem);
+
+ return 0;
+}
+
+
+int
+sigreturnFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ RegFile *regs = &xc->regs;
+ TypedBufferArg<OSF::sigcontext> sc(getArg(xc, 0));
+
+ sc.copyIn(xc->mem);
+
+ // restore state from sigcontext structure
+ regs->pc = sc->sc_pc;
+ regs->npc = regs->pc + sizeof(MachInst);
+
+ for (int i = 0; i < 31; ++i) {
+ regs->intRegFile[i] = sc->sc_regs[i];
+ regs->floatRegFile.q[i] = sc->sc_fpregs[i];
+ }
+
+ regs->miscRegs.fpcr = sc->sc_fpcr;
+
+ return 0;
+}
+
+int
+tableFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ int id = getArg(xc, 0); // table ID
+ int index = getArg(xc, 1); // index into table
+ // arg 2 is buffer pointer; type depends on table ID
+ int nel = getArg(xc, 3); // number of elements
+ int lel = getArg(xc, 4); // expected element size
+
+ switch (id) {
+ case OSF::TBL_SYSINFO: {
+ if (index != 0 || nel != 1 || lel != sizeof(OSF::tbl_sysinfo))
+ return -EINVAL;
+ TypedBufferArg<OSF::tbl_sysinfo> elp(getArg(xc, 2));
+
+ const int clk_hz = one_million;
+ elp->si_user = curTick / (ticksPerSecond / clk_hz);
+ elp->si_nice = 0;
+ elp->si_sys = 0;
+ elp->si_idle = 0;
+ elp->wait = 0;
+ elp->si_hz = clk_hz;
+ elp->si_phz = clk_hz;
+ elp->si_boottime = seconds_since_epoch; // seconds since epoch?
+ elp->si_max_procs = process->numCpus;
+ elp.copyOut(xc->mem);
+ return 0;
+ }
+
+ default:
+ cerr << "table(): id " << id << " unknown." << endl;
+ return -EINVAL;
+ }
+}
+
+//
+// forward declaration... defined below table
+//
+int
+indirectSyscallFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc);
+
+//
+// Handler for unimplemented syscalls that we haven't thought about.
+//
+int
+unimplementedFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ cerr << "Error: syscall " << desc->name
+ << " (#" << callnum << ") unimplemented.";
+ cerr << " Args: " << getArg(xc, 0) << ", " << getArg(xc, 1)
+ << ", ..." << endl;
+
+ abort();
+}
+
+
+//
+// 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.
+//
+int
+ignoreFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ DCOUT(SyscallWarnings) << "Warning: ignoring syscall " << desc->name
+ << "(" << getArg(xc, 0)
+ << ", " << getArg(xc, 1)
+ << ", ...)" << endl;
+
+ return 0;
+}
+
+
+int
+exitFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ new SimExitEvent("syscall caused exit", getArg(xc, 0) & 0xff);
+
+ return 1;
+}
+
+
+SyscallDesc syscallDescs[] = {
+ /* 0 */ SyscallDesc("syscall (#0)", indirectSyscallFunc),
+ /* 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", unimplementedFunc),
+ /* 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", getpidFunc),
+ /* 21 */ SyscallDesc("mount", unimplementedFunc),
+ /* 22 */ SyscallDesc("unmount", unimplementedFunc),
+ /* 23 */ SyscallDesc("setuid", unimplementedFunc),
+ /* 24 */ SyscallDesc("getuid", getuidFunc),
+ /* 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),
+ /* 46 */ SyscallDesc("obsolete osigaction", unimplementedFunc),
+ /* 47 */ SyscallDesc("getgid", unimplementedFunc),
+ /* 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),
+ /* 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", unimplementedFunc),
+ /* 68 */ SyscallDesc("pre_F64_lstat", unimplementedFunc),
+ /* 69 */ SyscallDesc("sbrk", unimplementedFunc),
+ /* 70 */ SyscallDesc("sstk", unimplementedFunc),
+ /* 71 */ SyscallDesc("mmap", mmapFunc),
+ /* 72 */ SyscallDesc("ovadvise", unimplementedFunc),
+ /* 73 */ SyscallDesc("munmap", unimplementedFunc),
+ /* 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", unimplementedFunc),
+ /* 92 */ SyscallDesc("fcntl", unimplementedFunc),
+ /* 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", sigreturnFunc),
+ /* 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),
+ /* 117 */ SyscallDesc("getrusage", getrusageFunc),
+ /* 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", unimplementedFunc),
+ /* 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("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),
+ /* 145 */ SyscallDesc("setrlimit", unimplementedFunc),
+ /* 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", unimplementedFunc),
+ /* 160 */ SyscallDesc("pre_F64_statfs", unimplementedFunc),
+ /* 161 */ SyscallDesc("pre_F64_fstatfs", unimplementedFunc),
+ /* 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),
+ /* 225 */ SyscallDesc("lstat", lstatFunc),
+ /* 226 */ SyscallDesc("fstat", fstatFunc),
+ /* 227 */ SyscallDesc("statfs", unimplementedFunc),
+ /* 228 */ SyscallDesc("fstatfs", unimplementedFunc),
+ /* 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", unimplementedFunc),
+ /* 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),
+};
+
+const int Num_Syscall_Descs = sizeof(syscallDescs) / sizeof(SyscallDesc);
+
+const int Max_Syscall_Desc = Num_Syscall_Descs - 1;
+
+//
+// Mach syscalls -- identified by negated syscall numbers
+//
+
+// Create a stack region for a thread.
+int
+stack_createFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ TypedBufferArg<OSF::vm_stack> argp(getArg(xc, 0));
+
+ argp.copyIn(xc->mem);
+
+ // if the user chose an address, just let them have it. Otherwise
+ // pick one for them.
+ if (argp->address == 0) {
+ argp->address = process->next_thread_stack_base;
+ int stack_size = (argp->rsize + argp->ysize + argp->gsize);
+ process->next_thread_stack_base -= stack_size;
+ argp.copyOut(xc->mem);
+ }
+
+ return 0;
+}
+
+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.
+//
+int
+nxm_task_initFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ TypedBufferArg<OSF::nxm_task_attr> attrp(getArg(xc, 0));
+ TypedBufferArg<Addr> configptr_ptr(getArg(xc, 1));
+
+ attrp.copyIn(xc->mem);
+
+ if (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 (attrp->flags != OSF::NXM_TASK_INIT_VP) {
+ cerr << "nxm_task_init: bad flag value " << attrp->flags
+ << " (expected " << OSF::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(OSF::nxm_config_info);
+ // next comes the per-cpu state vector
+ Addr slot_state_addr = cur_addr;
+ int slot_state_size = process->numCpus * sizeof(OSF::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(OSF::nxm_shared)
+ + (process->numCpus-1) * sizeof(OSF::nxm_sched_state));
+ cur_addr += rad_state_size;
+
+ // now initialize a config_info struct and copy it out to user space
+ TypedBufferArg<OSF::nxm_config_info> config(config_addr);
+
+ config->nxm_nslots_per_rad = process->numCpus;
+ config->nxm_nrads = 1; // only one RAD in our system!
+ config->nxm_slot_state = slot_state_addr;
+ config->nxm_rad[0] = rad_state_addr;
+
+ config.copyOut(xc->mem);
+
+ // initialize the slot_state array and copy it out
+ TypedBufferArg<OSF::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
+ slot_state[i] = (i == 0) ? OSF::NXM_SLOT_BOUND : OSF::NXM_SLOT_AVAIL;
+ }
+
+ slot_state.copyOut(xc->mem);
+
+ // 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<OSF::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) {
+ OSF::nxm_sched_state *ssp = &rad_state->nxm_ss[i];
+ ssp->nxm_u.sigmask = 0;
+ ssp->nxm_u.sig = 0;
+ ssp->nxm_u.flags = 0;
+ ssp->nxm_u.cancel_state = 0;
+ ssp->nxm_u.nxm_ssig = 0;
+ ssp->nxm_bits = 0;
+ ssp->nxm_quantum = attrp->nxm_quantum;
+ ssp->nxm_set_quantum = attrp->nxm_quantum;
+ ssp->nxm_sysevent = 0;
+
+ if (i == 0) {
+ uint64_t uniq = xc->regs.miscRegs.uniq;
+ ssp->nxm_u.pth_id = uniq + attrp->nxm_uniq_offset;
+ ssp->nxm_u.nxm_active = uniq | 1;
+ }
+ else {
+ ssp->nxm_u.pth_id = 0;
+ ssp->nxm_u.nxm_active = 0;
+ }
+ }
+
+ rad_state.copyOut(xc->mem);
+
+ //
+ // copy pointer to shared config area out to user
+ //
+ *configptr_ptr = config_addr;
+ configptr_ptr.copyOut(xc->mem);
+
+ return 0;
+}
+
+
+static void
+init_exec_context(ExecContext *ec,
+ OSF::nxm_thread_attr *attrp, uint64_t uniq_val)
+{
+ memset(&ec->regs, 0, sizeof(ec->regs));
+
+ ec->regs.intRegFile[ArgumentReg0] = attrp->registers.a0;
+ ec->regs.intRegFile[27/*t12*/] = attrp->registers.pc;
+ ec->regs.intRegFile[StackPointerReg] = attrp->registers.sp;
+ ec->regs.miscRegs.uniq = uniq_val;
+
+ ec->regs.pc = attrp->registers.pc;
+ ec->regs.npc = attrp->registers.pc + sizeof(MachInst);
+
+ ec->setStatus(ExecContext::Active);
+}
+
+int
+nxm_thread_createFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ TypedBufferArg<OSF::nxm_thread_attr> attrp(getArg(xc, 0));
+ TypedBufferArg<uint64_t> kidp(getArg(xc, 1));
+ int thread_index = getArg(xc, 2);
+
+ // get attribute args
+ attrp.copyIn(xc->mem);
+
+ if (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(OSF::nxm_shared) +
+ (process->numCpus-1) * sizeof(OSF::nxm_sched_state));
+
+ TypedBufferArg<OSF::nxm_shared> rad_state(0x14000,
+ rad_state_size);
+ rad_state.copyIn(xc->mem);
+
+ uint64_t uniq_val = attrp->pthid - rad_state->nxm_uniq_offset;
+
+ if (attrp->type == OSF::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 = 99;
+ kidp.copyOut(xc->mem);
+
+ return 0;
+ } else if (attrp->type == OSF::NXM_TYPE_VP) {
+ // A real "virtual processor" kernel thread. Need to fork
+ // this thread on another CPU.
+ OSF::nxm_sched_state *ssp = &rad_state->nxm_ss[thread_index];
+
+ if (ssp->nxm_u.nxm_active != 0)
+ return OSF::KERN_NOT_RECEIVER;
+
+ ssp->nxm_u.pth_id = attrp->pthid;
+ ssp->nxm_u.nxm_active = uniq_val | 1;
+
+ rad_state.copyOut(xc->mem);
+
+ Addr slot_state_addr = 0x12000 + sizeof(OSF::nxm_config_info);
+ int slot_state_size = process->numCpus * sizeof(OSF::nxm_slot_state_t);
+
+ TypedBufferArg<OSF::nxm_slot_state_t> slot_state(slot_state_addr,
+ slot_state_size);
+
+ slot_state.copyIn(xc->mem);
+
+ if (slot_state[thread_index] != OSF::NXM_SLOT_AVAIL) {
+ cerr << "nxm_thread_createFunc: requested VP slot "
+ << thread_index << " not available!" << endl;
+ fatal("");
+ }
+
+ slot_state[thread_index] = OSF::NXM_SLOT_BOUND;
+
+ slot_state.copyOut(xc->mem);
+
+ // Find a free simulator execution context.
+ list<ExecContext *> &ecList = process->execContexts;
+ list<ExecContext *>::iterator i = ecList.begin();
+ list<ExecContext *>::iterator end = ecList.end();
+ for (; i != end; ++i) {
+ ExecContext *xc = *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 = thread_index;
+ kidp.copyOut(xc->mem);
+
+ 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;
+}
+
+
+int
+nxm_idleFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ return 0;
+}
+
+int
+nxm_thread_blockFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ uint64_t tid = getArg(xc, 0);
+ uint64_t secs = getArg(xc, 1);
+ uint64_t flags = getArg(xc, 2);
+ uint64_t action = getArg(xc, 3);
+ uint64_t usecs = getArg(xc, 4);
+
+ cout << xc->cpu->name() << ": nxm_thread_block " << tid << " " << secs
+ << " " << flags << " " << action << " " << usecs << endl;
+
+ return 0;
+}
+
+
+int
+nxm_blockFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ Addr uaddr = getArg(xc, 0);
+ uint64_t val = getArg(xc, 1);
+ uint64_t secs = getArg(xc, 2);
+ uint64_t usecs = getArg(xc, 3);
+ uint64_t flags = getArg(xc, 4);
+
+ BaseCPU *cpu = xc->cpu;
+
+ cout << cpu->name() << ": nxm_block " << hex << uaddr << dec << " " << val
+ << " " << secs << " " << usecs
+ << " " << flags << endl;
+
+ return 0;
+}
+
+
+int
+nxm_unblockFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ Addr uaddr = getArg(xc, 0);
+
+ cout << xc->cpu->name() << ": nxm_unblock "
+ << hex << uaddr << dec << endl;
+
+ return 0;
+}
+
+
+int
+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 false;
+}
+
+
+// just activate one by default
+static int
+activate_waiting_context(Addr uaddr, Process *process,
+ bool activate_all = false)
+{
+ 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->setStatus(ExecContext::Active);
+
+ // get rid of this record
+ i = process->waitList.erase(i);
+
+ ++num_activated;
+ } else {
+ ++i;
+ }
+ }
+
+ return num_activated;
+}
+
+
+static void
+m5_lock_mutex(Addr uaddr, Process *process, ExecContext *xc)
+{
+ TypedBufferArg<uint64_t> lockp(uaddr);
+
+ lockp.copyIn(xc->mem);
+
+ if (*lockp == 0) {
+ // lock is free: grab it
+ *lockp = 1;
+ lockp.copyOut(xc->mem);
+ } else {
+ // lock is busy: disable until free
+ process->waitList.push_back(Process::WaitRec(uaddr, xc));
+ xc->setStatus(ExecContext::Suspended);
+ }
+}
+
+static void
+m5_unlock_mutex(Addr uaddr, Process *process, ExecContext *xc)
+{
+ TypedBufferArg<uint64_t> lockp(uaddr);
+
+ lockp.copyIn(xc->mem);
+ 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->mem);
+ }
+}
+
+
+int
+m5_mutex_lockFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ Addr uaddr = getArg(xc, 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;
+}
+
+
+int
+m5_mutex_trylockFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ Addr uaddr = getArg(xc, 0);
+ TypedBufferArg<uint64_t> lockp(uaddr);
+
+ lockp.copyIn(xc->mem);
+
+ if (*lockp == 0) {
+ // lock is free: grab it
+ *lockp = 1;
+ lockp.copyOut(xc->mem);
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+
+int
+m5_mutex_unlockFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ Addr uaddr = getArg(xc, 0);
+
+ m5_unlock_mutex(uaddr, process, xc);
+
+ return 0;
+}
+
+
+int
+m5_cond_signalFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ Addr cond_addr = getArg(xc, 0);
+
+ // Wqake up one process waiting on the condition variable.
+ activate_waiting_context(cond_addr, process);
+
+ return 0;
+}
+
+
+int
+m5_cond_broadcastFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ Addr cond_addr = getArg(xc, 0);
+
+ // Wake up all processes waiting on the condition variable.
+ activate_waiting_context(cond_addr, process, true);
+
+ return 0;
+}
+
+
+int
+m5_cond_waitFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ Addr cond_addr = getArg(xc, 0);
+ Addr lock_addr = getArg(xc, 1);
+ TypedBufferArg<uint64_t> condp(cond_addr);
+ TypedBufferArg<uint64_t> lockp(lock_addr);
+
+ // user is supposed to acquire lock before entering
+ lockp.copyIn(xc->mem);
+ assert(*lockp != 0);
+
+ m5_unlock_mutex(lock_addr, process, xc);
+
+ process->waitList.push_back(Process::WaitRec(cond_addr, xc));
+ xc->setStatus(ExecContext::Suspended);
+
+ return 0;
+}
+
+
+int
+m5_thread_exitFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ assert(xc->status() == ExecContext::Active);
+ xc->setStatus(ExecContext::Unallocated);
+
+ return 0;
+}
+
+
+SyscallDesc machSyscallDescs[] = {
+ /* 0 */ SyscallDesc("kern_invalid", unimplementedFunc),
+ /* 1 */ SyscallDesc("m5_mutex_lock", m5_mutex_lockFunc),
+ /* 2 */ SyscallDesc("m5_mutex_trylock", m5_mutex_trylockFunc),
+ /* 3 */ SyscallDesc("m5_mutex_unlock", m5_mutex_unlockFunc),
+ /* 4 */ SyscallDesc("m5_cond_signal", m5_cond_signalFunc),
+ /* 5 */ SyscallDesc("m5_cond_broadcast", m5_cond_broadcastFunc),
+ /* 6 */ SyscallDesc("m5_cond_wait", m5_cond_waitFunc),
+ /* 7 */ SyscallDesc("m5_thread_exit", 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", nxm_blockFunc),
+ /* 25 */ SyscallDesc("nxm_unblock", 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", nxm_thread_createFunc),
+ /* 33 */ SyscallDesc("nxm_task_init", nxm_task_initFunc),
+ /* 34 */ SyscallDesc("kern_invalid", unimplementedFunc),
+ /* 35 */ SyscallDesc("nxm_idle", 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", 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", 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", 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", 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)
+};
+
+const int Num_Mach_Syscall_Descs =
+ sizeof(machSyscallDescs) / sizeof(SyscallDesc);
+
+const int Max_Mach_Syscall_Desc = Num_Mach_Syscall_Descs - 1;
+
+// Since negated values are used to identify Mach syscalls, the
+// minimum (signed) valid syscall number is the negated max Mach
+// syscall number.
+const int Min_Syscall_Desc = -Max_Mach_Syscall_Desc;
+
+
+//
+// helper function for invoking syscalls
+//
+static
+int
+doSyscall(int callnum, Process *process,
+ ExecContext *xc)
+{
+ if (callnum < Min_Syscall_Desc || callnum > Max_Syscall_Desc) {
+ cerr << "Syscall " << callnum << " out of range" << endl;
+ abort();
+ }
+
+ SyscallDesc *desc =
+ (callnum < 0) ? &machSyscallDescs[-callnum] : &syscallDescs[callnum];
+
+ DCOUT(SyscallVerbose) << xc->cpu->name() << ": syscall " << desc->name
+ << " called @ " << curTick << endl;
+
+ return desc->doFunc(callnum, process, xc);
+}
+
+//
+// Indirect syscall invocation (call #0)
+//
+int
+indirectSyscallFunc(SyscallDesc *desc, int callnum, Process *process,
+ ExecContext *xc)
+{
+ int new_callnum = getArg(xc, 0);
+
+ for (int i = 0; i < 5; ++i)
+ setArg(xc, i, getArg(xc, i+1));
+
+ return doSyscall(new_callnum, process, xc);
+}
+
+
+void
+fake_syscall(Process *process, ExecContext *xc)
+{
+ int64_t callnum = xc->regs.intRegFile[ReturnValueReg];
+
+ int retval = doSyscall(callnum, process, xc);
+
+ set_return_value(xc, retval);
+}
diff --git a/arch/alpha/faults.cc b/arch/alpha/faults.cc
new file mode 100644
index 000000000..c3c19eb58
--- /dev/null
+++ b/arch/alpha/faults.cc
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#include "faults.hh"
+
+namespace {
+ const char *
+ fault_name[Num_Faults] = {
+ "none",
+ "reset",
+ "mchk",
+ "arith",
+ "interrupt",
+ "dtb_miss_single",
+ "dtb_miss_double",
+ "unalign",
+ "dfault",
+ "dfault",
+ "itbmiss",
+ "itbmiss",
+ "iaccvio",
+ "opdec",
+ "fen",
+ "pal",
+ };
+}
+
+const char *
+FaultName(int index)
+{
+ if (index < 0 || index >= Num_Faults)
+ return 0;
+
+ return fault_name[index];
+}
+
diff --git a/arch/alpha/faults.hh b/arch/alpha/faults.hh
new file mode 100644
index 000000000..bc8a4da0e
--- /dev/null
+++ b/arch/alpha/faults.hh
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#ifndef __FAULTS_HH__
+#define __FAULTS_HH__
+
+enum Fault {
+ No_Fault,
+ Reset_Fault, // processor reset
+ Machine_Check_Fault, // machine check (also internal S/W fault)
+ Arithmetic_Fault, // FP exception
+ Interrupt_Fault, // external interrupt
+ Ndtb_Miss_Fault, // DTB miss
+ Pdtb_Miss_Fault, // nested DTB miss
+ Alignment_Fault, // unaligned access
+ Dtb_Fault_Fault, // DTB page fault
+ Dtb_Acv_Fault, // DTB access violation
+ Itb_Miss_Fault, // ITB miss
+ Itb_Fault_Fault, // ITB page fault
+ Itb_Acv_Fault, // ITB access violation
+ Unimplemented_Opcode_Fault, // invalid/unimplemented instruction
+ Fen_Fault, // FP not-enabled fault
+ Pal_Fault, // call_pal S/W interrupt
+ Integer_Overflow_Fault,
+ Num_Faults // number of faults
+};
+
+const char *
+FaultName(int index);
+
+#endif // __FAULTS_HH__
diff --git a/arch/alpha/isa_desc b/arch/alpha/isa_desc
new file mode 100644
index 000000000..e6ac01f28
--- /dev/null
+++ b/arch/alpha/isa_desc
@@ -0,0 +1,2427 @@
+// -*- mode:c++ -*-
+//
+// Alpha ISA description file.
+//
+
+let {{
+ global rcs_id
+ rcs_id = "$Id$"
+}};
+
+
+#include <sstream>
+#include <iostream>
+#include <iomanip>
+
+#include <math.h>
+#if defined(linux)
+#include <fenv.h>
+#endif
+
+#include "static_inst.hh"
+#include "cprintf.hh"
+#include "misc.hh"
+#include "op_class.hh"
+
+#include "exec_context.hh"
+#include "simple_cpu.hh"
+#include "spec_state.hh"
+#include "cpu.hh"
+#include "exetrace.hh"
+#include "annotation.hh"
+
+#ifdef FULL_SYSTEM
+#include "ev5.hh"
+#endif
+
+namespace AlphaISA;
+
+// Universal (format-independent) fields
+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>;
+
+let {{
+ global operandTypeMap
+ operandTypeMap = {
+ '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)
+ }
+
+ global operandTraitsMap
+ operandTraitsMap = {
+ # 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': IntRegOperandTraits('uq', 'RA', 'IsInteger', 1),
+ 'Rb': IntRegOperandTraits('uq', 'RB', 'IsInteger', 2),
+ 'Rc': IntRegOperandTraits('uq', 'RC', 'IsInteger', 3),
+ 'Fa': FloatRegOperandTraits('df', 'FA', 'IsFloating', 1),
+ 'Fb': FloatRegOperandTraits('df', 'FB', 'IsFloating', 2),
+ 'Fc': FloatRegOperandTraits('df', 'FC', 'IsFloating', 3),
+ 'Mem': MemOperandTraits('uq', None,
+ ('IsMemRef', 'IsLoad', 'IsStore'), 4),
+ 'NPC': NPCOperandTraits('uq', None, ( None, None, 'IsControl' ), 4),
+ 'Runiq': ControlRegOperandTraits('uq', 'Uniq', None, 1),
+ 'FPCR': ControlRegOperandTraits('uq', 'Fpcr', None, 1),
+ # The next two are hacks for non-full-system call-pal emulation
+ 'R0': IntRegOperandTraits('uq', '0', None, 1),
+ 'R16': IntRegOperandTraits('uq', '16', None, 1),
+ }
+
+ defineDerivedOperandVars()
+}};
+
+declare {{
+// just temporary, while comparing with old code for debugging
+// #define SS_COMPATIBLE_DISASSEMBLY
+
+ /// Check "FP enabled" machine status bit. Called when executing any FP
+ /// instruction in full-system mode.
+ /// @retval Full-system mode: No_Fault if FP is enabled, Fen_Fault
+ /// if not. Non-full-system mode: always returns No_Fault.
+#ifdef FULL_SYSTEM
+ inline Fault checkFpEnableFault(ExecContext *xc)
+ {
+ Fault fault = No_Fault; // dummy... this ipr access should not fault
+ if (!ICSR_FPE(xc->readIpr(AlphaISA::IPR_ICSR, fault))) {
+ fault = Fen_Fault;
+ }
+ return fault;
+ }
+#else
+ inline Fault checkFpEnableFault(ExecContext *xc)
+ {
+ return No_Fault;
+ }
+#endif
+
+ /**
+ * Base class for all Alpha static instructions.
+ */
+ class AlphaStaticInst : public StaticInst<AlphaISA>
+ {
+ 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,
+ IPR_Base_DepTag = AlphaISA::IPR_Base_DepTag
+ };
+
+ /// Constructor.
+ AlphaStaticInst(const char *mnem, MachInst _machInst,
+ OpClass __opClass)
+ : StaticInst<AlphaISA>(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)
+ {
+ if (reg < FP_Base_DepTag) {
+ ccprintf(os, "r%d", reg);
+ }
+ else {
+ ccprintf(os, "f%d", reg - FP_Base_DepTag);
+ }
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
+ {
+ 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();
+ }
+ };
+}};
+
+
+def template BasicDeclare {{
+ /**
+ * Static instruction class for "%(mnemonic)s".
+ */
+ class %(class_name)s : public %(base_class)s
+ {
+ public:
+ /// Constructor.
+ %(class_name)s(MachInst machInst)
+ : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s)
+ {
+ %(constructor)s;
+ }
+
+ Fault execute(SimpleCPU *cpu, ExecContext *xc,
+ Trace::InstRecord *traceData)
+ {
+ SimpleCPU *memAccessObj __attribute__((unused)) = cpu;
+ Fault fault = No_Fault;
+
+ %(fp_enable_check)s;
+ %(exec_decl)s;
+ %(simple_rd)s;
+ %(code)s;
+
+ if (fault == No_Fault) {
+ %(simple_wb)s;
+ }
+
+ return fault;
+ }
+
+ Fault execute(CPU *cpu, SpecExecContext *xc, DynInst *dynInst,
+ Trace::InstRecord *traceData)
+ {
+ DynInst *memAccessObj __attribute__((unused)) = dynInst;
+ Fault fault = No_Fault;
+
+ %(fp_enable_check)s;
+ %(exec_decl)s;
+ %(dtld_rd)s;
+ %(code)s;
+
+ if (fault == No_Fault) {
+ %(dtld_wb)s;
+ }
+
+ return fault;
+ }
+ };
+}};
+
+def template BasicDecode {{
+ return new %(class_name)s(machInst);
+}};
+
+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)
+ return iop.subst('BasicDeclare', 'BasicDecode')
+}};
+
+
+
+////////////////////////////////////////////////////////////////////
+
+declare {{
+ /**
+ * 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, MachInst _machInst)
+ : AlphaStaticInst("nop", _machInst, No_OpClass),
+ originalDisassembly(_originalDisassembly)
+ {
+ flags[IsNop] = true;
+ }
+
+ ~Nop() { }
+
+ Fault execute(SimpleCPU *cpu, ExecContext *xc,
+ Trace::InstRecord *traceData)
+ {
+ return No_Fault;
+ }
+
+ Fault execute(CPU *cpu, SpecExecContext *xc, DynInst *dynInst,
+ Trace::InstRecord *traceData)
+ {
+ return No_Fault;
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
+ {
+#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
+ AlphaStaticInst *
+ makeNop(AlphaStaticInst *inst)
+ {
+ AlphaStaticInst *nop = new Nop(inst->disassemble(0), inst->machInst);
+ delete inst;
+ return nop;
+ }
+}};
+
+def format Nop() {{
+ return ('', 'return new Nop("%s", machInst);\n' % name)
+}};
+
+
+// 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)
+ return iop.subst('BasicDeclare', 'OperateNopCheckDecode')
+}};
+
+
+////////////////////////////////////////////////////////////////////
+//
+// Integer operate instructions
+//
+
+declare {{
+ /**
+ * 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, MachInst _machInst, OpClass __opClass)
+ : AlphaStaticInst(mnem, _machInst, __opClass), imm(INTIMM)
+ {
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
+ {
+ 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)
+ decls = iop.subst('BasicDeclare')
+
+ if uses_imm:
+ # append declaration for imm version
+ imm_cblk = CodeBlock(imm_code)
+ imm_iop = InstObjParams(name, Name + 'Imm', 'IntegerImm', imm_cblk,
+ opt_flags)
+ decls += imm_iop.subst('BasicDeclare')
+ # decode checks IMM bit to pick correct version
+ decode = iop.subst('RegOrImmDecode')
+ else:
+ # no imm version: just check for nop
+ decode = iop.subst('OperateNopCheckDecode')
+
+ return (decls, decode)
+}};
+
+
+////////////////////////////////////////////////////////////////////
+//
+// Floating-point instructions
+//
+// Note that many FP-type instructions which do not support all the
+// various rounding & trapping modes use the simpler format
+// BasicOperateWithNopCheck.
+//
+
+declare {{
+ /**
+ * 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:
+#if defined(linux)
+ static const int alphaToC99RoundingMode[];
+#endif
+
+ /// 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;
+
+ /// Constructor
+ AlphaFP(const char *mnem, MachInst _machInst, OpClass __opClass)
+ : AlphaStaticInst(mnem, _machInst, __opClass),
+ roundingMode((enum RoundingMode)FP_ROUNDMODE),
+ trappingMode((enum TrappingMode)FP_TRAPMODE)
+ {
+ if (trappingMode != Imprecise) {
+ warn("Warning: precise FP traps unimplemented\n");
+ }
+ }
+
+#if defined(linux)
+ int
+ getC99RoundingMode(ExecContext *xc)
+ {
+ if (roundingMode == Dynamic) {
+ return alphaToC99RoundingMode[bits(xc->readFpcr(), 59, 58)];
+ }
+ else {
+ return alphaToC99RoundingMode[roundingMode];
+ }
+ }
+#endif
+
+ // This differs from the AlphaStaticInst version only in
+ // printing suffixes for non-default rounding & trapping modes.
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
+ {
+ std::string mnem_str(mnemonic);
+
+ mnem_str += ((_destRegIdx[0] >= FP_Base_DepTag)
+ ? fpTrappingModeSuffix[trappingMode]
+ : intTrappingModeSuffix[trappingMode]);
+ mnem_str += roundingModeSuffix[roundingMode];
+
+ 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();
+ }
+ };
+
+#if defined(linux)
+ const int AlphaFP::alphaToC99RoundingMode[] = {
+ FE_TOWARDZERO, // Chopped
+ FE_DOWNWARD, // Minus_Infinity
+ FE_TONEAREST, // Normal
+ FE_UPWARD // Dynamic in inst, Plus_Infinity in FPCR
+ };
+#endif
+
+ 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" };
+}};
+
+
+def template FloatingPointDeclare {{
+ /**
+ * "Fast" static instruction class for "%(mnemonic)s" (imprecise
+ * trapping mode, normal rounding mode).
+ */
+ class %(class_name)sFast : public %(base_class)s
+ {
+ public:
+ /// Constructor.
+ %(class_name)sFast(MachInst machInst)
+ : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s)
+ {
+ %(constructor)s;
+ }
+
+ Fault execute(SimpleCPU *cpu, ExecContext *xc,
+ Trace::InstRecord *traceData)
+ {
+ Fault fault = No_Fault;
+
+ %(fp_enable_check)s;
+ %(exec_decl)s;
+ %(simple_rd)s;
+ %(code)s;
+
+ if (fault == No_Fault) {
+ %(simple_wb)s;
+ }
+
+ return fault;
+ }
+
+ Fault execute(CPU *cpu, SpecExecContext *xc, DynInst *dynInst,
+ Trace::InstRecord *traceData)
+ {
+ Fault fault = No_Fault;
+
+ %(fp_enable_check)s;
+ %(exec_decl)s;
+ %(dtld_rd)s;
+ %(code)s;
+
+ if (fault == No_Fault) {
+ %(dtld_wb)s;
+ }
+
+ return fault;
+ }
+ };
+
+ /**
+ * General static instruction class for "%(mnemonic)s". Supports
+ * all the various rounding and trapping modes.
+ */
+ class %(class_name)sGeneral : public %(base_class)s
+ {
+ public:
+ /// Constructor.
+ %(class_name)sGeneral(MachInst machInst)
+ : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s)
+ {
+ %(constructor)s;
+ }
+
+ Fault execute(SimpleCPU *cpu, ExecContext *xc,
+ Trace::InstRecord *traceData)
+ {
+ Fault fault = No_Fault;
+
+ %(fp_enable_check)s;
+ %(exec_decl)s;
+ %(simple_rd)s;
+
+#if defined(linux)
+ fesetround(getC99RoundingMode(xc));
+#endif
+
+ %(code)s;
+
+#if defined(linux)
+ fesetround(FE_TONEAREST);
+#endif
+
+ if (fault == No_Fault) {
+ %(simple_wb)s;
+ }
+
+ return fault;
+ }
+
+ Fault execute(CPU *cpu, SpecExecContext *xc, DynInst *dynInst,
+ Trace::InstRecord *traceData)
+ {
+ Fault fault = No_Fault;
+
+ %(fp_enable_check)s;
+ %(exec_decl)s;
+ %(dtld_rd)s;
+
+#if defined(linux)
+ fesetround(getC99RoundingMode(xc));
+#endif
+
+ %(code)s;
+
+#if defined(linux)
+ fesetround(FE_TONEAREST);
+#endif
+
+ if (fault == No_Fault) {
+ %(dtld_wb)s;
+ }
+
+ return fault;
+ }
+ };
+}};
+
+def template FloatingPointDecode {{
+ {
+ bool fast = (FP_TRAPMODE == AlphaFP::Imprecise
+ && FP_ROUNDMODE == AlphaFP::Normal);
+ AlphaStaticInst *i =
+ fast ? (AlphaStaticInst *)new %(class_name)sFast(machInst) :
+ (AlphaStaticInst *)new %(class_name)sGeneral(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)
+ return iop.subst('FloatingPointDeclare', 'FloatingPointDecode')
+}};
+
+
+////////////////////////////////////////////////////////////////////
+//
+// Memory-format instructions: LoadAddress, Load, Store
+//
+
+declare {{
+ /**
+ * Base class for general Alpha memory-format instructions.
+ */
+ class Memory : public AlphaStaticInst
+ {
+ protected:
+
+ /// Displacement for EA calculation (signed).
+ int32_t disp;
+ /// Memory request flags. See mem_req_base.hh.
+ unsigned memAccessFlags;
+
+ /// Constructor
+ Memory(const char *mnem, MachInst _machInst, OpClass __opClass)
+ : AlphaStaticInst(mnem, _machInst, __opClass),
+ disp(MEMDISP), memAccessFlags(0)
+ {
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
+ {
+ return csprintf("%-10s %c%d,%d(r%d)", mnemonic,
+ flags[IsFloating] ? 'f' : 'r', RA, MEMDISP, RB);
+ }
+ };
+
+ /**
+ * 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 AlphaStaticInst
+ {
+ protected:
+ /// Memory request flags. See mem_req_base.hh.
+ unsigned memAccessFlags;
+
+ /// Constructor
+ MemoryNoDisp(const char *mnem, MachInst _machInst, OpClass __opClass)
+ : AlphaStaticInst(mnem, _machInst, __opClass),
+ memAccessFlags(0)
+ {
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
+ {
+ return csprintf("%-10s (r%d)", mnemonic, RB);
+ }
+ };
+
+ /**
+ * Base class for "fake" effective-address computation
+ * instructions returnded by eaCompInst().
+ */
+ class EACompBase : public AlphaStaticInst
+ {
+ public:
+ /// Constructor
+ EACompBase(MachInst machInst)
+ : AlphaStaticInst("(eacomp)", machInst, IntALU)
+ {
+ }
+
+ Fault execute(SimpleCPU *cpu, ExecContext *xc,
+ Trace::InstRecord *traceData)
+ { panic("attempt to execute eacomp"); }
+
+ Fault execute(CPU *cpu, SpecExecContext *xc, DynInst *dynInst,
+ Trace::InstRecord *traceData)
+ { panic("attempt to execute eacomp"); }
+ };
+
+ /**
+ * Base class for "fake" memory-access instructions returnded by
+ * memAccInst().
+ */
+ class MemAccBase : public AlphaStaticInst
+ {
+ public:
+ /// Constructor
+ MemAccBase(MachInst machInst, OpClass __opClass)
+ : AlphaStaticInst("(memacc)", machInst, __opClass)
+ {
+ }
+
+ Fault execute(SimpleCPU *cpu, ExecContext *xc,
+ Trace::InstRecord *traceData)
+ { panic("attempt to execute memacc"); }
+
+ Fault execute(CPU *cpu, SpecExecContext *xc, DynInst *dynInst,
+ Trace::InstRecord *traceData)
+ { panic("attempt to execute memacc"); }
+ };
+
+}};
+
+
+def format LoadAddress(code) {{
+ iop = InstObjParams(name, Name, 'Memory', CodeBlock(code))
+ return iop.subst('BasicDeclare', 'BasicDecode')
+}};
+
+
+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 EACompBase
+ {
+ public:
+ /// Constructor
+ EAComp(MachInst machInst)
+ : EACompBase(machInst)
+ {
+ %(ea_constructor)s;
+ }
+ };
+
+ /**
+ * "Fake" memory access instruction class for "%(mnemonic)s".
+ */
+ class MemAcc : public MemAccBase
+ {
+ public:
+ /// Constructor
+ MemAcc(MachInst machInst)
+ : MemAccBase(machInst, %(op_class)s)
+ {
+ %(memacc_constructor)s;
+ }
+ };
+
+ /// Pointer to EAComp object.
+ StaticInstPtr<AlphaISA> eaCompPtr;
+ /// Pointer to MemAcc object.
+ StaticInstPtr<AlphaISA> memAccPtr;
+
+ public:
+
+ StaticInstPtr<AlphaISA> eaCompInst() { return eaCompPtr; }
+ StaticInstPtr<AlphaISA> memAccInst() { return memAccPtr; }
+
+ /// Constructor.
+ %(class_name)s(MachInst machInst)
+ : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s),
+ eaCompPtr(new EAComp(machInst)), memAccPtr(new MemAcc(machInst))
+ {
+ %(constructor)s;
+ }
+
+ Fault execute(SimpleCPU *cpu, ExecContext *xc,
+ Trace::InstRecord *traceData)
+ {
+ SimpleCPU *memAccessObj = cpu;
+ Addr EA;
+ Fault fault = No_Fault;
+
+ %(fp_enable_check)s;
+ %(exec_decl)s;
+ %(simple_nonmem_rd)s;
+ %(ea_code)s;
+
+ if (fault == No_Fault) {
+ %(simple_mem_rd)s;
+ %(memacc_code)s;
+ }
+
+ if (fault == No_Fault) {
+ %(simple_mem_wb)s;
+ }
+
+ if (fault == No_Fault) {
+ %(postacc_code)s;
+ }
+
+ if (fault == No_Fault) {
+ %(simple_nonmem_wb)s;
+ }
+
+ return fault;
+ }
+
+ Fault execute(CPU *cpu, SpecExecContext *xc, DynInst *dynInst,
+ Trace::InstRecord *traceData)
+ {
+ DynInst *memAccessObj = dynInst;
+ Addr EA;
+ Fault fault = No_Fault;
+
+ %(fp_enable_check)s;
+ %(exec_decl)s;
+ %(dtld_nonmem_rd)s;
+ %(ea_code)s;
+
+ if (fault == No_Fault) {
+ %(dtld_mem_rd)s;
+ %(memacc_code)s;
+ }
+
+ if (fault == No_Fault) {
+ %(dtld_mem_wb)s;
+ }
+
+ if (fault == No_Fault) {
+ %(postacc_code)s;
+ }
+
+ if (fault == No_Fault) {
+ %(dtld_nonmem_wb)s;
+ }
+
+ return fault;
+ }
+ };
+}};
+
+
+def template PrefetchDeclare {{
+ /**
+ * Static instruction class for "%(mnemonic)s".
+ */
+ class %(class_name)s : public %(base_class)s
+ {
+ public:
+ /// Constructor
+ %(class_name)s(MachInst machInst)
+ : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s)
+ {
+ %(constructor)s;
+ }
+
+ Fault execute(SimpleCPU *cpu, ExecContext *xc,
+ Trace::InstRecord *traceData)
+ {
+ Addr EA;
+ Fault fault = No_Fault;
+
+ %(fp_enable_check)s;
+ %(exec_decl)s;
+ %(simple_nonmem_rd)s;
+ %(ea_code)s;
+
+ if (fault == No_Fault) {
+ cpu->prefetch(EA, memAccessFlags);
+ }
+
+ return No_Fault;
+ }
+
+ Fault execute(CPU *cpu, SpecExecContext *xc, DynInst *dynInst,
+ Trace::InstRecord *traceData)
+ {
+ Addr EA;
+ Fault fault = No_Fault;
+
+ %(fp_enable_check)s;
+ %(exec_decl)s;
+ %(dtld_nonmem_rd)s;
+ %(ea_code)s;
+
+ if (fault == No_Fault) {
+ dynInst->prefetch(EA, memAccessFlags);
+ }
+
+ return No_Fault;
+ }
+ };
+}};
+
+
+// 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 {{
+global LoadStoreBase
+def LoadStoreBase(name, Name, ea_code, memacc_code, postacc_code = '',
+ base_class = 'Memory', flags = [],
+ declare_template = 'LoadStoreDeclare',
+ decode_template = 'BasicDecode'):
+ # Segregate flags into instruction flags (handled by InstObjParams)
+ # and memory access flags (handled here).
+
+ # Would be nice to autogenerate this list, but oh well.
+ valid_mem_flags = ['LOCKED', 'EVICT_NEXT', 'PF_EXCLUSIVE']
+ inst_flags = []
+ mem_flags = []
+ for f in flags:
+ if f in valid_mem_flags:
+ mem_flags.append(f)
+ else:
+ inst_flags.append(f)
+
+ ea_cblk = CodeBlock(ea_code)
+ memacc_cblk = CodeBlock(memacc_code)
+ postacc_cblk = CodeBlock(postacc_code)
+
+ 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
+
+ mem_flags = string.join(mem_flags, '|')
+ if mem_flags != '':
+ iop.constructor += '\n\tmemAccessFlags = ' + mem_flags + ';'
+
+ return iop.subst(declare_template, decode_template)
+}};
+
+
+def format LoadOrNop(ea_code, memacc_code, *flags) {{
+ return LoadStoreBase(name, Name, ea_code, memacc_code,
+ flags = flags,
+ decode_template = 'LoadNopCheckDecode')
+}};
+
+
+// Note that the flags passed in apply only to the prefetch version
+def format LoadOrPrefetch(ea_code, memacc_code, *pf_flags) {{
+ # declare the load instruction object and generate the decode block
+ (decls, decode) = \
+ LoadStoreBase(name, Name, ea_code, memacc_code,
+ decode_template = 'LoadPrefetchCheckDecode')
+
+ # Declare the prefetch instruction object.
+
+ # convert flags from tuple to list to make them mutable
+ pf_flags = list(pf_flags) + ['IsMemRef', 'IsLoad', 'IsDataPrefetch', 'RdPort']
+
+ (pfdecls, pfdecode) = \
+ LoadStoreBase(name, Name + 'Prefetch', ea_code, '',
+ flags = pf_flags,
+ declare_template = 'PrefetchDeclare')
+
+ return (decls + pfdecls, decode)
+}};
+
+
+def format Store(ea_code, memacc_code, *flags) {{
+ return LoadStoreBase(name, Name, ea_code, memacc_code,
+ flags = flags)
+}};
+
+
+def format StoreCond(ea_code, memacc_code, postacc_code, *flags) {{
+ return LoadStoreBase(name, Name, ea_code, memacc_code, postacc_code,
+ flags = flags)
+}};
+
+
+// Use 'MemoryNoDisp' as base: for wh64, fetch, ecb
+def format MiscPrefetch(ea_code, memacc_code, *flags) {{
+ return LoadStoreBase(name, Name, ea_code, memacc_code,
+ flags = flags, base_class = 'MemoryNoDisp')
+}};
+
+
+////////////////////////////////////////////////////////////////////
+
+
+declare {{
+
+ /**
+ * 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
+ Addr cachedPC;
+ /// Cached symbol table pointer from last disassembly
+ const SymbolTable *cachedSymtab;
+
+ /// Constructor
+ PCDependentDisassembly(const char *mnem, MachInst _machInst,
+ OpClass __opClass)
+ : AlphaStaticInst(mnem, _machInst, __opClass),
+ cachedPC(0), cachedSymtab(0)
+ {
+ }
+
+ const std::string &disassemble(Addr pc, const SymbolTable *symtab)
+ {
+ if (!cachedDisassembly ||
+ pc != cachedPC || symtab != cachedSymtab)
+ {
+ if (cachedDisassembly)
+ delete cachedDisassembly;
+
+ cachedDisassembly =
+ new std::string(generateDisassembly(pc, symtab));
+ cachedPC = pc;
+ cachedSymtab = symtab;
+ }
+
+ return *cachedDisassembly;
+ }
+ };
+
+ /**
+ * 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, MachInst _machInst, OpClass __opClass)
+ : PCDependentDisassembly(mnem, _machInst, __opClass),
+ disp(BRDISP << 2)
+ {
+ }
+
+ Addr branchTarget(Addr branchPC)
+ {
+ return branchPC + 4 + disp;
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
+ {
+ 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();
+ }
+ };
+
+ /**
+ * 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, MachInst _machInst, OpClass __opClass)
+ : PCDependentDisassembly(mnem, _machInst, __opClass),
+ disp(BRDISP)
+ {
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
+ {
+ 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<AlphaISA> *)new %(class_name)s(machInst)
+ : (StaticInst<AlphaISA> *)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'))
+ return iop.subst('BasicDeclare', 'BasicDecode')
+}};
+
+let {{
+global UncondCtrlBase
+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)
+ decls = nolink_iop.subst('BasicDeclare')
+
+ # 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)
+ decls += link_iop.subst('BasicDeclare')
+
+ # need to use link_iop for the decode template since it is expecting
+ # the shorter version of class_name (w/o "AndLink")
+ return (decls, nolink_iop.subst('JumpOrBranchDecode'))
+}};
+
+def format UncondBranch(*flags) {{
+ flags += ('IsUncondControl', 'IsDirectControl')
+ return UncondCtrlBase(name, Name, 'Branch', 'NPC + disp', flags)
+}};
+
+def format Jump(*flags) {{
+ flags += ('IsUncondControl', 'IsIndirectControl')
+ return UncondCtrlBase(name, Name, 'Jump', '(Rb & ~3) | (NPC & 1)', flags)
+}};
+
+
+declare {{
+ /**
+ * Base class for emulated call_pal calls (used only in
+ * non-full-system mode).
+ */
+ class EmulatedCallPal : public AlphaStaticInst
+ {
+ protected:
+
+ /// Constructor.
+ EmulatedCallPal(const char *mnem, MachInst _machInst,
+ OpClass __opClass)
+ : AlphaStaticInst(mnem, _machInst, __opClass)
+ {
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
+ {
+#ifdef SS_COMPATIBLE_DISASSEMBLY
+ return csprintf("%s %s", "call_pal", mnemonic);
+#else
+ return csprintf("%-10s %s", "call_pal", mnemonic);
+#endif
+ }
+ };
+}};
+
+def format EmulatedCallPal(code) {{
+ iop = InstObjParams(name, Name, 'EmulatedCallPal', CodeBlock(code))
+ return iop.subst('BasicDeclare', 'BasicDecode')
+}};
+
+declare {{
+ /**
+ * 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
+
+ /// Constructor.
+ CallPalBase(const char *mnem, MachInst _machInst,
+ OpClass __opClass)
+ : AlphaStaticInst(mnem, _machInst, __opClass),
+ palFunc(PALFUNC)
+ {
+ int palPriv = ((machInst & 0x80) != 0);
+ int shortPalFunc = (machInst & 0x3f);
+ palOffset = 0x2001 + (palPriv << 12) + (shortPalFunc << 6);
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
+ {
+ return csprintf("%-10s %#x", "call_pal", palFunc);
+ }
+ };
+}};
+
+
+def format CallPal(code) {{
+ iop = InstObjParams(name, Name, 'CallPalBase', CodeBlock(code))
+ return iop.subst('BasicDeclare', 'BasicDecode')
+}};
+
+//
+// hw_ld, hw_st
+//
+declare {{
+ /**
+ * Base class for hw_ld and hw_st.
+ */
+ class HwLoadStore : public AlphaStaticInst
+ {
+ protected:
+
+ /// Displacement for EA calculation (signed).
+ int16_t disp;
+ /// Memory request flags. See mem_req_base.hh.
+ unsigned memAccessFlags;
+
+ /// Constructor
+ HwLoadStore(const char *mnem, MachInst _machInst, OpClass __opClass)
+ : AlphaStaticInst(mnem, _machInst, __opClass), 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 generateDisassembly(Addr pc, const SymbolTable *symtab)
+ {
+#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 HwLoadStore(ea_code, memacc_code, class_ext, *flags) {{
+ return LoadStoreBase(name, Name + class_ext, ea_code, memacc_code,
+ flags = flags,
+ base_class = 'HwLoadStore')
+}};
+
+
+def format HwStoreCond(ea_code, memacc_code, postacc_code, class_ext, *flags) {{
+ return LoadStoreBase(name, Name + class_ext,
+ ea_code, memacc_code, postacc_code,
+ flags = flags,
+ base_class = 'HwLoadStore')
+}};
+
+
+declare {{
+ /**
+ * 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, MachInst _machInst, OpClass __opClass)
+ : AlphaStaticInst(mnem, _machInst, __opClass),
+ ipr_index(HW_IPR_IDX)
+ {
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
+ {
+ 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))
+ return iop.subst('BasicDeclare', 'BasicDecode')
+}};
+
+declare {{
+ /**
+ * 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, MachInst _machInst)
+ : AlphaStaticInst(_mnemonic, _machInst, No_OpClass)
+ {
+ }
+
+ Fault execute(SimpleCPU *cpu, ExecContext *xc,
+ Trace::InstRecord *traceData)
+ {
+ panic("attempt to execute unimplemented instruction '%s' "
+ "(inst 0x%08x, opcode 0x%x)", mnemonic, machInst, OPCODE);
+ return Unimplemented_Opcode_Fault;
+ }
+
+ Fault execute(CPU *cpu, SpecExecContext *xc, DynInst *dynInst,
+ Trace::InstRecord *traceData)
+ {
+ // don't panic if this is a misspeculated instruction
+ if (!xc->spec_mode)
+ panic("attempt to execute unimplemented instruction '%s' "
+ "(inst 0x%08x, opcode 0x%x)",
+ mnemonic, machInst, OPCODE);
+ return Unimplemented_Opcode_Fault;
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
+ {
+ return csprintf("%-10s (unimplemented)", mnemonic);
+ }
+ };
+
+ /**
+ * 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?
+ bool warned;
+
+ public:
+ /// Constructor
+ WarnUnimplemented(const char *_mnemonic, MachInst _machInst)
+ : AlphaStaticInst(_mnemonic, _machInst, No_OpClass), warned(false)
+ {
+ }
+
+ Fault execute(SimpleCPU *cpu, ExecContext *xc,
+ Trace::InstRecord *traceData)
+ {
+ if (!warned) {
+ warn("Warning: instruction '%s' unimplemented\n", mnemonic);
+ warned = true;
+ }
+
+ return No_Fault;
+ }
+
+ Fault execute(CPU *cpu, SpecExecContext *xc, DynInst *dynInst,
+ Trace::InstRecord *traceData)
+ {
+ if (!xc->spec_mode && !warned) {
+ warn("Warning: instruction '%s' unimplemented\n", mnemonic);
+ warned = true;
+ }
+
+ return No_Fault;
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
+ {
+#ifdef SS_COMPATIBLE_DISASSEMBLY
+ return csprintf("%-10s", mnemonic);
+#else
+ return csprintf("%-10s (unimplemented)", mnemonic);
+#endif
+ }
+ };
+}};
+
+def template WarnUnimplDeclare {{
+ /**
+ * Static instruction class for "%(mnemonic)s".
+ */
+ class %(class_name)s : public %(base_class)s
+ {
+ public:
+ /// Constructor
+ %(class_name)s(MachInst machInst)
+ : %(base_class)s("%(mnemonic)s", machInst)
+ {
+ }
+ };
+}};
+
+
+def format FailUnimpl() {{
+ iop = InstObjParams(name, 'FailUnimplemented')
+ return ('', iop.subst('BasicDecodeWithMnemonic'))
+}};
+
+def format WarnUnimpl() {{
+ iop = InstObjParams(name, Name, 'WarnUnimplemented')
+ return iop.subst('WarnUnimplDeclare', 'BasicDecode')
+}};
+
+declare {{
+ /**
+ * 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(MachInst _machInst)
+ : AlphaStaticInst("unknown", _machInst, No_OpClass)
+ {
+ }
+
+ Fault execute(SimpleCPU *cpu, ExecContext *xc,
+ Trace::InstRecord *traceData)
+ {
+ panic("attempt to execute unknown instruction "
+ "(inst 0x%08x, opcode 0x%x)", machInst, OPCODE);
+ return Unimplemented_Opcode_Fault;
+ }
+
+ Fault execute(CPU *cpu, SpecExecContext *xc, DynInst *dynInst,
+ Trace::InstRecord *traceData)
+ {
+ // don't panic if this is a misspeculated instruction
+ if (!xc->spec_mode)
+ panic("attempt to execute unknown instruction "
+ "(inst 0x%08x, opcode 0x%x)", machInst, OPCODE);
+ return Unimplemented_Opcode_Fault;
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
+ {
+ return csprintf("%-10s (inst 0x%x, opcode 0x%x)",
+ "unknown", machInst, OPCODE);
+ }
+ };
+}};
+
+def format Unknown() {{
+ return ('', 'return new Unknown(machInst);\n')
+}};
+
+declare {{
+
+ /// 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.
+ 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
+ }
+}};
+
+decode OPCODE default Unknown::unknown() {
+
+ format LoadAddress {
+ 0x08: lda({{ Ra = Rb + disp; }});
+ 0x09: ldah({{ Ra = Rb + (disp << 16); }});
+ }
+
+ format LoadOrNop {
+ 0x0a: ldbu({{ EA = Rb + disp; }}, {{ Ra.uq = Mem.ub; }});
+ 0x0c: ldwu({{ EA = Rb + disp; }}, {{ Ra.uq = Mem.uw; }});
+ 0x0b: ldq_u({{ EA = (Rb + disp) & ~7; }}, {{ Ra = Mem.uq; }});
+ 0x23: ldt({{ EA = Rb + disp; }}, {{ Fa = Mem.df; }});
+ 0x2a: ldl_l({{ EA = Rb + disp; }}, {{ Ra.sl = Mem.sl; }}, LOCKED);
+ 0x2b: ldq_l({{ EA = Rb + disp; }}, {{ Ra.uq = Mem.uq; }}, LOCKED);
+ }
+
+ format LoadOrPrefetch {
+ 0x28: ldl({{ EA = Rb + disp; }}, {{ Ra.sl = Mem.sl; }});
+ 0x29: ldq({{ EA = Rb + disp; }}, {{ Ra.uq = Mem.uq; }}, EVICT_NEXT);
+ 0x22: lds({{ EA = Rb + disp; }}, {{ Fa.uq = s_to_t(Mem.ul); }},
+ PF_EXCLUSIVE);
+ }
+
+ format Store {
+ 0x0e: stb({{ EA = Rb + disp; }}, {{ Mem.ub = Ra<7:0>; }});
+ 0x0d: stw({{ EA = Rb + disp; }}, {{ Mem.uw = Ra<15:0>; }});
+ 0x2c: stl({{ EA = Rb + disp; }}, {{ Mem.ul = Ra<31:0>; }});
+ 0x2d: stq({{ EA = Rb + disp; }}, {{ Mem.uq = Ra.uq; }});
+ 0x0f: stq_u({{ EA = (Rb + disp) & ~7; }}, {{ Mem.uq = Ra.uq; }});
+ 0x26: sts({{ EA = Rb + disp; }}, {{ Mem.ul = t_to_s(Fa.uq); }});
+ 0x27: stt({{ EA = Rb + disp; }}, {{ Mem.df = Fa; }});
+ }
+
+ format StoreCond {
+ 0x2e: stl_c({{ EA = Rb + disp; }}, {{ Mem.ul = Ra<31:0>; }},
+ {{
+ uint64_t tmp = Mem_write_result;
+ Ra = (tmp == 0 || tmp == 1) ? tmp : Ra;
+ }}, LOCKED);
+ 0x2f: stq_c({{ EA = Rb + disp; }}, {{ Mem.uq = Ra; }},
+ {{
+ uint64_t tmp = Mem_write_result;
+ Ra = (tmp == 0 || tmp == 1) ? tmp : Ra;
+ }}, 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 = Integer_Overflow_Fault;
+ 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 = Integer_Overflow_Fault;
+ 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 = Integer_Overflow_Fault;
+ 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 = Integer_Overflow_Fault;
+ 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({{
+#ifdef FULL_SYSTEM
+ Rc = 1;
+#else
+ Rc = 2;
+#endif
+ }});
+ }
+ }
+ }
+
+#ifdef 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; }}, IntMULT);
+ 0x20: mulq({{ Rc = Ra * Rb_or_imm; }}, IntMULT);
+ 0x30: umulh({{
+ uint64_t hi, lo;
+ mul128(Ra, Rb_or_imm, hi, lo);
+ Rc = hi;
+ }}, IntMULT);
+ 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 = Integer_Overflow_Fault;
+ Rc.sl = tmp<31:0>;
+ }}, IntMULT);
+ 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 = Integer_Overflow_Fault;
+ Rc = lo;
+ }}, IntMULT);
+ }
+
+ 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>; }}); }
+
+ format FailUnimpl {
+ 0x30: ctpop();
+ 0x31: perr();
+ 0x32: ctlz();
+ 0x33: cttz();
+ 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; }}, FloatCVT);
+ }
+ 0x78: decode RB {
+ 31: ftois({{ Rc.sl = t_to_s(Fa.uq); }},
+ FloatCVT);
+ }
+ }
+ }
+ }
+
+ // 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);
+ }
+ }
+
+ // IEEE floating point
+ 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); }}, FloatCVT);
+ 0x024: itoft({{ Fc.uq = Ra.uq; }}, FloatCVT);
+ 0x014: FailUnimpl::itoff(); // VAX-format conversion
+ }
+ }
+ }
+
+ // Square root instructions must have FA == 31
+ 0xb: decode FA {
+ 31: decode FP_TYPEFUNC {
+ format FloatingPointOperate {
+#ifdef SS_COMPATIBLE_FP
+ 0x0b: sqrts({{
+ if (Fb < 0.0)
+ fault = Arithmetic_Fault;
+ Fc = sqrt(Fb);
+ }}, FloatSQRT);
+#else
+ 0x0b: sqrts({{
+ if (Fb.sf < 0.0)
+ fault = Arithmetic_Fault;
+ Fc.sf = sqrt(Fb.sf);
+ }}, FloatSQRT);
+#endif
+ 0x2b: sqrtt({{
+ if (Fb < 0.0)
+ fault = Arithmetic_Fault;
+ Fc = sqrt(Fb);
+ }}, FloatSQRT);
+ }
+ }
+ }
+
+ // 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.
+ // 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.
+ 0: decode FP_TYPEFUNC {
+ format FloatingPointOperate {
+#ifdef SS_COMPATIBLE_FP
+ 0x00: adds({{ Fc = Fa + Fb; }});
+ 0x01: subs({{ Fc = Fa - Fb; }});
+ 0x02: muls({{ Fc = Fa * Fb; }}, FloatMULT);
+ 0x03: divs({{ Fc = Fa / Fb; }}, FloatDIV);
+#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; }}, FloatMULT);
+ 0x03: divs({{ Fc.sf = Fa.sf / Fb.sf; }}, FloatDIV);
+#endif
+
+ 0x20: addt({{ Fc = Fa + Fb; }});
+ 0x21: subt({{ Fc = Fa - Fb; }});
+ 0x22: mult({{ Fc = Fa * Fb; }}, FloatMULT);
+ 0x23: divt({{ Fc = Fa / Fb; }}, FloatDIV);
+ }
+ }
+
+ // 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; }},
+ FloatCMP);
+ 0x0a7, 0x5a7: cmptle({{ Fc = (Fa <= Fb) ? 2.0 : 0.0; }},
+ FloatCMP);
+ 0x0a6, 0x5a6: cmptlt({{ Fc = (Fa < Fb) ? 2.0 : 0.0; }},
+ FloatCMP);
+ 0x0a4, 0x5a4: cmptun({{ // unordered
+ Fc = (!(Fa < Fb) && !(Fa == Fb) && !(Fa > Fb)) ? 2.0 : 0.0;
+ }}, FloatCMP);
+ }
+ }
+
+ // 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: cvttq({{ Fc.sq = (int64_t)rint(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 = Integer_Overflow_Fault;
+ 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 {
+ 0x0000: trapb();
+ 0x0400: excb();
+ 0x4000: mb();
+ 0x4400: wmb();
+ 0x8000: fetch();
+ 0xa000: fetch_m();
+ 0xe800: ecb();
+ }
+
+ format MiscPrefetch {
+ 0xf800: wh64({{ EA = Rb; }},
+ {{ memAccessObj->writeHint(EA, 64); }},
+ IsMemRef, IsStore, WrPort);
+ }
+
+ format BasicOperate {
+ 0xc000: rpcc({{ Ra = curTick; }});
+ }
+
+#ifdef FULL_SYSTEM
+ format BasicOperate {
+ 0xe000: rc({{
+ Ra = xc->regs.intrflag;
+ xc->regs.intrflag = 0;
+ }}, No_OpClass);
+ 0xf000: rs({{
+ Ra = xc->regs.intrflag;
+ xc->regs.intrflag = 1;
+ }}, No_OpClass);
+ }
+#else
+ format FailUnimpl {
+ 0xe000: rc();
+ 0xf000: rs();
+ }
+#endif
+ }
+
+#ifdef FULL_SYSTEM
+ 0x00: CallPal::call_pal({{
+ // check to see if simulator wants to do something special
+ // on this PAL call (including maybe suppress it)
+ bool dopal = xc->simPalCheck(palFunc);
+
+ Annotate::Callpal(xc, palFunc);
+
+ if (dopal) {
+ if (!xc->misspeculating()) {
+ AlphaISA::swap_palshadow(&xc->regs, true);
+ }
+ xc->setIpr(AlphaISA::IPR_EXC_ADDR, NPC);
+ NPC = xc->readIpr(AlphaISA::IPR_PAL_BASE, fault) + palOffset;
+ }
+ }});
+#else
+ 0x00: decode PALFUNC {
+ format EmulatedCallPal {
+ 0x83: callsys({{ xc->syscall(); }});
+ // 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
+
+#ifdef FULL_SYSTEM
+ format HwLoadStore {
+ 0x1b: decode HW_LDST_QUAD {
+ 0: hw_ld({{ EA = (Rb + disp) & ~3; }}, {{ Ra = Mem.ul; }}, L);
+ 1: hw_ld({{ EA = (Rb + disp) & ~7; }}, {{ Ra = Mem.uq; }}, Q);
+ }
+
+ 0x1f: 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();
+ }
+ }
+
+ format BasicOperate {
+ 0x1e: hw_rei({{ xc->hwrei(); }});
+
+ // M5 special opcodes use the reserved 0x01 opcode space
+ 0x01: decode M5FUNC {
+ 0x00: arm({{
+ Annotate::ARM(xc);
+ xc->kernelStats.arm();
+ }});
+ 0x01: quiesce({{
+ Annotate::QUIESCE(xc);
+ xc->setStatus(ExecContext::Suspended);
+ xc->kernelStats.quiesce();
+ }});
+ 0x10: ivlb({{
+ Annotate::BeginInterval(xc);
+ xc->kernelStats.ivlb();
+ }}, No_OpClass);
+ 0x11: ivle({{ Annotate::EndInterval(xc); }}, No_OpClass);
+ 0x20: m5exit({{
+ if (!xc->misspeculating())
+ m5_exit();
+ }}, No_OpClass);
+ }
+ }
+
+ format HwMoveIPR {
+ 0x19: hw_mfpr({{
+ // this instruction is only valid in PAL mode
+ if (!PC_PAL(xc->regs.pc)) {
+ fault = Unimplemented_Opcode_Fault;
+ }
+ else {
+ Ra = xc->readIpr(ipr_index, fault);
+ }
+ }});
+ 0x1d: hw_mtpr({{
+ // this instruction is only valid in PAL mode
+ if (!PC_PAL(xc->regs.pc)) {
+ fault = Unimplemented_Opcode_Fault;
+ }
+ else {
+ xc->setIpr(ipr_index, Ra);
+ if (traceData) { traceData->setData(Ra); }
+ }
+ }});
+ }
+#endif
+}
diff --git a/arch/alpha/isa_traits.hh b/arch/alpha/isa_traits.hh
new file mode 100644
index 000000000..d77505651
--- /dev/null
+++ b/arch/alpha/isa_traits.hh
@@ -0,0 +1,282 @@
+/*
+ * 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.
+ */
+
+#ifndef __ISA_TRAITS_HH__
+#define __ISA_TRAITS_HH__
+
+#include "host.hh"
+#include "faults.hh"
+#include "misc.hh"
+
+class CPU;
+class IniFile;
+
+#define TARGET_ALPHA
+
+template <class ISA> class StaticInst;
+template <class ISA> class StaticInstPtr;
+
+class AlphaISA
+{
+ public:
+
+ typedef uint32_t MachInst;
+ typedef uint64_t Addr;
+ typedef uint8_t RegIndex;
+
+ enum {
+ MemoryEnd = 0xffffffffffffffffULL,
+
+ NumIntRegs = 32,
+ NumFloatRegs = 32,
+ NumMiscRegs = 32,
+
+ MaxRegsOfAnyType = 32,
+ // Static instruction parameters
+ MaxInstSrcRegs = 3,
+ MaxInstDestRegs = 2,
+
+ // semantically meaningful register indices
+ ZeroReg = 31, // architecturally meaningful
+ // the rest of these depend on the ABI
+ StackPointerReg = 30,
+ GlobalPointerReg = 29,
+ ReturnAddressReg = 26,
+ ReturnValueReg = 0,
+ ArgumentReg0 = 16,
+ ArgumentReg1 = 17,
+ ArgumentReg2 = 18,
+ ArgumentReg3 = 19,
+ ArgumentReg4 = 20,
+ ArgumentReg5 = 21,
+
+ LogVMPageSize = 13, // 8K bytes
+ VMPageSize = (1 << LogVMPageSize),
+
+ BranchPredAddrShiftAmt = 2, // instructions are 4-byte aligned
+
+ WordBytes = 4,
+ HalfwordBytes = 2,
+ ByteBytes = 1,
+ DepNA = 0,
+ };
+
+ // 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 = 64,
+ Fpcr_DepTag = 64, // floating point control register
+ Uniq_DepTag = 65,
+ IPR_Base_DepTag = 66
+ };
+
+ typedef uint64_t IntReg;
+ typedef IntReg IntRegFile[NumIntRegs];
+
+ // floating point register file entry type
+ typedef union {
+ uint64_t q;
+ double d;
+ } FloatReg;
+
+ typedef union {
+ uint64_t q[NumFloatRegs]; // integer qword view
+ double d[NumFloatRegs]; // double-precision floating point view
+ } FloatRegFile;
+
+ // control register file contents
+ typedef uint64_t MiscReg;
+ typedef struct {
+ 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
+ } MiscRegFile;
+
+#ifdef FULL_SYSTEM
+
+ typedef uint64_t InternalProcReg;
+
+#include "isa_fullsys_traits.hh"
+
+#else
+ enum {
+ NumInternalProcRegs = 0
+ };
+#endif
+
+ enum {
+ TotalNumRegs =
+ NumIntRegs + NumFloatRegs + NumMiscRegs + NumInternalProcRegs
+ };
+
+ typedef union {
+ IntReg intreg;
+ FloatReg fpreg;
+ MiscReg ctrlreg;
+ } AnyReg;
+
+ struct RegFile {
+ IntRegFile intRegFile; // (signed) integer register file
+ FloatRegFile floatRegFile; // floating point register file
+ MiscRegFile miscRegs; // control register file
+ Addr pc; // program counter
+ Addr npc; // next-cycle program counter
+#ifdef FULL_SYSTEM
+ IntReg palregs[NumIntRegs]; // PAL shadow registers
+ InternalProcReg ipr[NumInternalProcRegs]; // internal processor regs
+ int intrlock; // interrupt register lock flag
+ int intrflag; // interrupt flag
+ bool pal_shadow; // using pal_shadow registers
+#endif // FULL_SYSTEM
+ // Are these architectural, or just for convenience?
+ uint8_t opcode, ra; // current instruction details (for intr's)
+ };
+
+ static StaticInstPtr<AlphaISA> decodeInst(MachInst);
+
+ enum annotes {
+ ANNOTE_NONE = 0,
+ // An impossible number for instruction annotations
+ ITOUCH_ANNOTE = 0xffffffff,
+ };
+
+#if 0
+ static inline Addr
+ extractInstructionPrefetchTarget(const MachInst &IR, Addr PC) {
+ return(0);
+ }
+#endif
+
+ static inline bool isCallerSaveIntegerRegister(unsigned int reg) {
+ panic("register classification not implemented");
+ return (reg >= 1 && reg <= 8 || reg >= 22 && reg <= 25 || reg == 27);
+ }
+
+ static inline bool isCalleeSaveIntegerRegister(unsigned int reg) {
+ panic("register classification not implemented");
+ return (reg >= 9 && reg <= 15);
+ }
+
+ static inline bool isCallerSaveFloatRegister(unsigned int reg) {
+ panic("register classification not implemented");
+ return false;
+ }
+
+ static inline bool isCalleeSaveFloatRegister(unsigned int reg) {
+ panic("register classification not implemented");
+ return false;
+ }
+
+ 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;
+ }
+
+ // Machine operations
+
+ static void saveMachineReg(AnyReg &savereg, const RegFile &reg_file,
+ int regnum);
+
+ static void restoreMachineReg(RegFile &regs, const AnyReg &reg,
+ int regnum);
+
+#if 0
+ static void serializeSpecialRegs(const Serializeable::Proxy &proxy,
+ const RegFile &regs);
+
+ static void unserializeSpecialRegs(IniFile &db,
+ const std::string &category,
+ ConfigNode *node,
+ RegFile &regs);
+#endif
+};
+
+
+typedef AlphaISA TheISA;
+
+typedef TheISA::MachInst MachInst;
+typedef TheISA::Addr Addr;
+typedef TheISA::RegIndex RegIndex;
+typedef TheISA::IntReg IntReg;
+typedef TheISA::IntRegFile IntRegFile;
+typedef TheISA::FloatReg FloatReg;
+typedef TheISA::FloatRegFile FloatRegFile;
+typedef TheISA::MiscReg MiscReg;
+typedef TheISA::MiscRegFile MiscRegFile;
+typedef TheISA::AnyReg AnyReg;
+typedef TheISA::RegFile RegFile;
+
+const int NumIntRegs = TheISA::NumIntRegs;
+const int NumFloatRegs = TheISA::NumFloatRegs;
+const int NumMiscRegs = TheISA::NumMiscRegs;
+const int TotalNumRegs = TheISA::TotalNumRegs;
+const int VMPageSize = TheISA::VMPageSize;
+const int LogVMPageSize = TheISA::LogVMPageSize;
+const int ZeroReg = TheISA::ZeroReg;
+const int StackPointerReg = TheISA::StackPointerReg;
+const int GlobalPointerReg = TheISA::GlobalPointerReg;
+const int ReturnAddressReg = TheISA::ReturnAddressReg;
+const int ReturnValueReg = TheISA::ReturnValueReg;
+const int ArgumentReg0 = TheISA::ArgumentReg0;
+const int ArgumentReg1 = TheISA::ArgumentReg1;
+const int BranchPredAddrShiftAmt = TheISA::BranchPredAddrShiftAmt;
+
+#ifdef FULL_SYSTEM
+typedef TheISA::InternalProcReg InternalProcReg;
+const int NumInternalProcRegs = TheISA::NumInternalProcRegs;
+const int NumInterruptLevels = TheISA::NumInterruptLevels;
+
+// more stuff that should be imported here, but I'm too tired to do it
+// right now...
+#include "ev5.hh"
+#endif
+
+#endif // __ALPHA_ISA_H__
diff --git a/arch/alpha/osfpal.cc b/arch/alpha/osfpal.cc
new file mode 100644
index 000000000..796651666
--- /dev/null
+++ b/arch/alpha/osfpal.cc
@@ -0,0 +1,304 @@
+/*
+ * 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.
+ */
+
+#include "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
+#if 0
+ 0, // 0xbf
+ 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/arch/alpha/osfpal.hh b/arch/alpha/osfpal.hh
new file mode 100644
index 000000000..61e545306
--- /dev/null
+++ b/arch/alpha/osfpal.hh
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+#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,
+ NumCodes
+ };
+
+ static const char *name(int index);
+};
+
+#endif // __OSFPAL_HH__
diff --git a/arch/alpha/vtophys.cc b/arch/alpha/vtophys.cc
new file mode 100644
index 000000000..33f8f02ad
--- /dev/null
+++ b/arch/alpha/vtophys.cc
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+#include <string>
+
+#include "pmap.h"
+
+#include "exec_context.hh"
+#include "physical_memory.hh"
+#include "trace.hh"
+#include "vtophys.hh"
+
+using namespace std;
+
+inline Addr
+level3_index(Addr vaddr)
+{ return (vaddr >> ALPHA_PGSHIFT) & PTEMASK; }
+
+inline Addr
+level2_index(Addr vaddr)
+{ return (vaddr >> (ALPHA_PGSHIFT + NPTEPG_SHIFT)) & PTEMASK; }
+
+inline Addr
+level1_index(Addr vaddr)
+{ return (vaddr >> (ALPHA_PGSHIFT + 2 * NPTEPG_SHIFT)) & PTEMASK; }
+
+Addr
+kernel_pte_lookup(PhysicalMemory *pmem, Addr ptbr, Addr vaddr)
+{
+ uint64_t level1_map = ptbr;
+ Addr level1_pte = level1_map + (level1_index(vaddr) << PTESHIFT);
+
+ uint64_t level1 = pmem->phys_read_qword(level1_pte);
+ if (!entry_valid(level1)) {
+ DPRINTF(VtoPhys, "level 1 PTE not valid, va = %#\n", vaddr);
+ return 0;
+ }
+
+ uint64_t level2_map = PMAP_PTE_PA(level1);
+ Addr level2_pte = level2_map + (level2_index(vaddr) << PTESHIFT);
+ uint64_t level2 = pmem->phys_read_qword(level2_pte);
+ if (!entry_valid(level2)) {
+ DPRINTF(VtoPhys, "level 2 PTE not valid, va = %#x\n", vaddr);
+ return 0;
+ }
+
+ uint64_t level3_map = PMAP_PTE_PA(level2);
+ Addr level3_pte = level3_map + (level3_index(vaddr) << PTESHIFT);
+
+ return level3_pte;
+}
+
+Addr
+vtophys(PhysicalMemory *xc, Addr vaddr)
+{
+ Addr paddr = 0;
+ if (vaddr < ALPHA_K0SEG_BASE)
+ DPRINTF(VtoPhys, "vtophys: invalid vaddr %#x", vaddr);
+ else if (vaddr < ALPHA_K1SEG_BASE)
+ paddr = ALPHA_K0SEG_TO_PHYS(vaddr);
+ else
+ panic("vtophys: ptbr is not set on virtual lookup");
+
+ DPRINTF(VtoPhys, "vtophys(%#x) -> %#x\n", vaddr, paddr);
+
+ return paddr;
+}
+
+Addr
+vtophys(ExecContext *xc, Addr vaddr)
+{
+ Addr ptbr = xc->regs.ipr[AlphaISA::IPR_PALtemp20];
+ Addr paddr = 0;
+ if (vaddr < ALPHA_K0SEG_BASE) {
+ DPRINTF(VtoPhys, "vtophys: invalid vaddr %#x", vaddr);
+ } else if (vaddr < ALPHA_K1SEG_BASE) {
+ paddr = ALPHA_K0SEG_TO_PHYS(vaddr);
+ } else {
+ if (!ptbr)
+ panic("vtophys: ptbr is not set on virtual lookup");
+
+ Addr pte = kernel_pte_lookup(xc->physmem, ptbr, vaddr);
+ uint64_t entry = xc->physmem->phys_read_qword(pte);
+ if (pte && entry_valid(entry))
+ paddr = PMAP_PTE_PA(entry) | (vaddr & PGOFSET);
+ }
+
+ DPRINTF(VtoPhys, "vtophys(%#x) -> %#x\n", vaddr, paddr);
+
+ return paddr;
+}
+
+uint8_t *
+vtomem(ExecContext *xc, Addr vaddr, size_t len)
+{
+ Addr paddr = vtophys(xc, vaddr);
+ return xc->physmem->dma_addr(paddr, len);
+}
diff --git a/arch/alpha/vtophys.hh b/arch/alpha/vtophys.hh
new file mode 100644
index 000000000..0b65a506f
--- /dev/null
+++ b/arch/alpha/vtophys.hh
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+#ifndef __VTOPHYS_H__
+#define __VTOPHYS_H__
+
+#include "pmap.h"
+
+inline bool entry_valid(uint64_t entry)
+{ return (entry & ALPHA_PTE_VALID) != 0; }
+
+class ExecContext;
+class PhysicalMemory;
+
+Addr kernel_pte_lookup(PhysicalMemory *pmem, Addr ptbr, Addr vaddr);
+Addr vtophys(PhysicalMemory *xc, Addr vaddr);
+Addr vtophys(ExecContext *xc, Addr vaddr);
+uint8_t *vtomem(ExecContext *xc, Addr vaddr, size_t len);
+
+#endif // __VTOPHYS_H__
+
diff --git a/arch/isa_parser.py b/arch/isa_parser.py
new file mode 100644
index 000000000..a4b588197
--- /dev/null
+++ b/arch/isa_parser.py
@@ -0,0 +1,1446 @@
+#! /usr/bin/env python
+
+# $Id$
+
+# 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.
+
+import os
+import sys
+import re
+import string
+# get type names
+from types import *
+
+# Check arguments. Right now there are only two: the name of the ISA
+# description (input) file and the name of the C++ decoder (output) file.
+isa_desc_filename = sys.argv[1]
+decoder_filename = sys.argv[2]
+
+# Might as well suck the file in while we're here. This way if it's a
+# bad filename we don't waste a lot of time building the parser :-).
+input = open(isa_desc_filename)
+isa_desc = input.read()
+input.close()
+
+# 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_EXT'] + '/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', 'DECLARE', 'DECODE', 'DEFAULT', 'DEF', 'FORMAT',
+ 'LET', 'NAMESPACE', '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',
+# not used any more... commented out to suppress PLY warning
+# 'LBRACKET', 'RBRACKET',
+ 'LBRACE', 'RBRACE',
+ 'LESS', 'GREATER',
+ 'COMMA', 'SEMI', 'COLON', 'DBLCOLON',
+ 'ASTERISK',
+
+ # C preprocessor directives
+ 'CPPDIRECTIVE'
+)
+
+# Regular expressions for token matching
+t_LPAREN = r'\('
+t_RPAREN = r'\)'
+# not used any more... commented out to suppress PLY warning
+# t_LBRACKET = r'\['
+# t_RBRACKET = r'\]'
+t_LBRACE = r'\{'
+t_RBRACE = r'\}'
+t_LESS = r'\<'
+t_GREATER = 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
+
+#
+# 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]).
+#####################################################################
+
+# Not sure why, but we get a handful of shift/reduce conflicts on DECLARE.
+# By default these get resolved as shifts, which is correct, but
+# warnings are printed. Explicitly marking DECLARE as right-associative
+# suppresses the warnings.
+precedence = (
+ ('right', 'DECLARE'),
+ )
+
+# 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_declares name_decl opt_defs_and_declares decode_block'
+ global_decls1 = t[1]
+ isa_name = t[2]
+ namespace = isa_name + "Inst"
+ global_decls2 = t[3]
+ (inst_decls, code) = t[4]
+ code = indent(code)
+ # grab the last three path components of isa_desc_filename
+ filename = '/'.join(isa_desc_filename.split('/')[-3:])
+ # if the isa_desc file defines a 'rcs_id' string,
+ # echo that into the output too
+ try:
+ local_rcs_id = rcs_id
+ # strip $s out of ID so it doesn't get re-substituted
+ local_rcs_id = re.sub(r'\$', '', local_rcs_id)
+ except NameError:
+ local_rcs_id = 'Id: no RCS id found'
+ output = open(decoder_filename, 'w')
+ # split string to keep rcs from substituting this file's RCS id in
+ print >> output, '/* $Id' + '''$ */
+
+/*
+ * Copyright (c) 2003
+ * The Regents of The University of Michigan
+ * All Rights Reserved
+ *
+ * Permission is granted to use, copy, create derivative works and
+ * redistribute this software and such derivative works for any
+ * purpose, so long as the copyright notice above, this grant of
+ * permission, and the disclaimer below appear in all copies made; and
+ * so long as the name of The University of Michigan is not used in
+ * any advertising or publicity pertaining to the use or distribution
+ * of this software without specific, written prior authorization.
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE
+ * UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND
+ * WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE
+ * LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT,
+ * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
+ * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGES.
+ */
+
+/*
+ * DO NOT EDIT THIS FILE!!!
+ *
+ * It was automatically generated from this ISA description:
+ * Filename: %(filename)s
+ * RCS %(local_rcs_id)s
+ */
+
+#include "bitfield.hh" // required for bitfield support
+
+
+/////////////////////////////////////
+// Global defs (outside namespace) //
+/////////////////////////////////////
+
+%(global_decls1)s
+
+/**
+ * Namespace for %(isa_name)s static instruction objects.
+ */
+namespace %(namespace)s
+{
+
+/////////////////////////////////////
+// Global defs (within namespace) //
+/////////////////////////////////////
+
+%(global_decls2)s
+
+////////////////////////////////////
+// Declares from inst definitions //
+////////////////////////////////////
+
+%(inst_decls)s
+
+} // namespace %(namespace)s
+
+//////////////////////
+// Decoder function //
+//////////////////////
+
+StaticInstPtr<%(isa_name)s>
+%(isa_name)s::decodeInst(%(isa_name)s::MachInst machInst)
+{
+ using namespace %(namespace)s;
+%(code)s
+} // decodeInst
+''' % vars()
+ output.close()
+
+# ISA name declaration looks like "namespace <foo>;"
+def p_name_decl(t):
+ 'name_decl : NAMESPACE ID SEMI'
+ t[0] = t[2]
+
+# 'opt_defs_and_declares' is a possibly empty sequence of
+# defs and/or declares.
+def p_opt_defs_and_declares_0(t):
+ 'opt_defs_and_declares : empty'
+ t[0] = ''
+
+def p_opt_defs_and_declares_1(t):
+ 'opt_defs_and_declares : defs_and_declares'
+ t[0] = t[1]
+
+def p_defs_and_declares_0(t):
+ 'defs_and_declares : def_or_declare'
+ t[0] = t[1]
+
+def p_defs_and_declares_1(t):
+ 'defs_and_declares : defs_and_declares def_or_declare'
+ t[0] = t[1] + t[2]
+
+# The list of possible definition/declaration statements.
+def p_def_or_declare(t):
+ '''def_or_declare : def_format
+ | def_bitfield
+ | def_template
+ | global_declare
+ | global_let
+ | cpp_directive'''
+ t[0] = t[1]
+
+# preprocessor directives are copied directly to the output.
+def p_cpp_directive(t):
+ '''cpp_directive : CPPDIRECTIVE'''
+ t[0] = t[1]
+
+# Global declares 'declare {{...}}' (C++ code blocks) are copied
+# directly to the output.
+def p_global_declare(t):
+ 'global_declare : DECLARE CODELIT SEMI'
+ t[0] = substBitOps(t[2])
+
+# global let blocks 'let {{...}}' (Python code blocks) are executed
+# directly when seen. These are typically used to initialize global
+# Python variables used in later format definitions.
+def p_global_let(t):
+ 'global_let : LET CODELIT SEMI'
+ try:
+ exec(fixPythonIndentation(t[2]))
+ except:
+ error_bt(t.lineno(1), 'error in global let block "%s".' % t[2])
+ t[0] = '' # 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)
+ t[0] = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr)
+
+# 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)
+ t[0] = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr)
+
+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]] = t[4]
+ t[0] = ''
+
+# 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))
+ # insert a comment into the output to note that the def was processed
+ t[0] = '''
+//
+// parser: format %s defined
+//
+''' % id
+
+# The formal parameter list for an instruction format is a possibly
+# empty list of comma-separated parameters.
+def p_param_list_0(t):
+ 'param_list : empty'
+ t[0] = [ ]
+
+def p_param_list_1(t):
+ 'param_list : param'
+ t[0] = [t[1]]
+
+def p_param_list_2(t):
+ 'param_list : param_list COMMA param'
+ t[0] = t[1]
+ t[0].append(t[3])
+
+# Each formal parameter is either an identifier or an identifier
+# preceded by an asterisk. As in Python, the latter (if present) gets
+# a tuple containing all the excess positional arguments, allowing
+# varargs functions.
+def p_param_0(t):
+ 'param : ID'
+ t[0] = t[1]
+
+def p_param_1(t):
+ 'param : ASTERISK ID'
+ # just concatenate them: '*ID'
+ 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()
+ (decls, code, has_default) = t[5]
+ # use the "default defaults" only if there was no explicit
+ # default statement in decode_stmt_list
+ if not has_default:
+ (default_decls, default_code) = default_defaults
+ decls += default_decls
+ code += default_code
+ t[0] = (decls, '''
+switch (%s) {
+%s
+}
+''' % (t[2], indent(code)))
+
+# 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
+ (decls, code) = t[2]
+ defaultStack.push((decls, '\ndefault:\n%sbreak;' % code))
+ # 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'
+ (decls1, code1, has_default1) = t[1]
+ (decls2, code2, has_default2) = t[2]
+ if (has_default1 and has_default2):
+ error(t.lineno(1), 'Two default cases in decode block')
+ t[0] = (decls1 + '\n' + decls2, code1 + '\n' + code2,
+ has_default1 or has_default2)
+
+#
+# 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 both the declaration and decode
+# 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] = (t[1], t[1], 0)
+
+# 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, is_default) = t[1]
+ (decls, code) = t[3]
+ # just wrap the decoding code from the block as a case in the
+ # outer switch statement.
+ t[0] = (decls, '\n%s:\n%s' % (label, indent(code)), is_default)
+
+# Instruction definition (finally!).
+def p_decode_stmt_inst(t):
+ 'decode_stmt : case_label COLON inst SEMI'
+ (label, is_default) = t[1]
+ (decls, code) = t[3]
+ t[0] = (decls, '\n%s:%sbreak;' % (label, indent(code)), is_default)
+
+# 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])), 0)
+
+def p_case_label_1(t):
+ 'case_label : DEFAULT'
+ t[0] = ('default', 1)
+
+#
+# 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()
+ (decls, code) = 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 = '// %s::%s(%s)\n' % (currentFormat.id, t[1], args)
+ t[0] = (comment + decls, comment + code)
+
+# 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])
+ (decls, code) = format.defineInst(t[3], t[5], t.lineno(1))
+ comment = '// %s::%s(%s)\n' % (t[1], t[3], t[5])
+ t[0] = (comment + decls, comment + code)
+
+def p_arg_list_0(t):
+ 'arg_list : empty'
+ t[0] = [ ]
+
+def p_arg_list_1(t):
+ 'arg_list : arg'
+ t[0] = [t[1]]
+
+def p_arg_list_2(t):
+ 'arg_list : arg_list COMMA arg'
+ t[0] = t[1]
+ t[0].append(t[3])
+
+def p_arg(t):
+ '''arg : ID
+ | INTLIT
+ | STRLIT
+ | CODELIT'''
+ t[0] = t[1]
+
+#
+# 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_bt(0, "unknown syntax error")
+
+# END OF GRAMMAR RULES
+#
+# Now build the parser.
+yacc.yacc()
+
+################
+# Format object.
+#
+# A format object encapsulates an instruction format. It must provide
+# a defineInst() method that generates the code for an instruction
+# definition.
+
+class Format:
+ def __init__(self, id, params, code):
+ # constructor: just save away arguments
+ self.id = id
+ self.params = params
+ # strip blank lines from code (ones at the end are troublesome)
+ code = re.sub(r'(?m)^\s*$', '', code);
+ if code == '':
+ code = ' pass\n'
+ param_list = string.join(params, ", ")
+ f = 'def defInst(name, Name, ' + param_list + '):\n' + code
+ exec(f)
+ self.func = defInst
+
+ def defineInst(self, name, args, lineno):
+ # automatically provide a capitalized version of mnemonic
+ Name = string.capitalize(name)
+ try:
+ retval = self.func(name, Name, *args)
+ except:
+ error_bt(lineno, 'error defining "%s".' % name)
+ return retval
+
+# 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).
+
+class Stack:
+ def __init__(self, initItem):
+ self.stack = [ initItem ]
+
+ def push(self, item):
+ self.stack.append(item);
+
+ def pop(self):
+ return self.stack.pop()
+
+ def top(self):
+ return self.stack[-1]
+
+# The global format stack.
+formatStack = Stack(NoFormat())
+
+# The global default case stack.
+defaultStack = Stack( None )
+
+###################
+# 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.
+def error(lineno, string):
+ sys.exit("%s:%d: %s" % (isa_desc_filename, lineno, string))
+
+# Like error(), but include a Python stack backtrace (for processing
+# Python exceptions).
+def error_bt(lineno, string):
+ print >> sys.stderr, "%s:%d: %s" % (isa_desc_filename, lineno, string)
+ raise
+
+
+#####################################################################
+#
+# 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
+
+
+#####################################################################
+#
+# Code Parser
+#
+# The remaining code is the support for automatically extracting
+# instruction characteristics from pseudocode.
+#
+#####################################################################
+
+# Force the argument to be a list
+def makeList(list_or_item):
+ if not list_or_item:
+ return []
+ elif type(list_or_item) == ListType:
+ return list_or_item
+ else:
+ return [ list_or_item ]
+
+# generate operandSizeMap based on provided operandTypeMap:
+# basically generate equiv. C++ type and make is_signed flag
+def buildOperandSizeMap():
+ global operandSizeMap
+ operandSizeMap = {}
+ for ext in operandTypeMap.keys():
+ (desc, size) = operandTypeMap[ext]
+ if desc == 'signed int':
+ type = 'int%d_t' % size
+ is_signed = 1
+ elif desc == 'unsigned int':
+ type = 'uint%d_t' % size
+ is_signed = 0
+ elif desc == 'float':
+ is_signed = 1 # shouldn't really matter
+ if size == 32:
+ type = 'float'
+ elif size == 64:
+ type = 'double'
+ if type == '':
+ error(0, 'Unrecognized type description "%s" in operandTypeMap')
+ operandSizeMap[ext] = (size, type, is_signed)
+
+#
+# Base class for operand traits. An instance of this class (or actually
+# a class derived from this one) encapsulates the traits of a particular
+# operand type (e.g., "32-bit integer register").
+#
+class OperandTraits:
+ def __init__(self, dflt_ext, reg_spec, flags, sort_pri):
+ # Force construction of operandSizeMap from operandTypeMap
+ # if it hasn't happened yet
+ if not globals().has_key('operandSizeMap'):
+ buildOperandSizeMap()
+ self.dflt_ext = dflt_ext
+ (self.dflt_size, self.dflt_type, self.dflt_is_signed) = \
+ operandSizeMap[dflt_ext]
+ self.reg_spec = reg_spec
+ # 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')
+ self.flags = ( [], [], [] )
+ elif type(flags) == StringType:
+ # a single flag: assumed to be unconditional
+ self.flags = ( [ flags ], [], [] )
+ elif type(flags) == ListType:
+ # a list of flags: also assumed to be unconditional
+ self.flags = ( flags, [], [] )
+ elif type(flags) == TupleType:
+ # 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
+ self.flags = (makeList(uncond_flags),
+ makeList(src_flags), makeList(dest_flags))
+ self.sort_pri = sort_pri
+
+ 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, op_desc):
+ # note the empty slice '[:]' gives us a copy of self.flags[0]
+ # instead of a reference to it
+ my_flags = self.flags[0][:]
+ if op_desc.is_src:
+ my_flags += self.flags[1]
+ if op_desc.is_dest:
+ my_flags += self.flags[2]
+ return my_flags
+
+ def makeDecl(self, op_desc):
+ (size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
+ # Note that initializations in the declarations are solely
+ # to avoid 'uninitialized variable' errors from the compiler.
+ return type + ' ' + op_desc.munged_name + ' = 0;\n';
+
+class IntRegOperandTraits(OperandTraits):
+ def isReg(self):
+ return 1
+
+ def isIntReg(self):
+ return 1
+
+ def makeConstructor(self, op_desc):
+ c = ''
+ if op_desc.is_src:
+ c += '\n\t_srcRegIdx[%d] = %s;' % \
+ (op_desc.src_reg_idx, self.reg_spec)
+ if op_desc.is_dest:
+ c += '\n\t_destRegIdx[%d] = %s;' % \
+ (op_desc.dest_reg_idx, self.reg_spec)
+ return c
+
+ def makeRead(self, op_desc, cpu_model):
+ (size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
+ if (type == 'float' or type == 'double'):
+ error(0, 'Attempt to read integer register as FP')
+ if (size == self.dflt_size):
+ return '%s = xc->readIntReg(_srcRegIdx[%d]);\n' % \
+ (op_desc.munged_name, op_desc.src_reg_idx)
+ else:
+ return '%s = bits(xc->readIntReg(_srcRegIdx[%d]), %d, 0);\n' % \
+ (op_desc.munged_name, op_desc.src_reg_idx, size-1)
+
+ def makeWrite(self, op_desc, cpu_model):
+ (size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
+ if (type == 'float' or type == 'double'):
+ error(0, 'Attempt to write integer register as FP')
+ if (size != self.dflt_size and is_signed):
+ final_val = 'sext<%d>(%s)' % (size, op_desc.munged_name)
+ else:
+ final_val = op_desc.munged_name
+ wb = '''
+ {
+ %s final_val = %s;
+ xc->setIntReg(_destRegIdx[%d], final_val);\n
+ if (traceData) { traceData->setData(final_val); }
+ }''' % (self.dflt_type, final_val, op_desc.dest_reg_idx)
+ return wb
+
+class FloatRegOperandTraits(OperandTraits):
+ def isReg(self):
+ return 1
+
+ def isFloatReg(self):
+ return 1
+
+ def makeConstructor(self, op_desc):
+ c = ''
+ if op_desc.is_src:
+ c += '\n\t_srcRegIdx[%d] = %s + FP_Base_DepTag;' % \
+ (op_desc.src_reg_idx, self.reg_spec)
+ if op_desc.is_dest:
+ c += '\n\t_destRegIdx[%d] = %s + FP_Base_DepTag;' % \
+ (op_desc.dest_reg_idx, self.reg_spec)
+ return c
+
+ def makeRead(self, op_desc, cpu_model):
+ (size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
+ bit_select = 0
+ if (type == 'float'):
+ func = 'readFloatRegSingle'
+ elif (type == 'double'):
+ func = 'readFloatRegDouble'
+ else:
+ func = 'readFloatRegInt'
+ if (size != self.dflt_size):
+ bit_select = 1
+ base = 'xc->%s(_srcRegIdx[%d] - FP_Base_DepTag)' % \
+ (func, op_desc.src_reg_idx)
+ if bit_select:
+ return '%s = bits(%s, %d, 0);\n' % \
+ (op_desc.munged_name, base, size-1)
+ else:
+ return '%s = %s;\n' % (op_desc.munged_name, base)
+
+ def makeWrite(self, op_desc, cpu_model):
+ (size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
+ final_val = op_desc.munged_name
+ if (type == 'float'):
+ func = 'setFloatRegSingle'
+ elif (type == 'double'):
+ func = 'setFloatRegDouble'
+ else:
+ func = 'setFloatRegInt'
+ type = 'uint%d_t' % self.dflt_size
+ if (size != self.dflt_size and is_signed):
+ final_val = 'sext<%d>(%s)' % (size, op_desc.munged_name)
+ wb = '''
+ {
+ %s final_val = %s;
+ xc->%s(_destRegIdx[%d] - FP_Base_DepTag, final_val);\n
+ if (traceData) { traceData->setData(final_val); }
+ }''' % (type, final_val, func, op_desc.dest_reg_idx)
+ return wb
+
+class ControlRegOperandTraits(OperandTraits):
+ def isReg(self):
+ return 1
+
+ def isControlReg(self):
+ return 1
+
+ def makeConstructor(self, op_desc):
+ c = ''
+ if op_desc.is_src:
+ c += '\n\t_srcRegIdx[%d] = %s_DepTag;' % \
+ (op_desc.src_reg_idx, self.reg_spec)
+ if op_desc.is_dest:
+ c += '\n\t_destRegIdx[%d] = %s_DepTag;' % \
+ (op_desc.dest_reg_idx, self.reg_spec)
+ return c
+
+ def makeRead(self, op_desc, cpu_model):
+ (size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
+ bit_select = 0
+ if (type == 'float' or type == 'double'):
+ error(0, 'Attempt to read control register as FP')
+ base = 'xc->read%s()' % self.reg_spec
+ if size == self.dflt_size:
+ return '%s = %s;\n' % (op_desc.munged_name, base)
+ else:
+ return '%s = bits(%s, %d, 0);\n' % \
+ (op_desc.munged_name, base, size-1)
+
+ def makeWrite(self, op_desc, cpu_model):
+ (size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
+ if (type == 'float' or type == 'double'):
+ error(0, 'Attempt to write control register as FP')
+ wb = 'xc->set%s(%s);\n' % (self.reg_spec, op_desc.munged_name)
+ wb += 'if (traceData) { traceData->setData(%s); }' % \
+ op_desc.munged_name
+ return wb
+
+class MemOperandTraits(OperandTraits):
+ def isMem(self):
+ return 1
+
+ def makeConstructor(self, op_desc):
+ return ''
+
+ def makeDecl(self, op_desc):
+ (size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
+ # 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' % (type, op_desc.munged_name)
+ # Declare var to hold memory access flags.
+ c += 'unsigned %s_flags = memAccessFlags;\n' % op_desc.base_name
+ # If this operand is a dest (i.e., it's a store operation),
+ # then we need to declare a variable for the write result code
+ # as well.
+ if op_desc.is_dest:
+ c += 'uint64_t %s_write_result = 0;\n' % op_desc.base_name
+ return c
+
+ def makeRead(self, op_desc, cpu_model):
+ (size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
+ eff_type = 'uint%d_t' % size
+ return 'fault = memAccessObj->read(EA, (%s&)%s, %s_flags);\n' \
+ % (eff_type, op_desc.munged_name, op_desc.base_name)
+
+ def makeWrite(self, op_desc, cpu_model):
+ (size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
+ eff_type = 'uint%d_t' % size
+ return 'fault = memAccessObj->write((%s&)%s, EA, %s_flags,' \
+ ' &%s_write_result);\n' \
+ % (eff_type, op_desc.munged_name, op_desc.base_name,
+ op_desc.base_name)
+
+class NPCOperandTraits(OperandTraits):
+ def makeConstructor(self, op_desc):
+ return ''
+
+ def makeRead(self, op_desc, cpu_model):
+ return '%s = xc->readPC() + 4;\n' % op_desc.munged_name
+
+ def makeWrite(self, op_desc, cpu_model):
+ return 'xc->setNextPC(%s);\n' % op_desc.munged_name
+
+
+#
+# Define operand variables that get derived from the basic declaration
+# of ISA-specific operands in operandTraitsMap. This function must be
+# called by the ISA description file explicitly after defining
+# operandTraitsMap (in a 'let' block).
+#
+def defineDerivedOperandVars():
+ global operands
+ operands = operandTraitsMap.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)
+
+
+#
+# Operand descriptor class. An instance of this class represents
+# a specific operand for a code block.
+#
+class OperandDescriptor:
+ def __init__(self, full_name, base_name, ext, is_src, is_dest):
+ self.full_name = full_name
+ self.base_name = base_name
+ self.ext = ext
+ self.is_src = is_src
+ self.is_dest = is_dest
+ self.traits = operandTraitsMap[base_name]
+ # The 'effective extension' (eff_ext) is either the actual
+ # extension, if one was explicitly provided, or the default.
+ # The 'munged name' replaces the '.' between the base and
+ # extension (if any) with a '_' to make a legal C++ variable name.
+ if ext:
+ self.eff_ext = ext
+ self.munged_name = base_name + '_' + ext
+ else:
+ self.eff_ext = self.traits.dflt_ext
+ self.munged_name = base_name
+
+ # 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.traits.getFlags(self)
+ self.constructor = self.traits.makeConstructor(self)
+ self.exec_decl = self.traits.makeDecl(self)
+
+ if self.is_src:
+ self.simple_rd = self.traits.makeRead(self, 'simple')
+ self.dtld_rd = self.traits.makeRead(self, 'dtld')
+ else:
+ self.simple_rd = ''
+ self.dtld_rd = ''
+
+ if self.is_dest:
+ self.simple_wb = self.traits.makeWrite(self, 'simple')
+ self.dtld_wb = self.traits.makeWrite(self, 'dtld')
+ else:
+ self.simple_wb = ''
+ self.dtld_wb = ''
+
+class OperandDescriptorList:
+ def __init__(self):
+ self.items = []
+ self.bases = {}
+
+ 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.traits.sort_pri - b.traits.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)
+
+#
+# Find all the operands in the given code block. Returns an operand
+# descriptor list (instance of class OperandDescriptorList).
+#
+def findOperands(code):
+ operands = OperandDescriptorList()
+ # delete comments so we don't accidentally 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 = operands.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 = OperandDescriptor(op_full, op_base, op_ext,
+ is_src, is_dest)
+ operands.append(op_desc)
+ # start next search after end of current match
+ next_pos = match.end()
+ operands.sort()
+ # enumerate source & dest register operands... used in building
+ # constructor later
+ srcRegs = 0
+ destRegs = 0
+ operands.numFPDestRegs = 0
+ operands.numIntDestRegs = 0
+ for op_desc in operands:
+ if op_desc.traits.isReg():
+ if op_desc.is_src:
+ op_desc.src_reg_idx = srcRegs
+ srcRegs += 1
+ if op_desc.is_dest:
+ op_desc.dest_reg_idx = destRegs
+ destRegs += 1
+ if op_desc.traits.isFloatReg():
+ operands.numFPDestRegs += 1
+ elif op_desc.traits.isIntReg():
+ operands.numIntDestRegs += 1
+ operands.numSrcRegs = srcRegs
+ operands.numDestRegs = destRegs
+ # now make a final pass to finalize op_desc fields that may depend
+ # on the register enumeration
+ for op_desc in operands:
+ op_desc.finalize()
+ return operands
+
+# Munge operand names in code string to make legal C++ variable names.
+# (Will match munged_name attribute of OperandDescriptor object.)
+def substMungedOpNames(code):
+ return operandsWithExtRE.sub(r'\1_\2', 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 = findOperands(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.exec_decl = self.operands.concatAttrStrings('exec_decl')
+
+ is_mem = lambda op: op.traits.isMem()
+ not_mem = lambda op: not op.traits.isMem()
+
+ self.simple_rd = self.operands.concatAttrStrings('simple_rd')
+ self.simple_wb = self.operands.concatAttrStrings('simple_wb')
+ self.simple_mem_rd = \
+ self.operands.concatSomeAttrStrings(is_mem, 'simple_rd')
+ self.simple_mem_wb = \
+ self.operands.concatSomeAttrStrings(is_mem, 'simple_wb')
+ self.simple_nonmem_rd = \
+ self.operands.concatSomeAttrStrings(not_mem, 'simple_rd')
+ self.simple_nonmem_wb = \
+ self.operands.concatSomeAttrStrings(not_mem, 'simple_wb')
+
+ self.dtld_rd = self.operands.concatAttrStrings('dtld_rd')
+ self.dtld_wb = self.operands.concatAttrStrings('dtld_wb')
+ self.dtld_mem_rd = \
+ self.operands.concatSomeAttrStrings(is_mem, 'dtld_rd')
+ self.dtld_mem_wb = \
+ self.operands.concatSomeAttrStrings(is_mem, 'dtld_wb')
+ self.dtld_nonmem_rd = \
+ self.operands.concatSomeAttrStrings(not_mem, 'dtld_rd')
+ self.dtld_nonmem_wb = \
+ self.operands.concatSomeAttrStrings(not_mem, 'dtld_wb')
+
+ self.flags = self.operands.concatAttrLists('flags')
+
+ # 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 = 'WrPort'
+ elif 'IsLoad' in self.flags or 'IsPrefetch' in self.flags:
+ self.op_class = 'RdPort'
+ elif 'IsFloating' in self.flags:
+ self.op_class = 'FloatADD'
+ else:
+ self.op_class = 'IntALU'
+
+# Assume all instruction flags are of the form 'IsFoo'
+instFlagRE = re.compile(r'Is.*')
+
+# OpClass constants are just a little more complicated
+opClassRE = re.compile(r'Int.*|Float.*|.*Port|No_OpClass')
+
+class InstObjParams:
+ def __init__(self, mnem, class_name, base_class = '',
+ code_block = None, opt_args = []):
+ self.mnemonic = mnem
+ self.class_name = class_name
+ self.base_class = base_class
+ if code_block:
+ for code_attr in code_block.__dict__.keys():
+ setattr(self, code_attr, getattr(code_block, code_attr))
+ 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 = ''
+
+ def subst(self, *args):
+ result = []
+ for t in args:
+ if not templateMap.has_key(t):
+ error(0, 'InstObjParams::subst: undefined template "%s"' % t)
+ try:
+ result.append(templateMap[t] % self.__dict__)
+ except KeyError, key:
+ error(0, 'InstObjParams::subst: no definition for "%s"' % key)
+ if len(args) == 1:
+ result = result[0]
+ return result
+
+#
+# All set... read in and parse the ISA description.
+#
+yacc.parse(isa_desc)
diff --git a/base/bitfield.hh b/base/bitfield.hh
new file mode 100644
index 000000000..ee5ea72cf
--- /dev/null
+++ b/base/bitfield.hh
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+#ifndef __BITFIELD_HH
+#define __BITFIELD_HH
+
+#include <inttypes.h>
+
+/**
+ * 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
diff --git a/base/callback.hh b/base/callback.hh
new file mode 100644
index 000000000..a1d23b5ed
--- /dev/null
+++ b/base/callback.hh
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#ifndef __CALLBACK_HH__
+#define __CALLBACK_HH__
+
+#include <list>
+
+class Callback {
+ public:
+ virtual ~Callback() {}
+ virtual void process() = 0;
+};
+
+class CallbackQueue
+{
+ protected:
+ std::list<Callback *> callbacks;
+
+ public:
+ void add(Callback *callback) { callbacks.push_back(callback); }
+ bool empty() const { return callbacks.empty(); }
+ void processOne() {
+ Callback *c = callbacks.front();
+ callbacks.pop_front();
+ c->process();
+ }
+ void processAll() { while (!empty()) processOne(); }
+};
+
+#endif // __CALLBACK_HH__
diff --git a/base/circlebuf.cc b/base/circlebuf.cc
new file mode 100644
index 000000000..482c97f84
--- /dev/null
+++ b/base/circlebuf.cc
@@ -0,0 +1,187 @@
+/*
+ * 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.
+ */
+
+#include <algorithm>
+#include <string>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "cprintf.hh"
+#include "circlebuf.hh"
+#include "intmath.h"
+
+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::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/base/circlebuf.hh b/base/circlebuf.hh
new file mode 100644
index 000000000..e0abed31c
--- /dev/null
+++ b/base/circlebuf.hh
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#ifndef __CIRCLEBUF_HH__
+#define __CIRCLEBUF_HH__
+
+
+class CircleBuf
+{
+protected:
+ char *buf;
+ bool rollover;
+ int buflen;
+ int size;
+ int start;
+ int stop;
+
+public:
+ explicit CircleBuf(int l);
+ ~CircleBuf();
+
+ bool empty() { return size == 0; }
+ void dump();
+ void flush();
+ void read(char *b, int len);
+ void read(int fd, int len);
+ void read(int fd);
+ 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/base/cprintf.cc b/base/cprintf.cc
new file mode 100644
index 000000000..be6e64f59
--- /dev/null
+++ b/base/cprintf.cc
@@ -0,0 +1,277 @@
+/*
+ * 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.
+ */
+
+#include <cassert>
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+
+#include "cprintf.hh"
+
+using namespace std;
+
+namespace cp {
+
+void
+ArgList::dump(const string &format)
+{
+ const char *p = format.c_str();
+
+ stream->fill(' ');
+ stream->flags((ios::fmtflags)0);
+
+ Format fmt;
+
+ while (*p) {
+ switch (*p) {
+ case '%': {
+ if (p[1] == '%') {
+ *stream << '%';
+ p += 2;
+ continue;
+ }
+
+ if (objects.empty())
+ format_invalid(*stream);
+
+ Base *data = objects.front();
+
+ fmt.clear();
+ 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;
+ }
+ }
+
+ ios::fmtflags saved_flags = stream->flags();
+ char old_fill = stream->fill();
+ int old_precision = stream->precision();
+
+ data->process(*stream, fmt);
+
+ stream->flags(saved_flags);
+ stream->fill(old_fill);
+ stream->precision(old_precision);
+
+ delete data;
+ objects.pop_front();
+ ++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;
+ }
+
+ ios::iostate state = stream->rdstate();
+ if (state) {
+#if 0
+ cout << "stream->rdstate() == " << state << endl;
+ if (state & ios::badbit)
+ cout << "stream is bad!\n";
+ if (state & ios::eofbit)
+ cout << "stream at eof!\n";
+ if (state & ios::failbit)
+ cout << "stream failed!\n";
+ if (state & ios::goodbit)
+ cout << "stream is good!!\n";
+#endif
+ stream->clear();
+ }
+ }
+
+ while (!objects.empty()) {
+ Base *data = objects.front();
+ data->process(*stream, fmt);
+ delete data;
+ objects.pop_front();
+ }
+}
+
+string
+ArgList::dumpToString(const string &format)
+{
+ stringstream ss;
+
+ dump(ss, format);
+
+ return ss.str();
+}
+
+}
diff --git a/base/cprintf.hh b/base/cprintf.hh
new file mode 100644
index 000000000..2dc84502a
--- /dev/null
+++ b/base/cprintf.hh
@@ -0,0 +1,197 @@
+/*
+ * 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.
+ */
+
+#ifndef __CPRINTF_HH__
+#define __CPRINTF_HH__
+
+#include <iostream>
+#include <list>
+#include <sstream>
+#include <string>
+
+namespace cp {
+
+#include "cprintf_formats.hh"
+
+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:
+ format_invalid(out);
+ break;
+ }
+ }
+ };
+
+ typedef std::list<Base *> list_t;
+
+ protected:
+ list_t objects;
+ std::ostream *stream;
+
+ public:
+ ArgList() : stream(&std::cout) {}
+
+ 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/base/cprintf_formats.hh b/base/cprintf_formats.hh
new file mode 100644
index 000000000..1e5de4fdf
--- /dev/null
+++ b/base/cprintf_formats.hh
@@ -0,0 +1,354 @@
+/*
+ * 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.
+ */
+
+#ifndef __CPRINTF_FORMATS_HH__
+#define __CPRINTF_FORMATS_HH__
+
+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() { }
+ 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;
+ }
+};
+
+inline void
+format_invalid(std::ostream &out)
+{
+ using namespace std;
+
+ out << "format invalid!!!" << endl;
+}
+
+
+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)
+{ format_invalid(out); }
+
+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); }
+
+#if 0
+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); }
+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)
+{ format_invalid(out); }
+
+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); }
+
+#endif // __CPRINTF_FORMATS_HH__
diff --git a/base/date.cc b/base/date.cc
new file mode 100644
index 000000000..f961b9c21
--- /dev/null
+++ b/base/date.cc
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+const char *compileDate = __DATE__ " " __TIME__;
diff --git a/base/dbl_list.hh b/base/dbl_list.hh
new file mode 100644
index 000000000..4f6d61a45
--- /dev/null
+++ b/base/dbl_list.hh
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ */
+
+#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/base/endian.hh b/base/endian.hh
new file mode 100644
index 000000000..2877744ae
--- /dev/null
+++ b/base/endian.hh
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+#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/base/fast_alloc.cc b/base/fast_alloc.cc
new file mode 100644
index 000000000..290e59113
--- /dev/null
+++ b/base/fast_alloc.cc
@@ -0,0 +1,191 @@
+/*
+ * 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.
+ */
+
+/*
+ * This code was originally written by Steve Reinhardt as part of
+ * the Wisconsin Wind Tunnel simulator. Relicensed as part of M5
+ * by permission.
+ */
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include <assert.h>
+#include "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
diff --git a/base/fast_alloc.hh b/base/fast_alloc.hh
new file mode 100644
index 000000000..7d699abd1
--- /dev/null
+++ b/base/fast_alloc.hh
@@ -0,0 +1,203 @@
+/*
+ * 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.
+ */
+
+/*
+ * 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
+
+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 // __FAST_ALLOC_H__
diff --git a/base/fifo_buffer.cc b/base/fifo_buffer.cc
new file mode 100644
index 000000000..d0b59e832
--- /dev/null
+++ b/base/fifo_buffer.cc
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#include "fifo_buffer.hh"
+
+template<class T>
+void
+FifoBuffer<T>::dump(void)
+{
+ if (buffer->count() > 0)
+ for (iterator i=buffer->tail(); i.notnull(); i=i.prev())
+ i->dump();
+}
+
+
diff --git a/base/fifo_buffer.hh b/base/fifo_buffer.hh
new file mode 100644
index 000000000..27b4973ac
--- /dev/null
+++ b/base/fifo_buffer.hh
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+#ifndef __FIFO_BUFFER_HH__
+#define __FIFO_BUFFER_HH__
+
+#include "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(void) { return buffer->head(); }
+ iterator tail(void) { return buffer->tail(); }
+
+ unsigned count(void) {return buffer->count();}
+ unsigned free_slots(void) {return buffer->num_free();}
+
+ T * peek(void)
+ {
+ if (count() > 0) {
+ return tail().data_ptr();
+ }
+ else {
+ return 0;
+ }
+ }
+
+ T remove(void)
+ {
+ assert(buffer->count() > 0);
+ T rval = *buffer->tail();
+ buffer->remove_tail();
+ return rval;
+ }
+
+ void dump(void);
+
+ ~FifoBuffer() { delete buffer; }
+};
+
+
+#endif
+
diff --git a/base/hashmap.hh b/base/hashmap.hh
new file mode 100644
index 000000000..21d4a818e
--- /dev/null
+++ b/base/hashmap.hh
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+#ifndef __HASHMAP_HH__
+#define __HASHMAP_HH__
+
+#if defined(__GNUC__) && __GNUC__ >= 3
+#include <ext/hash_map>
+#else
+#include <hash_map>
+#endif
+
+#include <string>
+
+#include "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 {
+ template<>
+ struct hash<uint64_t> {
+ size_t operator()(uint64_t r) const {
+ return r;
+ }
+ };
+
+ template<>
+ struct hash<Counter> {
+ size_t operator()(Counter r) const {
+ return r;
+ };
+ };
+
+ 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/base/inet.cc b/base/inet.cc
new file mode 100644
index 000000000..33483bb32
--- /dev/null
+++ b/base/inet.cc
@@ -0,0 +1,161 @@
+/*
+ * 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.
+ */
+
+#include <sstream>
+#include <string>
+
+#include "cprintf.hh"
+#include "host.hh"
+#include "inet.hh"
+
+using namespace::std;
+string
+eaddr_string(const uint8_t a[6])
+{
+ stringstream stream;
+ ccprintf(stream, "%x:%x:%x:%x:%x:%x", a[0], a[1], a[2], a[3], a[4], a[5]);
+
+ return stream.str();
+}
+
+/*
+ * 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.
+ */
+/***********************************************************************
+ This section of code taken from NetBSD
+***********************************************************************/
+
+#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);
+}
+
+/***********************************************************************
+ This is the end of the NetBSD code
+***********************************************************************/
diff --git a/base/inet.hh b/base/inet.hh
new file mode 100644
index 000000000..1c48d0730
--- /dev/null
+++ b/base/inet.hh
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+#ifndef __INET_HH__
+#define __INET_HH__
+
+#include "host.hh"
+
+uint32_t crc32be(const uint8_t *buf, size_t len);
+uint32_t crc32le(const uint8_t *buf, size_t len);
+std::string eaddr_string(const uint8_t a[6]);
+#endif // __INET_HH__
diff --git a/base/inifile.cc b/base/inifile.cc
new file mode 100644
index 000000000..3f80ec259
--- /dev/null
+++ b/base/inifile.cc
@@ -0,0 +1,437 @@
+/*
+ * 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.
+ */
+
+#define USE_CPP
+// #define CPP_PIPE
+
+
+#ifdef USE_CPP
+#include <sys/signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#endif
+
+#include <fstream>
+#include <iostream>
+#if __GNUC__ >= 3
+#include <ext/stdio_filebuf.h>
+#endif
+
+#include <vector>
+#include <string>
+
+#include "inifile.hh"
+#include "str.hh"
+
+using namespace std;
+
+IniFile::IniFile()
+{}
+
+IniFile::~IniFile()
+{
+ ConfigTable::iterator i = table.begin();
+ ConfigTable::iterator end = table.end();
+
+ while (i != end) {
+ delete (*i).second;
+ ++i;
+ }
+}
+
+
+#ifdef USE_CPP
+bool
+IniFile::loadCPP(const string &file, vector<char *> &cppArgs)
+{
+ int fd[2];
+
+#ifdef CPP_PIPE
+ if (pipe(fd) == -1)
+ return false;
+#else
+ char tempfile[] = "/tmp/configXXXXXX";
+ fd[0] = fd[1] = mkstemp(tempfile);
+#endif
+
+ int pid = fork();
+
+ if (pid == -1)
+ return 1;
+
+ 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];
+
+ args[nextArg++] = filename;
+ args[nextArg++] = NULL;
+
+ close(STDOUT_FILENO);
+ if (dup2(fd[1], STDOUT_FILENO) == -1)
+ return 1;
+
+ execvp("g++", args);
+
+ exit(1);
+ }
+
+ int retval;
+ waitpid(pid, &retval, 0);
+
+ // check for normal completion of CPP
+ if (!WIFEXITED(retval) || WEXITSTATUS(retval) != 0)
+ return false;
+
+#ifdef CPP_PIPE
+ close(fd[1]);
+#else
+ lseek(fd[0], 0, SEEK_SET);
+#endif
+
+ bool status = false;
+
+#if __GNUC__ >= 3
+ using namespace __gnu_cxx;
+ stdio_filebuf<char> fbuf(fd[0], ios_base::in, true,
+ static_cast<stdio_filebuf<char>::int_type>(BUFSIZ));
+
+ if (fbuf.is_open()) {
+ istream f(&fbuf);
+ status = load(f);
+ }
+
+#else
+ ifstream f(fd[0]);
+ if (f.is_open())
+ status = load(f);
+#endif
+
+#ifndef CPP_PIPE
+ unlink(tempfile);
+#endif
+
+ 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)
+{
+ EntryTable::iterator ei = table.find(entryName);
+
+ if (ei == table.end()) {
+ // new entry
+ table[entryName] = new Entry(value);
+ }
+ else {
+ // override old entry
+ ei->second->setValue(value);
+ }
+}
+
+
+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)
+{
+ ConfigTable::iterator ci = table.find(sectionName);
+
+ if (ci != table.end()) {
+ return ci->second;
+ }
+ else {
+ // new entry
+ Section *sec = new Section();
+ table[sectionName] = sec;
+ return sec;
+ }
+}
+
+
+IniFile::Section *
+IniFile::findSection(const string &sectionName) const
+{
+ ConfigTable::const_iterator ci = table.find(sectionName);
+
+ return (ci == table.end()) ? NULL : ci->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);
+
+ offset = rest.find('=');
+ if (offset == string::npos) // no '='found
+ return false;
+
+ string entryName = rest.substr(0, offset);
+ string value = rest.substr(offset + 1);
+
+ eat_white(sectionName);
+ eat_white(entryName);
+ eat_white(value);
+
+ Section *s = addSection(sectionName);
+ s->addEntry(entryName, value);
+
+ return true;
+}
+
+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;
+
+ string::size_type offset = line.find('=');
+ string entryName = line.substr(0, offset);
+ string value = line.substr(offset + 1);
+
+ eat_white(entryName);
+ eat_white(value);
+
+ section->addEntry(entryName, value);
+ }
+
+ 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::findDefault(const string &_section, const string &entry,
+ string &value) const
+{
+ string section = _section;
+ while (!find(section, entry, value)) {
+ if (!find(section, "default", section))
+ return false;
+ }
+
+ return true;
+}
+
+
+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 (ConfigTable::iterator ci = table.begin();
+ ci != table.end(); ++ci) {
+ const string &sectionName = ci->first;
+ Section *section = ci->second;
+
+ if (!section->isReferenced()) {
+ if (section->findEntry("unref_section_ok") == NULL) {
+ cerr << "Section " << sectionName << " not referenced."
+ << endl;
+ unref = true;
+ }
+ }
+ else {
+#if 0
+ if (section->findEntry("unref_entries_ok") == NULL) {
+ bool unrefEntries = section->printUnreferenced(sectionName);
+ unref = unref || unrefEntries;
+ }
+#else
+ if (section->printUnreferenced(sectionName)) {
+ unref = true;
+ }
+#endif
+ }
+ }
+
+ 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 << "\n";
+ }
+}
+
+void
+IniFile::dump()
+{
+ for (ConfigTable::iterator ci = table.begin();
+ ci != table.end(); ++ci) {
+ ci->second->dump(ci->first);
+ }
+}
diff --git a/base/inifile.hh b/base/inifile.hh
new file mode 100644
index 000000000..b384fe21a
--- /dev/null
+++ b/base/inifile.hh
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+
+#ifndef __INIFILE_HH__
+#define __INIFILE_HH__
+
+#include <fstream>
+#include <list>
+#include <string>
+#include <vector>
+
+#include "hashmap.hh"
+
+class IniFile
+{
+ protected:
+ class Entry
+ {
+ std::string value;
+ mutable bool referenced;
+
+ public:
+ Entry(const std::string &v)
+ : value(v), referenced(false)
+ {
+ }
+
+ bool isReferenced() { return referenced; }
+
+ const std::string &getValue() const;
+
+ void setValue(const std::string &v) { value = v; }
+ };
+
+ class Section
+ {
+ typedef m5::hash_map<std::string, Entry *> EntryTable;
+
+ EntryTable table;
+ mutable bool referenced;
+
+ public:
+ Section()
+ : table(), referenced(false)
+ {
+ }
+
+ bool isReferenced() { return referenced; }
+
+ void addEntry(const std::string &entryName, const std::string &value);
+ Entry *findEntry(const std::string &entryName) const;
+
+ bool printUnreferenced(const std::string &sectionName);
+ void dump(const std::string &sectionName);
+ };
+
+ typedef m5::hash_map<std::string, Section *> ConfigTable;
+
+ protected:
+ ConfigTable table;
+
+ Section *addSection(const std::string &sectionName);
+ Section *findSection(const std::string &sectionName) const;
+
+ bool load(std::istream &f);
+
+ public:
+ IniFile();
+ ~IniFile();
+
+ bool loadCPP(const std::string &file, std::vector<char *> &cppFlags);
+ bool load(const std::string &file);
+
+ bool add(const std::string &s);
+
+ bool find(const std::string &section, const std::string &entry,
+ std::string &value) const;
+ bool findDefault(const std::string &section, const std::string &entry,
+ std::string &value) const;
+
+ bool printUnreferenced();
+
+ void dump();
+};
+
+#endif // __INIFILE_HH__
diff --git a/base/intmath.cc b/base/intmath.cc
new file mode 100644
index 000000000..8d08e59a8
--- /dev/null
+++ b/base/intmath.cc
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#include "intmath.h"
+
+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/base/intmath.h b/base/intmath.h
new file mode 100644
index 000000000..814dacd5f
--- /dev/null
+++ b/base/intmath.h
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+#ifndef __INTMATH_H__
+#define __INTMATH_H__
+
+// Returns the prime number one less than n.
+int PrevPrime(int n);
+
+// Determine if a number is prime
+inline bool
+IsPrime(int n)
+{
+ int 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;
+}
+
+inline unsigned
+LeastSigBit(unsigned n)
+{ return n & ~(n - 1); }
+
+inline bool
+IsPowerOf2(unsigned n)
+{ return n != 0 && LeastSigBit(n) == n; }
+
+inline int
+FloorLog2(unsigned x)
+{
+ if (x == 0)
+ return -1;
+
+ 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
+CeilLog2(unsigned n)
+{ return FloorLog2(n-1)+1; }
+
+inline unsigned
+FloorPow2(unsigned n)
+{ return 1 << FloorLog2(n); }
+
+inline unsigned
+CeilPow2(unsigned n)
+{ return 1 << CeilLog2(n); }
+
+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_H__
diff --git a/base/kgdb.h b/base/kgdb.h
new file mode 100644
index 000000000..35f74f4ba
--- /dev/null
+++ b/base/kgdb.h
@@ -0,0 +1,203 @@
+/* $Id$ */
+/*
+ * 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
+
+/*
+ * MMCSR Fault Type Codes. [OSF/1 PALcode Specific]
+ */
+
+#define ALPHA_MMCSR_INVALTRANS 0
+#define ALPHA_MMCSR_ACCESS 1
+#define ALPHA_MMCSR_FOR 2
+#define ALPHA_MMCSR_FOE 3
+#define ALPHA_MMCSR_FOW 4
+
+/*
+ * Instruction Fault Type Codes. [OSF/1 PALcode Specific]
+ */
+
+#define ALPHA_IF_CODE_BPT 0
+#define ALPHA_IF_CODE_BUGCHK 1
+#define ALPHA_IF_CODE_GENTRAP 2
+#define ALPHA_IF_CODE_FEN 3
+#define ALPHA_IF_CODE_OPDEC 4
+
+#define BKPT_INST 0x00000080 // breakpoint instruction
+#define BKPT_SIZE (4) // size of breakpoint inst
+
+#define IS_BREAKPOINT_TRAP(type, code) ((type) == ALPHA_KENTRY_IF && \
+ (code) == ALPHA_IF_CODE_BPT)
+#define IS_WATCHPOINT_TRAP(type, code) 0
+
+
+#endif /* __KGDB_H__ */
diff --git a/base/misc.cc b/base/misc.cc
new file mode 100644
index 000000000..0ce9f7be9
--- /dev/null
+++ b/base/misc.cc
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+
+#include <iostream>
+#include <string>
+
+#include "host.hh"
+#include "cprintf.hh"
+#include "misc.hh"
+#include "universe.hh"
+#include "trace.hh"
+
+using namespace std;
+
+void
+__panic(const string &format, cp::ArgList &args, const char *func,
+ const char *file, int line)
+{
+ string fmt = "panic: " + format + " [%s:%s, line %d]\n";
+ args.append(func);
+ args.append(file);
+ args.append(line);
+ args.dump(cerr, fmt);
+
+ delete &args;
+
+#if TRACING_ON
+ // dump trace buffer, if there is one
+ Trace::theLog.dump(cerr);
+#endif
+
+ abort();
+}
+
+void
+__fatal(const string &format, cp::ArgList &args, const char *func,
+ const char *file, int line)
+{
+ long mem_usage();
+
+ string fmt = "fatal: " + format + " [%s:%s, line %d]\n"
+ "\n%d\nMemory Usage: %ld KBytes\n";
+
+ args.append(func);
+ args.append(file);
+ args.append(line);
+ args.append(curTick);
+ args.append(mem_usage());
+ 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;
+#ifdef VERBOSE_WARN
+ fmt += " [%s:%s, line %d]\n";
+ args.append(func);
+ args.append(file);
+ args.append(line);
+#else
+ fmt += "\n";
+#endif
+ args.dump(cerr, fmt);
+
+ delete &args;
+}
diff --git a/base/misc.hh b/base/misc.hh
new file mode 100644
index 000000000..3ac4d1491
--- /dev/null
+++ b/base/misc.hh
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+#ifndef __MISC_HH__
+#define __MISC_HH__
+
+#include <assert.h>
+#include "cprintf.hh"
+
+//
+// This implements a cprintf based panic
+//
+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
+//
+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/base/mod_num.hh b/base/mod_num.hh
new file mode 100644
index 000000000..3b4ef9bb8
--- /dev/null
+++ b/base/mod_num.hh
@@ -0,0 +1,201 @@
+/*
+ * 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.
+ */
+
+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/base/object_file.cc b/base/object_file.cc
new file mode 100644
index 000000000..b9542f280
--- /dev/null
+++ b/base/object_file.cc
@@ -0,0 +1,173 @@
+/*
+ * 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.
+ */
+
+#include <list>
+#include <string>
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "cprintf.hh"
+#include "ecoff.hh"
+#include "object_file.hh"
+#include "symtab.hh"
+
+using namespace std;
+
+ObjectFile::ObjectFile()
+ : descriptor(-1), data(NULL)
+{}
+
+ObjectFile::ObjectFile(string file)
+ : descriptor(-1), data(NULL)
+{ open(file); }
+
+ObjectFile::~ObjectFile()
+{ close(); }
+
+bool
+ObjectFile::open(string file_name)
+{
+ close();
+
+ name = file_name;
+
+ descriptor = ::open(name.c_str(), O_RDONLY);
+ if (descriptor < 0)
+ return false;
+
+ len = (size_t)::lseek(descriptor, 0, SEEK_END);
+
+ data = (uint8_t *)::mmap(NULL, len, PROT_READ, MAP_SHARED, descriptor, 0);
+ if (data == MAP_FAILED)
+ return false;
+
+ postOpen();
+
+ return true;
+}
+
+void
+ObjectFile::close()
+{
+ if (descriptor >= 0)
+ ::close(descriptor);
+
+ if (data)
+ ::munmap(data, len);
+}
+
+void
+EcoffObject::postOpen()
+{
+ exec = &(((EcoffExecHeader *)data)->f);
+ aout = &(((EcoffExecHeader *)data)->a);
+
+ text_off = aout->text_start;
+ data_off = aout->data_start;
+ bss_off = aout->bss_start;
+
+ text_size = aout->tsize;
+ data_size = aout->dsize;
+ bss_size = aout->bsize;
+}
+
+bool
+EcoffObject::loadGlobals(SymbolTable *symtab)
+{
+ if (!symtab)
+ return false;
+
+ if (exec->f_magic != ALPHAMAGIC) {
+ cprintf("wrong magic\n");
+ return false;
+ }
+
+ EcoffSymHeader *syms = (EcoffSymHeader *)(data + exec->f_symptr);
+ if (syms->magic != ECOFF_SYM_MAGIC) {
+ cprintf("bad symbol header magic\n");
+ exit(1);
+ }
+
+ EcoffExtSymEntry *ext_syms =
+ (EcoffExtSymEntry *)(data + syms->cbExtOffset);
+
+ char *ext_strings = (char *)(data + syms->cbSsExtOffset);
+ for (int i = 0; i < syms->iextMax; i++) {
+ EcoffSymEntry *entry = &(ext_syms[i].asym);
+ if (entry->iss != -1)
+ symtab->insert(entry->value, ext_strings + entry->iss);
+ }
+
+ return true;
+}
+
+bool
+EcoffObject::loadLocals(SymbolTable *symtab)
+{
+ if (!symtab)
+ return false;
+
+ if (exec->f_magic != ALPHAMAGIC) {
+ cprintf("wrong magic\n");
+ return false;
+ }
+
+ EcoffSymHeader *syms = (EcoffSymHeader *)(data + exec->f_symptr);
+ if (syms->magic != ECOFF_SYM_MAGIC) {
+ cprintf("bad symbol header magic\n");
+ exit(1);
+ }
+
+ EcoffSymEntry *local_syms = (EcoffSymEntry *)(data + syms->cbSymOffset);
+ char *local_strings = (char *)(data + syms->cbSsOffset);
+ EcoffFileDesc *fdesc = (EcoffFileDesc *)(data + syms->cbFdOffset);
+
+ for (int i = 0; i < syms->ifdMax; i++) {
+ EcoffSymEntry *entry =
+ (EcoffSymEntry *)(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 == 1 || entry[j].st == 6)
+ if (entry[j].iss != -1)
+ symtab->insert(entry[j].value, strings + entry[j].iss);
+ }
+ }
+
+ for (int i = 0; i < syms->isymMax; i++) {
+ EcoffSymEntry *entry = &(local_syms[i]);
+ if (entry->st == 6)
+ if (entry->st == 1 || entry->st == 6)
+ symtab->insert(entry->value, local_strings + entry->iss);
+ }
+
+ return true;
+}
diff --git a/base/object_file.hh b/base/object_file.hh
new file mode 100644
index 000000000..c100efc94
--- /dev/null
+++ b/base/object_file.hh
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+#ifndef __OBJECT_FILE_HH__
+#define __OBJECT_FILE_HH__
+
+#include "ecoff.hh"
+#include "isa_traits.hh" // for Addr
+
+class SymbolTable;
+
+class ObjectFile
+{
+ protected:
+ std::string name;
+ int descriptor;
+ uint8_t *data;
+ size_t len;
+
+ public:
+ ObjectFile();
+ explicit ObjectFile(std::string file);
+ virtual ~ObjectFile();
+
+ bool open(std::string file);
+ void close();
+
+ virtual bool loadGlobals(SymbolTable *symtab) = 0;
+ virtual bool loadLocals(SymbolTable *symtab) = 0;
+ virtual void postOpen() = 0;
+
+ protected:
+ Addr text_off;
+ Addr data_off;
+ Addr bss_off;
+
+ size_t text_size;
+ size_t data_size;
+ size_t bss_size;
+
+ public:
+ Addr textOffset() const { return text_off; }
+ Addr dataOffset() const { return data_off; }
+ Addr bssOffset() const { return bss_off; }
+
+ size_t textSize() const { return text_size; }
+ size_t dataSize() const { return data_size; }
+ size_t bssSize() const { return bss_size; }
+};
+
+class EcoffObject : public ObjectFile
+{
+ protected:
+ EcoffFileHeader *exec;
+ EcoffAOutHeader *aout;
+
+ public:
+ EcoffObject() {}
+ explicit EcoffObject(std::string file) { open(file); }
+ virtual ~EcoffObject() {}
+
+ virtual bool loadGlobals(SymbolTable *symtab);
+ virtual bool loadLocals(SymbolTable *symtab);
+ virtual void postOpen();
+};
+
+#endif // __OBJECT_FILE_HH__
diff --git a/base/pollevent.cc b/base/pollevent.cc
new file mode 100644
index 000000000..fd08d4c4c
--- /dev/null
+++ b/base/pollevent.cc
@@ -0,0 +1,254 @@
+/*
+ * 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.
+ */
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+
+#include <fcntl.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include "async.hh"
+#include "host.hh"
+#include "misc.hh"
+#include "pollevent.hh"
+#include "universe.hh"
+
+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();
+}
+
+/////////////////////////////////////////////////////
+//
+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 = 0;
+
+ if (sigaction(SIGIO, &act, &oldio) == -1)
+ panic("could not do sigaction");
+
+ act.sa_handler = handleALRM;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+
+ 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/base/pollevent.hh b/base/pollevent.hh
new file mode 100644
index 000000000..57e12f549
--- /dev/null
+++ b/base/pollevent.hh
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+#ifndef __POLLEVENT_H__
+#define __POLLEVENT_H__
+
+#include <vector>
+#include <poll.h>
+#include "universe.hh"
+
+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;
+};
+
+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/base/random.cc b/base/random.cc
new file mode 100644
index 000000000..42a169c06
--- /dev/null
+++ b/base/random.cc
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+#include <cstdlib>
+#include <cmath>
+
+#include "param.hh"
+#include "random.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()
+{
+ ::srandom(seed);
+}
+
+long
+getLong()
+{
+ return random();
+}
+
+// idea for generating a double from erand48
+double
+getDouble()
+{
+ union {
+ uint32_t _long[2];
+ uint16_t _short[4];
+ };
+
+ _long[0] = random();
+ _long[1] = random();
+
+ return ldexp((double) _short[0], -48) +
+ ldexp((double) _short[1], -32) +
+ ldexp((double) _short[2], -16);
+}
diff --git a/base/random.hh b/base/random.hh
new file mode 100644
index 000000000..f1b383eda
--- /dev/null
+++ b/base/random.hh
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+#ifndef __RANDOM_HH__
+#define __RANDOM_HH__
+
+#include "host.hh"
+
+long getLong();
+double getDouble();
+
+template <typename T>
+struct Random;
+
+struct Random<int8_t>
+{
+ static int8_t get()
+ { return getLong() & (int8_t)-1; }
+};
+
+struct Random<uint8_t>
+{
+ uint8_t get()
+ { return getLong() & (uint8_t)-1; }
+};
+
+struct Random<int16_t>
+{
+ int16_t get()
+ { return getLong() & (int16_t)-1; }
+};
+
+struct Random<uint16_t>
+{
+ uint16_t get()
+ { return getLong() & (uint16_t)-1; }
+};
+
+struct Random<int32_t>
+{
+ int32_t get()
+ { return (int32_t)getLong(); }
+};
+
+struct Random<uint32_t>
+{
+ uint32_t get()
+ { return (uint32_t)getLong(); }
+};
+
+struct Random<int64_t>
+{
+ int64_t get()
+ { return (int64_t)getLong() << 32 || (uint64_t)getLong(); }
+};
+
+struct Random<uint64_t>
+{
+ uint64_t get()
+ { return (uint64_t)getLong() << 32 || (uint64_t)getLong(); }
+};
+
+struct Random<float>
+{
+ float get()
+ { return getDouble(); }
+};
+
+struct Random<double>
+{
+ double get()
+ { return getDouble(); }
+};
+
+#endif // __RANDOM_HH__
diff --git a/base/range.hh b/base/range.hh
new file mode 100644
index 000000000..254e71460
--- /dev/null
+++ b/base/range.hh
@@ -0,0 +1,260 @@
+/*
+ * 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.
+ */
+
+#ifndef __RANGE_HH__
+#define __RANGE_HH__
+
+#include <assert.h>
+
+#include "str.hh"
+#include "intmath.h"
+
+template<class T>
+class Range
+{
+ private:
+ bool valid;
+
+ public:
+ T start;
+ T end;
+
+ public:
+ Range() {}
+
+ Range(const Range &r) { operator=(r); }
+
+ Range(const T& s, const T& e)
+ : start(s), end(e)
+ {
+ valid = (start <= end);
+ }
+
+ Range(const std::string &s) { valid = parse(s); }
+
+ ~Range() {}
+
+ int compare(const T &p);
+ bool parse(const std::string &s);
+ const Range &operator=(const Range &r);
+
+ bool isValid() const { return valid; }
+};
+
+
+template<class T>
+inline int
+Range<T>::compare(const T &p)
+{
+ assert(isValid());
+
+ if (p < start)
+ return -1;
+ else if (p > end)
+ return 1;
+ else
+ return 0;
+}
+
+// Parse a range string
+//
+// Ranges are in the following format:
+// <range> := {<start_val>}:{<end>}
+// <end> := <end_val> | +<delta>
+template<class T>
+inline bool
+Range<T>::parse(const std::string &str)
+{
+ std::vector<std::string> values;
+ tokenize(values, str, ':');
+
+ T thestart, theend;
+
+ if (values.size() != 2)
+ return false;
+
+ std::string s = values[0];
+ std::string e = values[1];
+
+ if (!to_number(s, thestart))
+ return false;
+
+ bool increment = (e[0] == '+');
+ if (increment)
+ e = e.substr(1);
+
+ if (!to_number(e, theend))
+ return false;
+
+ if (increment)
+ theend += thestart;
+
+ start = thestart;
+ end = theend;
+
+ if (start > end)
+ return false;
+
+ return true;
+}
+
+
+template<class T>
+inline const Range<T> &
+Range<T>::operator=(const Range<T> &r)
+{
+ if (this != &r) {
+ start = r.start;
+ end = r.end;
+
+ valid = r.valid;
+ }
+ else {
+ valid = false;
+ }
+
+ return *this;
+}
+
+template<class T>
+inline std::ostream &
+operator<<(std::ostream &o, const Range<T> &r)
+{
+ // don't currently support output of invalid ranges
+ assert(r.isValid());
+ o << r.start << ":" << r.end;
+ return o;
+}
+
+//////////////////////////////////////////
+//
+// Compare two ranges
+//
+template<class T>
+inline bool
+operator==(const Range<T> &l, const Range<T> &r)
+{
+ // ranges must both be valid to be equal
+ return (l.isValid() && r.isValid() &&
+ (l.start == r.start) && (l.end == r.end));
+}
+
+template<class T>
+inline bool
+operator!=(const Range<T> &l, const Range<T> &r)
+{
+ // for symmetry with ==, an invalid range is not equal to any other
+ return (!l.isValid() || !r.isValid() ||
+ (l.start != r.start) || (l.end != r.end));
+}
+
+//////////////////////////////////////////
+//
+// Compare position to a range
+//
+// - 'pos == range' indicates that position pos is within the given range.
+// This test always returns false if the range is invalid.
+//
+// - 'pos < range' and 'pos > range' indicate that the position is
+// before the start of or after the end of the range, respectively.
+// The range must be valid for these comparisons to be made.
+//
+// All other comparisons do the obvious thing based on these definitions.
+//
+//
+
+//
+// Basic comparisons
+//
+template<class T>
+inline bool
+operator==(const T &pos, const Range<T> &range)
+{ return range.isValid() && pos >= range.start && pos <= range.end; }
+
+template<class T>
+inline bool
+operator<(const T &pos, const Range<T> &range)
+{ assert(range.isValid()); return pos < range.start; }
+
+template<class T>
+inline bool
+operator>(const T &pos, const Range<T> &range)
+{ assert(range.isValid()); return pos > range.end; }
+
+//
+// Derived comparisons
+//
+template<class T>
+inline bool
+operator<=(const T &pos, const Range<T> &range)
+{ assert(range.isValid()); return pos <= range.end; }
+
+template<class T>
+inline bool
+operator>=(const T &pos, const Range<T> &range)
+{ assert(range.isValid()); return pos >= range.start; }
+
+template<class T>
+inline bool
+operator!=(const T &pos, const Range<T> &range)
+{ return !(pos == range); }
+
+//
+// Define symmetric comparisons based on above
+//
+template<class T>
+inline bool
+operator>(const Range<T> &range, const T &pos)
+{ return pos < range; }
+
+template<class T>
+inline bool
+operator<(const Range<T> &range, const T &pos)
+{ return pos > range; }
+
+template<class T>
+inline bool
+operator<=(const Range<T> &range, const T &pos)
+{ return pos >= range; }
+
+template<class T>
+inline bool
+operator>=(const Range<T> &range, const T &pos)
+{ return pos <= range; }
+
+template<class T>
+inline bool
+operator==(const Range<T> &range, const T &pos)
+{ return (pos == range); }
+
+template<class T>
+inline bool
+operator!=(const Range<T> &range, const T &pos)
+{ return (pos != range); }
+
+#endif // __RANGE_HH__
diff --git a/base/refcnt.hh b/base/refcnt.hh
new file mode 100644
index 000000000..5bc62ae23
--- /dev/null
+++ b/base/refcnt.hh
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+
+#ifndef __REFCNT_HH__
+#define __REFCNT_HH__
+
+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
+{
+ private:
+ T *data;
+
+ void copy(T *d) {
+ data = d;
+ if (data)
+ data->incref();
+ }
+ void del() {
+ if (data)
+ data->decref();
+ }
+
+ 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) {
+ if (data != p) {
+ del();
+ copy(p);
+ }
+ return *this;
+ }
+
+ RefCountingPtr &operator=(const RefCountingPtr& r) {
+ if (data != r.data) {
+ del();
+ copy(r.data);
+ }
+ return *this;
+ }
+
+ 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/base/remote_gdb.cc b/base/remote_gdb.cc
new file mode 100644
index 000000000..5a6987877
--- /dev/null
+++ b/base/remote_gdb.cc
@@ -0,0 +1,1150 @@
+/* $Id$ */
+/*
+ * 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 <unistd.h>
+
+#include <string>
+
+#include "exec_context.hh"
+#include "intmath.h"
+#include "kgdb.h"
+
+#include "physical_memory.hh"
+#include "remote_gdb.hh"
+#include "socket.hh"
+#include "trace.hh"
+#include "vtophys.hh"
+#include "system.hh"
+#include "static_inst.hh"
+
+using namespace std;
+
+#ifdef DEBUG
+RemoteGDB *theDebugger = NULL;
+
+void
+debugger()
+{
+ if (theDebugger)
+ theDebugger->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)
+{}
+
+GDBListener::~GDBListener()
+{
+ if (event)
+ delete event;
+}
+
+void
+GDBListener::listen()
+{
+ while (!listener.listen(port, true)) {
+ DPRINTF(RGDB, "GDBListener(listen): Can't bind port %d\n", port);
+ port++;
+ }
+
+ cerr << "Listening for remote gdb connection on port " << port << endl;
+ event = new Event(this, listener.getfd(), POLLIN);
+ pollQueue.schedule(event);
+}
+
+void
+GDBListener::accept()
+{
+ if (!listener.islistening())
+ panic("GDBListener(accept): cannot accept a connection 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)
+{ gdb->trap(ALPHA_KENTRY_IF); }
+
+RemoteGDB::RemoteGDB(System *_system, ExecContext *c)
+ : event(NULL), fd(-1), active(false), attached(false),
+ system(_system), pmem(_system->physmem), context(c)
+{
+#ifdef DEBUG
+ theDebugger = this;
+#endif
+ memset(gdbregs, 0, sizeof(gdbregs));
+}
+
+RemoteGDB::~RemoteGDB()
+{
+ if (event)
+ delete event;
+}
+
+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;
+ Addr pte;
+
+ va = alpha_trunc_page(va);
+ last_va = alpha_round_page(va + len);
+
+ do {
+ if (va < ALPHA_K0SEG_BASE) {
+ DPRINTF(RGDB, "RGDB(acc): Mapping is invalid %#x < K0SEG\n", va);
+ return false;
+ }
+
+ if (va < ALPHA_K1SEG_BASE) {
+ if (va < (ALPHA_K0SEG_BASE + pmem->getSize())) {
+ DPRINTF(RGDB, "RGDB(acc): Mapping is valid K0SEG <= "
+ "%#x < K0SEG + size\n", va);
+ return true;
+ } else {
+ DPRINTF(RGDB, "RGDB(acc): Mapping is invalid %#x < K0SEG\n",
+ va);
+ return false;
+ }
+ }
+
+ Addr ptbr = context->regs.ipr[AlphaISA::IPR_PALtemp20];
+ pte = kernel_pte_lookup(pmem, ptbr, va);
+ if (!pte || !entry_valid(pmem->phys_read_qword(pte))) {
+ DPRINTF(RGDB, "RGDB(acc): %#x pte is invalid\n", va);
+ return false;
+ }
+ va += ALPHA_PGBYTES;
+ } while (va < last_va);
+
+ DPRINTF(RGDB, "RGDB(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_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));
+ memcpy(&gdbregs[KGDB_REG_V0], context->regs.intRegFile, 32 * sizeof(uint64_t));
+#ifdef KGDB_FP_REGS
+ memcpy(&gdbregs[KGDB_REG_F0], context->regs.floatRegFile.q,
+ 32 * sizeof(uint64_t));
+#endif
+ gdbregs[KGDB_REG_PC] = context->regs.pc;
+}
+
+///////////////////////////////////////////////////////////
+// RemoteGDB::setregs
+//
+// Translate the GDB register format into the kernel
+// debugger register format.
+//
+void
+RemoteGDB::setregs()
+{
+ memcpy(context->regs.intRegFile, &gdbregs[KGDB_REG_V0], 32 * sizeof(uint64_t));
+#ifdef KGDB_FP_REGS
+ memcpy(context->regs.floatRegFile.q, &gdbregs[KGDB_REG_F0],
+ 32 * sizeof(uint64_t));
+#endif
+ context->regs.pc = gdbregs[KGDB_REG_PC];
+}
+
+void
+RemoteGDB::setTempBreakpoint(TempBreakpoint &bkpt, Addr addr)
+{
+ DPRINTF(RGDB, "RGDB(setTempBreakpoint): addr=%#x\n", addr);
+
+ bkpt.address = addr;
+ insertHardBreak(addr, 4);
+}
+
+void
+RemoteGDB::clearTempBreakpoint(TempBreakpoint &bkpt)
+{
+ DPRINTF(RGDB, "RGDB(setTempBreakpoint): addr=%#x\n",
+ bkpt.address);
+
+
+ removeHardBreak(bkpt.address, 4);
+ bkpt.address = 0;
+}
+
+void
+RemoteGDB::clearSingleStep()
+{
+ DPRINTF(RGDB, "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->regs.pc;
+ 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<TheISA> 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(RGDB, "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(RGDB, "RGDB(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(RGDB, "RGDB(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;
+
+ uint8_t *maddr;
+
+ if (vaddr < 10) {
+ DPRINTF(RGDB, "\nRGDB(read): reading memory location zero!\n");
+ vaddr = lastaddr + lastsize;
+ }
+
+ DPRINTF(RGDB, "RGDB(read): addr=%#x, size=%d", vaddr, size);
+#if TRACING_ON
+ char *d = data;
+ size_t s = size;
+#endif
+
+ lastaddr = vaddr;
+ lastsize = size;
+
+ size_t count = min((Addr)size,
+ VMPageSize - (vaddr & (VMPageSize - 1)));
+
+ maddr = vtomem(context, vaddr, count);
+ memcpy(data, maddr, count);
+
+ vaddr += count;
+ data += count;
+ size -= count;
+
+ while (size >= VMPageSize) {
+ maddr = vtomem(context, vaddr, count);
+ memcpy(data, maddr, VMPageSize);
+
+ vaddr += VMPageSize;
+ data += VMPageSize;
+ size -= VMPageSize;
+ }
+
+ if (size > 0) {
+ maddr = vtomem(context, vaddr, count);
+ memcpy(data, maddr, size);
+ }
+
+#if TRACING_ON
+ if (DTRACE(RGDB)) {
+ char buf[1024];
+ mem2hex(buf, d, s);
+ cprintf(": %s\n", buf);
+ }
+#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;
+
+ uint8_t *maddr;
+
+ if (vaddr < 10) {
+ DPRINTF(RGDB, "RGDB(write): writing memory location zero!\n");
+ vaddr = lastaddr + lastsize;
+ }
+
+ if (DTRACE(RGDB)) {
+ char buf[1024];
+ mem2hex(buf, data, size);
+ cprintf("RGDB(write): addr=%#x, size=%d: %s\n", vaddr, size, buf);
+ }
+
+ lastaddr = vaddr;
+ lastsize = size;
+
+ size_t count = min((Addr)size,
+ VMPageSize - (vaddr & (VMPageSize - 1)));
+
+ maddr = vtomem(context, vaddr, count);
+ memcpy(maddr, data, count);
+
+ vaddr += count;
+ data += count;
+ size -= count;
+
+ while (size >= VMPageSize) {
+ maddr = vtomem(context, vaddr, count);
+ memcpy(maddr, data, VMPageSize);
+
+ vaddr += VMPageSize;
+ data += VMPageSize;
+ size -= VMPageSize;
+ }
+
+ if (size > 0) {
+ maddr = vtomem(context, vaddr, count);
+ memcpy(maddr, 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(RGDB, "creating hardware breakpoint at %#x\n", evpc);
+ schedule();
+}
+
+void
+RemoteGDB::HardBreakpoint::process(ExecContext *xc)
+{
+ DPRINTF(RGDB, "handling hardware breakpoint at %#x\n", pc());
+
+ if (xc == gdb->context)
+ gdb->trap(ALPHA_KENTRY_IF);
+}
+
+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(RGDB, "inserting hardware breakpoint at %#x\n", addr);
+
+ HardBreakpoint *&bkpt = hardBreakMap[addr];
+ if (bkpt == 0)
+ bkpt = new HardBreakpoint(this, addr);
+
+ bkpt->refcount++;
+
+ return true;
+
+#if 0
+ break_iter_t i = hardBreakMap.find(addr);
+ if (i == hardBreakMap.end()) {
+ HardBreakpoint *bkpt = new HardBreakpoint(this, addr);
+ hardBreakMap[addr] = bkpt;
+ i = hardBreakMap.insert(make_pair(addr, bkpt));
+ if (i == hardBreakMap.end())
+ return false;
+ }
+
+ (*i).second->refcount++;
+#endif
+}
+
+bool
+RemoteGDB::removeHardBreak(Addr addr, size_t len)
+{
+ if (len != sizeof(MachInst))
+ panic("invalid length\n");
+
+ DPRINTF(RGDB, "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(RGDB, "RGDB(trap): PC=%#x NPC=%#x\n",
+ context->regs.pc, context->regs.npc);
+
+ 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) {
+ if (!IS_BREAKPOINT_TRAP(type, 0)) {
+ // No debugger active -- let trap handle this.
+ return false;
+ }
+ active = true;
+ } else {
+ // Tell remote host that an exception has occurred.
+ sprintf((char *)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".
+ sprintf((char *)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->regs.pc = val;
+ context->regs.npc = val + sizeof(MachInst);
+ }
+ clearSingleStep();
+ goto out;
+
+ case KGDB_CONT:
+ if (p - data < datalen) {
+ val = hex2i(&p);
+ context->regs.pc = val;
+ context->regs.npc = val + sizeof(MachInst);
+ }
+ clearSingleStep();
+ goto out;
+
+ case KGDB_ASYNC_STEP:
+ subcmd = hex2i(&p);
+ if (*p++ == ';') {
+ val = hex2i(&p);
+ context->regs.pc = val;
+ context->regs.npc = val + sizeof(MachInst);
+ }
+ setSingleStep();
+ goto out;
+
+ case KGDB_STEP:
+ if (p - data < datalen) {
+ val = hex2i(&p);
+ context->regs.pc = val;
+ context->regs.npc = 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(RGDB, "kgdb: 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(RGDB, "kgdb: 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(RGDB, "kgdb: Unsupported command: %s\n",
+ gdb_command(command));
+ DDUMP(RGDB, (uint8_t *)data, datalen);
+ send("");
+ continue;
+
+ default:
+ // Unknown command.
+ DPRINTF(RGDB, "kgdb: 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/base/remote_gdb.hh b/base/remote_gdb.hh
new file mode 100644
index 000000000..315860ead
--- /dev/null
+++ b/base/remote_gdb.hh
@@ -0,0 +1,189 @@
+/*
+ * 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.
+ */
+
+#ifndef __REMOTE_GDB_HH__
+#define __REMOTE_GDB_HH__
+
+#include "kgdb.h"
+#include "pc_event.hh"
+#include "pollevent.hh"
+#include "socket.hh"
+
+class System;
+class ExecContext;
+class PhysicalMemory;
+
+class RemoteGDB
+{
+ 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;
+
+ 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 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:
+ HardBreakpoint(RemoteGDB *_gdb, Addr addr);
+
+ int refcount;
+ 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);
+};
+
+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();
+};
+
+#endif /* __REMOTE_GDB_H__ */
diff --git a/base/res_list.hh b/base/res_list.hh
new file mode 100644
index 000000000..b5eb209c9
--- /dev/null
+++ b/base/res_list.hh
@@ -0,0 +1,756 @@
+/*
+ * 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.
+ */
+
+#ifndef __RES_LIST_HH__
+#define __RES_LIST_HH__
+
+#include "cprintf.hh"
+#include "std_types.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)
+ 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/base/sched_list.hh b/base/sched_list.hh
new file mode 100644
index 000000000..f5b90f571
--- /dev/null
+++ b/base/sched_list.hh
@@ -0,0 +1,176 @@
+/*
+ * 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.
+ */
+
+#ifndef SCHED_LIST_HH
+#define SCHED_LIST_HH
+
+#include <list>
+#include "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 (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>
+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/base/socket.cc b/base/socket.cc
new file mode 100644
index 000000000..00fdf1ba3
--- /dev/null
+++ b/base/socket.cc
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#include <errno.h>
+#include <unistd.h>
+
+#include "host.hh"
+#include "misc.hh"
+#include "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!");
+
+ 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;
+}
+
+#if !defined(__OpenBSD__) && !defined(linux)
+typedef int socklen_t;
+#endif
+
+// 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/base/socket.hh b/base/socket.hh
new file mode 100644
index 000000000..39bacba94
--- /dev/null
+++ b/base/socket.hh
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+#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/base/statistics.cc b/base/statistics.cc
new file mode 100644
index 000000000..1e8cd2565
--- /dev/null
+++ b/base/statistics.cc
@@ -0,0 +1,823 @@
+/*
+ * 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.
+ */
+
+#include <iomanip>
+#include <iostream>
+#include <list>
+#include <map>
+#include <string>
+#include <sstream>
+
+#include <math.h>
+
+#include "cprintf.hh"
+#include "intmath.h"
+#include "misc.hh"
+#include "statistics.hh"
+#include "str.hh"
+#include "universe.hh"
+
+#ifdef __M5_NAN
+float
+__nan()
+{
+ union {
+ uint32_t ui;
+ float f;
+ } nan;
+
+ nan.ui = 0x7fc00000;
+ return nan.f;
+}
+#endif
+
+#ifdef STAT_DEBUG
+static int total_stats = 0;
+#endif
+
+using namespace std;
+
+// This is a hack to get this parameter from the old stats package.
+namespace Statistics {
+bool PrintDescriptions = true;
+
+namespace Detail {
+struct SubData
+{
+ string name;
+ string desc;
+};
+
+struct StatData
+{
+ StatData();
+ ~StatData();
+
+ bool init;
+ bool print;
+ string name;
+ vector<SubData> *subdata;
+ string desc;
+ int precision;
+ FormatFlags flags;
+ const Stat *prereq;
+};
+
+StatData::StatData()
+ : init(false), print(false), subdata(NULL), precision(-1), flags(none),
+ prereq(NULL)
+{
+}
+
+StatData::~StatData()
+{
+ if (subdata)
+ delete subdata;
+}
+
+class Database
+{
+ private:
+ Database(const Database &) {}
+
+ private:
+ typedef list<Stat *> list_t;
+ typedef map<const Stat *, StatData *> map_t;
+
+ list_t allStats;
+ list_t printStats;
+ map_t map;
+
+ public:
+ Database();
+ ~Database();
+
+ void dump(ostream &stream);
+
+ StatData *find(const Stat *stat);
+ void check();
+ void regStat(Stat *stat);
+ StatData *print(Stat *stat);
+};
+
+Database::Database()
+{}
+
+Database::~Database()
+{}
+
+void
+Database::dump(ostream &stream)
+{
+ list_t::iterator i = printStats.begin();
+ list_t::iterator end = printStats.end();
+
+ while (i != end) {
+ Stat *stat = *i;
+ if (stat->dodisplay())
+ stat->display(stream);
+ ++i;
+ }
+}
+
+StatData *
+Database::find(const Stat *stat)
+{
+ map_t::const_iterator i = map.find(stat);
+
+ if (i == map.end())
+ return NULL;
+
+ return (*i).second;
+}
+
+void
+Database::check()
+{
+ list_t::iterator i = allStats.begin();
+ list_t::iterator end = allStats.end();
+
+ while (i != end) {
+ Stat *stat = *i;
+ StatData *data = find(stat);
+ if (!data || !data->init) {
+#ifdef STAT_DEBUG
+ cprintf("this is stat number %d\n",(*i)->number);
+#endif
+ panic("Not all stats have been initialized");
+ }
+
+ if (data->print) {
+ if (data->name.empty())
+ panic("all printable stats must be named");
+
+ list_t::iterator j = printStats.insert(printStats.end(), *i);
+ inplace_merge(printStats.begin(), j,
+ printStats.end(), Stat::less);
+ }
+
+ ++i;
+ }
+}
+
+void
+Database::regStat(Stat *stat)
+{
+ if (map.find(stat) != map.end())
+ panic("shouldn't register stat twice!");
+
+ allStats.push_back(stat);
+
+ StatData *data = new StatData;
+ bool success = (map.insert(make_pair(stat, data))).second;
+ assert(map.find(stat) != map.end());
+ assert(success && "this should never fail");
+}
+
+bool
+Stat::less(Stat *stat1, Stat *stat2)
+{
+ const string &name1 = stat1->myname();
+ const string &name2 = stat2->myname();
+
+ 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;
+}
+
+StatData *
+Database::print(Stat *stat)
+{
+ StatData *data = find(stat);
+ assert(data);
+
+ data->print = true;
+
+ return data;
+}
+
+Database &
+StatDB()
+{
+ static Database db;
+ return db;
+}
+
+Stat::Stat(bool reg)
+{
+#if 0
+ // This assert can help you find that pesky stat.
+ assert(this != (void *)0xbffff5c0);
+#endif
+
+ if (reg)
+ StatDB().regStat(this);
+#ifdef STAT_DEBUG
+ number = ++total_stats;
+ cprintf("I'm stat number %d\n",number);
+#endif
+}
+
+void
+Stat::setInit()
+{ mydata()->init = true; }
+
+StatData *
+Stat::mydata()
+{
+ StatData *data = StatDB().find(this);
+ assert(data);
+
+ return data;
+}
+
+const StatData *
+Stat::mydata() const
+{
+ StatData *data = StatDB().find(this);
+ assert(data);
+
+ return data;
+}
+
+const SubData *
+Stat::mysubdata(int index) const
+{
+ assert(index >= 0);
+ if (index >= size())
+ return NULL;
+
+ const StatData *data = this->mydata();
+ if (!data->subdata || data->subdata->size() <= index)
+ return NULL;
+
+ return &(*data->subdata)[index];
+}
+
+SubData *
+Stat::mysubdata_create(int index)
+{
+ int size = this->size();
+ assert(index >= 0 && (size == 0 || size > 0 && index < size));
+
+ StatData *data = this->mydata();
+ if (!data->subdata) {
+ if (!data->subdata) {
+ if (size == 0)
+ size = index + 1;
+
+ data->subdata = new vector<SubData>(size);
+ }
+ } else if (data->subdata->size() <= index)
+ data->subdata->resize(index + 1);
+
+ SubData *sd = &(*data->subdata)[index];
+ assert(sd);
+
+ return sd;
+}
+
+string
+Stat::myname() const
+{ return mydata()->name; }
+
+string
+Stat::mysubname(int index) const
+{
+ const SubData *sd = mysubdata(index);
+ return sd ? sd->name : "";
+}
+
+string
+Stat::mydesc() const
+{ return mydata()->desc; }
+
+string
+Stat::mysubdesc(int index) const
+{
+ const SubData *sd = mysubdata(index);
+ return sd ? sd->desc : "";
+}
+
+int
+Stat::myprecision() const
+{ return mydata()->precision; }
+
+FormatFlags
+Stat::myflags() const
+{ return mydata()->flags; }
+
+bool
+Stat::dodisplay() const
+{ return !mydata()->prereq || !mydata()->prereq->zero(); }
+
+StatData *
+Stat::print()
+{
+ StatData *data = StatDB().print(this);
+ assert(data && data->init);
+
+ return data;
+}
+
+Stat &
+Stat::name(const string &name)
+{
+ print()->name = name;
+ return *this;
+}
+
+Stat &
+Stat::desc(const string &desc)
+{
+ print()->desc = desc;
+ return *this;
+}
+
+Stat &
+Stat::precision(int precision)
+{
+ print()->precision = precision;
+ return *this;
+}
+
+Stat &
+Stat::flags(FormatFlags flags)
+{
+ if (flags & __reserved)
+ panic("Cannot set reserved flags!\n");
+
+ print()->flags |= flags;
+ return *this;
+}
+
+Stat &
+Stat::prereq(const Stat &prereq)
+{
+ print()->prereq = &prereq;
+ return *this;
+}
+
+Stat &
+Stat::subname(int index, const string &name)
+{
+ print();
+ mysubdata_create(index)->name = name;
+ return *this;
+}
+Stat &
+Stat::subdesc(int index, const string &desc)
+{
+ print();
+ mysubdata_create(index)->desc = desc;
+ return *this;
+}
+
+bool
+ScalarStat::zero() const
+{
+ return val() == 0.0;
+}
+
+bool
+VectorStat::zero() const
+{
+ return val()[0] == 0.0;
+}
+
+string
+ValueToString(result_t value, int precision)
+{
+ 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 {
+#ifndef STAT_DISPLAY_COMPAT
+ val << "no value";
+#else
+ val << "<err: div-0>";
+#endif
+ }
+
+ return val.str();
+}
+
+void
+PrintOne(ostream &stream, result_t value,
+ const string &name, const string &desc, int precision,
+ FormatFlags flags, result_t pdf = NAN, result_t cdf = NAN)
+{
+ 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);
+
+#ifdef STAT_DISPLAY_COMPAT
+ if (flags & __substat) {
+ ccprintf(stream, "%32s%12s%10s%10s", name,
+ ValueToString(value, precision),
+ pdfstr, cdfstr);
+ } else
+#endif
+ {
+ ccprintf(stream, "%-40s%12s%10s%10s", name,
+ ValueToString(value, precision), pdfstr, cdfstr);
+ }
+
+ if (PrintDescriptions) {
+ if (!desc.empty())
+ ccprintf(stream, " # %s", desc);
+ }
+ stream << endl;
+}
+
+void
+ScalarStat::display(ostream &stream) const
+{
+ PrintOne(stream, val(), myname(), mydesc(), myprecision(), myflags());
+}
+
+void
+VectorStat::display(ostream &stream) const
+{
+ bool have_subname = false;
+ bool have_subdesc = false;
+ int size = this->size();
+ for (int i = 0; i < size; ++i) {
+ if (!mysubname(i).empty())
+ have_subname = true;
+ if (!mysubdesc(i).empty())
+ have_subdesc = true;
+ }
+
+ vector<string> *subnames = 0;
+ vector<string> *subdescs = 0;
+ if (have_subname) {
+ subnames = new vector<string>(size);
+ for (int i = 0; i < size; ++i)
+ (*subnames)[i] = mysubname(i);
+ }
+ if (have_subdesc) {
+ subdescs = new vector<string>(size);
+ for (int i = 0; i < size; ++i)
+ (*subdescs)[i] = mysubdesc(i);
+ }
+
+ VectorDisplay(stream, myname(), subnames, mydesc(), subdescs,
+ myprecision(), myflags(), val(), total());
+}
+
+#ifndef STAT_DISPLAY_COMPAT
+#define NAMESEP "::"
+#else
+#define NAMESEP "_"
+#endif
+
+#ifndef STAT_DISPLAY_COMPAT
+void
+VectorDisplay(std::ostream &stream,
+ const std::string &myname,
+ const std::vector<std::string> *mysubnames,
+ const std::string &mydesc,
+ const std::vector<std::string> *mysubdescs,
+ int myprecision, FormatFlags myflags,
+ const rvec_t &vec, result_t mytotal)
+{
+ int _size = vec.size();
+ result_t _total = 0.0;
+ result_t _pdf, _cdf = 0.0;
+
+ if (myflags & (pdf | cdf)) {
+ for (int i = 0; i < _size; ++i) {
+ _total += vec[i];
+ }
+ }
+
+ if (_size == 1) {
+ PrintOne(stream, vec[0], myname, mydesc, myprecision, myflags);
+ } else {
+ for (int i = 0; i < _size; ++i) {
+ string subname;
+ if (mysubnames) {
+ subname = (*mysubnames)[i];
+ if (subname.empty())
+ continue;
+ } else {
+ subname = to_string(i);
+ }
+
+ string name = myname + NAMESEP + subname;
+ if (!(myflags & pdf))
+ PrintOne(stream, vec[i], name, mydesc, myprecision, myflags);
+ else {
+ _pdf = vec[i] / _total;
+ _cdf += _pdf;
+ PrintOne(stream, vec[i], name, mydesc, myprecision, myflags,
+ _pdf, _cdf);
+ }
+ }
+
+ if (myflags & total)
+ PrintOne(stream, mytotal, myname + NAMESEP + "total",
+ mydesc, myprecision, myflags);
+ }
+}
+#else
+void
+VectorDisplay(std::ostream &stream,
+ const std::string &myname,
+ const std::vector<std::string> *mysubnames,
+ const std::string &mydesc,
+ const std::vector<std::string> *mysubdescs,
+ int myprecision, FormatFlags myflags,
+ const rvec_t &vec, result_t mytotal)
+{
+ int _size = vec.size();
+ result_t _total = 0.0;
+ result_t _pdf, _cdf = 0.0;
+
+ if (myflags & (pdf | cdf)) {
+ for (int i = 0; i < _size; ++i) {
+ _total += vec[i];
+ }
+ }
+
+ if (_size == 1) {
+ PrintOne(stream, vec[0], myname, mydesc, myprecision, myflags);
+ } else {
+ if (myflags & total)
+ PrintOne(stream, mytotal, myname, mydesc, myprecision, myflags);
+
+ if (myflags & dist) {
+ ccprintf(stream, "%s.start_dist\n", myname);
+ for (int i = 0; i < _size; ++i) {
+ string subname, subdesc;
+ subname = to_string(i);
+ if (mysubnames) {
+ if (!subname.empty()) {
+ subname = (*mysubnames)[i];
+ }
+ }
+ if (mysubdescs) {
+ subdesc = (*mysubdescs)[i];
+ }
+ if (!(myflags & (pdf | cdf))) {
+ PrintOne(stream, vec[i], subname, subdesc, myprecision,
+ myflags | __substat);
+ } else {
+ if (_total) {
+ _pdf = vec[i] / _total;
+ _cdf += _pdf;
+ } else {
+ _pdf = _cdf = 0.0;
+ }
+ if (!(myflags & cdf)) {
+ PrintOne(stream, vec[i], subname, subdesc, myprecision,
+ myflags | __substat, _pdf);
+ } else {
+ PrintOne(stream, vec[i], subname, subdesc, myprecision,
+ myflags | __substat, _pdf, _cdf);
+ }
+ }
+ }
+ ccprintf(stream, "%s.end_dist\n", myname);
+ } else {
+ for (int i = 0; i < _size; ++i) {
+ string subname;
+ if (mysubnames) {
+ subname = (*mysubnames)[i];
+ if (subname.empty())
+ continue;
+ } else {
+ subname = to_string(i);
+ }
+
+ string name = myname + NAMESEP + subname;
+ if (!(myflags & pdf)) {
+ PrintOne(stream, vec[i], name, mydesc, myprecision,
+ myflags);
+ } else {
+ if (_total) {
+ _pdf = vec[i] / _total;
+ _cdf += _pdf;
+ } else {
+ _pdf = _cdf = 0.0;
+ }
+ _pdf = vec[i] / _total;
+ _cdf += _pdf;
+ PrintOne(stream, vec[i], name, mydesc, myprecision,
+ myflags, _pdf, _cdf);
+ }
+ }
+ }
+ }
+}
+#endif
+
+#ifndef STAT_DISPLAY_COMPAT
+void
+DistDisplay(ostream &stream, const string &name, const string &desc,
+ int precision, FormatFlags flags,
+ result_t min_val, result_t max_val,
+ result_t underflow, result_t overflow,
+ const rvec_t &vec, int min, int max, int bucket_size, int size);
+{
+ assert(size == vec.size());
+
+ result_t total = 0.0;
+ result_t pdf, cdf = 0.0;
+
+ total += underflow;
+ for (int i = 0; i < size; ++i)
+ total += vec[i];
+ total += overflow;
+
+ pdf = underflow / total;
+ cdf += pdf;
+
+ PrintOne(stream, underflow, name + NAMESEP + "underflow", desc,
+ precision, myflags, pdf, cdf);
+
+ for (int i = 0; i < size; ++i) {
+ stringstream namestr;
+ namestr << name;
+
+ int low = i * bucket_size + min;
+ int high = ::std::min((i + 1) * bucket_size + min - 1, max);
+ namestr << low;
+ if (low < high)
+ namestr << "-" << high;
+
+ pdf = vec[i] / total;
+ cdf += pdf;
+ PrintOne(stream, vec[i], namestr.str(), desc, precision, myflags,
+ pdf, cdf);
+ }
+
+ pdf = overflow / total;
+ cdf += pdf;
+ PrintOne(stream, overflow, name + NAMESEP + "overflow", desc,
+ precision, myflags, pdf, cdf);
+ PrintOne(stream, total, name + NAMESEP + "total", desc,
+ precision, myflags);
+}
+#else
+void
+DistDisplay(ostream &stream, const string &name, const string &desc,
+ int precision, FormatFlags flags,
+ result_t min_val, result_t max_val,
+ result_t underflow, result_t overflow,
+ const rvec_t &vec, int min, int max, int bucket_size, int size)
+{
+ assert(size == vec.size());
+ string blank;
+
+ result_t total = 0.0;
+
+ total += underflow;
+ for (int i = 0; i < size; ++i)
+ total += vec[i];
+ total += overflow;
+
+ ccprintf(stream, "%-42s", name + ".start_dist");
+ if (PrintDescriptions && !desc.empty())
+ ccprintf(stream, " # %s", desc);
+ stream << endl;
+
+ PrintOne(stream, total, name + ".samples", blank, precision, flags);
+ PrintOne(stream, min_val, name + ".min_value", blank, precision, flags);
+
+ if (underflow > 0)
+ PrintOne(stream, min_val, name + ".underflows", blank, precision,
+ flags);
+
+ int _min;
+ result_t _pdf, _cdf, mypdf, mycdf;
+
+ _cdf = 0.0;
+ for (int i = 0; i < size; ++i) {
+ if (flags & nozero && vec[i] == 0.0 ||
+ flags & nonan && isnan(vec[i]))
+ return;
+
+ _min = i * bucket_size + min;
+ _pdf = vec[i] / total * 100.0;
+ _cdf += _pdf;
+
+ mypdf = (flags & pdf) ? _pdf : NAN;
+ mycdf = (flags & cdf) ? _cdf : NAN;
+
+ PrintOne(stream, vec[i], ValueToString(_min, 0), blank, precision,
+ flags | __substat, mypdf, mycdf);
+ }
+
+ if (overflow > 0)
+ PrintOne(stream, overflow, name + ".overflows", blank, precision,
+ flags);
+ PrintOne(stream, max_val, name + ".max_value", blank, precision, flags);
+ ccprintf(stream, "%s.end_dist\n\n", name);
+}
+#endif
+
+void
+FancyDisplay(ostream &stream, const string &name, const string &desc,
+ int precision, FormatFlags flags, result_t mean,
+ result_t variance)
+{
+ result_t stdev = isnan(variance) ? NAN : sqrt(variance);
+ PrintOne(stream, mean, name + NAMESEP + "mean", desc, precision, flags);
+ PrintOne(stream, stdev, name + NAMESEP + "stdev", desc, precision, flags);
+}
+
+BinBase::BinBase(size_t size)
+ : memsize(CeilPow2(size)), mem(NULL)
+{
+}
+
+BinBase::~BinBase()
+{
+ if (mem)
+ delete [] mem;
+}
+
+char *
+BinBase::memory()
+{
+ if (!mem) {
+ mem = new char[memsize];
+ memset(mem, 0, memsize);
+ }
+
+ return mem;
+}
+
+} // namespace Detail
+
+void
+check()
+{
+ Detail::StatDB().check();
+}
+
+void
+dump(ostream &stream)
+{
+ Detail::StatDB().dump(stream);
+}
+
+} // namespace Statistics
diff --git a/base/statistics.hh b/base/statistics.hh
new file mode 100644
index 000000000..3d9d654ed
--- /dev/null
+++ b/base/statistics.hh
@@ -0,0 +1,1682 @@
+/*
+ * 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.
+ */
+
+/*
+ * @todo
+ *
+ * Generalized N-dimensinal vector
+ * documentation
+ * fix AvgStor
+ * key stats
+ * interval stats
+ * -- these both can use the same function that prints out a
+ * specific set of stats
+ * VectorStandardDeviation totals
+ *
+ */
+#ifndef __STATISTICS_HH__
+#define __STATISTICS_HH__
+
+#include <algorithm>
+#include <functional>
+#include <iosfwd>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <assert.h>
+
+#include "host.hh"
+#include "refcnt.hh"
+#include "str.hh"
+
+#ifndef NAN
+float __nan();
+#define NAN (__nan())
+#define __M5_NAN
+#endif
+
+#define STAT_DISPLAY_COMPAT
+
+extern Tick curTick;
+
+namespace Statistics {
+typedef double result_t;
+typedef std::vector<result_t> rvec_t;
+
+typedef u_int32_t FormatFlags;
+const FormatFlags none = 0x0000;
+const FormatFlags total = 0x0001;
+const FormatFlags pdf = 0x0002;
+const FormatFlags nozero = 0x0004;
+const FormatFlags nonan = 0x0008;
+const FormatFlags cdf = 0x0010;
+const FormatFlags dist = 0x0020;
+const FormatFlags __substat = 0x8000;
+const FormatFlags __reserved = __substat;
+
+namespace Detail {
+//////////////////////////////////////////////////////////////////////
+//
+// Statistics Framework Base classes
+//
+//////////////////////////////////////////////////////////////////////
+struct StatData;
+struct SubData;
+
+class Stat
+{
+ protected:
+ void setInit();
+ StatData *mydata();
+ const StatData *mydata() const;
+ StatData *print();
+ const SubData *mysubdata(int index) const;
+ SubData *mysubdata_create(int index);
+
+ public:
+ virtual std::string myname() const;
+ virtual std::string mysubname(int index) const;
+ virtual std::string mydesc() const;
+ virtual std::string mysubdesc(int index) const;
+ virtual FormatFlags myflags() const;
+ virtual bool dodisplay() const;
+ virtual int myprecision() const;
+
+ public:
+ Stat(bool reg);
+ virtual ~Stat() {}
+
+ virtual void display(std::ostream &stream) const = 0;
+ virtual size_t size() const = 0;
+ virtual bool zero() const = 0;
+
+ Stat &name(const std::string &name);
+ Stat &desc(const std::string &desc);
+ Stat &precision(int p);
+ Stat &flags(FormatFlags f);
+ Stat &prereq(const Stat &prereq);
+ Stat &subname(int index, const std::string &name);
+ Stat &subdesc(int index, const std::string &name);
+
+ public:
+ static bool less(Stat *stat1, Stat *stat2);
+
+#ifdef STAT_DEBUG
+ int number;
+#endif
+};
+
+// Scalar stats involved in formulas
+class ScalarStat : public Stat
+{
+ public:
+ ScalarStat(bool reg) : Stat(reg) {}
+ virtual result_t val() const = 0;
+ virtual bool zero() const;
+ virtual void display(std::ostream &stream) const;
+};
+
+void
+VectorDisplay(std::ostream &stream, const std::string &myname,
+ const std::vector<std::string> *mysubnames,
+ const std::string &mydesc,
+ const std::vector<std::string> *mysubdescs,
+ int myprecision, FormatFlags myflags, const rvec_t &vec,
+ result_t mytotal);
+
+// Vector stats involved in formulas
+class VectorStat : public Stat
+{
+ public:
+ VectorStat(bool reg) : Stat(reg) {}
+ virtual const rvec_t &val() const = 0;
+ virtual result_t total() const = 0;
+ virtual bool zero() const;
+ virtual void display(std::ostream &stream) const;
+};
+
+//////////////////////////////////////////////////////////////////////
+//
+// Simple Statistics
+//
+//////////////////////////////////////////////////////////////////////
+template <typename T>
+struct StatStor
+{
+ public:
+ struct Params { };
+
+ private:
+ T data;
+
+ public:
+ StatStor(const Params &) : data(T()) {}
+
+ void set(T val, const Params &p) { data = val; }
+ void inc(T val, const Params &p) { data += val; }
+ void dec(T val, const Params &p) { data -= val; }
+ result_t val(const Params &p) const { return (result_t)data; }
+ T value(const Params &p) const { return data; }
+};
+
+template <typename T>
+struct AvgStor
+{
+ public:
+ struct Params { };
+
+ private:
+ T current;
+ mutable result_t total;
+ mutable Tick last;
+
+ public:
+ AvgStor(const Params &) : current(T()), total(0), last(0) { }
+
+ void set(T val, const Params &p) {
+ total += current * (curTick - last);
+ last = curTick;
+ current = val;
+ }
+ void inc(T val, const Params &p) { set(current + val, p); }
+ void dec(T val, const Params &p) { set(current - val, p); }
+ result_t val(const Params &p) const {
+ total += current * (curTick - last);
+ last = curTick;
+ return (result_t)(total + current) / (result_t)(curTick + 1);
+ }
+ T value(const Params &p) const { return current; }
+};
+
+template <typename T, template <typename T> class Storage, class Bin>
+class ScalarBase : public ScalarStat
+{
+ protected:
+ typedef Storage<T> storage_t;
+ typedef typename storage_t::Params params_t;
+ typedef typename Bin::Bin<storage_t> bin_t;
+
+ protected:
+ bin_t bin;
+ params_t params;
+
+ protected:
+ storage_t *data() { return bin.data(params); }
+ const storage_t *data() const {
+ return (const_cast<bin_t *>(&bin))->data(params);
+ }
+
+ protected:
+ // Copying stats is not allowed
+ ScalarBase(const ScalarBase &stat);
+ const ScalarBase &operator=(const ScalarBase &);
+
+ public:
+ result_t val() const { return data()->val(params); }
+ T value() const { return data()->value(params); }
+
+ public:
+ ScalarBase() : ScalarStat(true) {
+ bin.init(params);
+ setInit();
+ }
+
+ public:
+ // Common operators for stats
+ void operator++() { data()->inc(1, params); }
+ void operator--() { data()->dec(1, params); }
+
+ void operator++(int) { ++*this; }
+ void operator--(int) { --*this; }
+
+ template <typename U>
+ void operator=(const U& v) { data()->set(v, params); }
+
+ template <typename U>
+ void operator+=(const U& v) { data()->inc(v, params); }
+
+ template <typename U>
+ void operator-=(const U& v) { data()->dec(v, params); }
+
+ virtual size_t size() const { return 1; }
+};
+
+//////////////////////////////////////////////////////////////////////
+//
+// Vector Statistics
+//
+//////////////////////////////////////////////////////////////////////
+template <typename T, template <typename T> class Storage, class Bin>
+class ScalarProxy;
+
+template <typename T, template <typename T> class Storage, class Bin>
+class VectorBase : public VectorStat
+{
+ protected:
+ typedef Storage<T> storage_t;
+ typedef typename storage_t::Params params_t;
+ typedef typename Bin::VectorBin<storage_t> bin_t;
+
+ private:
+ mutable rvec_t *vec;
+
+ protected:
+ bin_t bin;
+ params_t params;
+
+ protected:
+ storage_t *data(int index) { return bin.data(index, params); }
+ const storage_t *data(int index) const {
+ return (const_cast<bin_t *>(&bin))->data(index, params);
+ }
+
+ protected:
+ // Copying stats is not allowed
+ VectorBase(const VectorBase &stat);
+ const VectorBase &operator=(const VectorBase &);
+
+ public:
+ const rvec_t &val() const {
+ if (vec)
+ vec->resize(size());
+ else
+ vec = new rvec_t(size());
+
+ for (int i = 0; i < size(); ++i)
+ (*vec)[i] = data(i)->val(params);
+
+ return *vec;
+ }
+
+ result_t total() const {
+ result_t total = 0.0;
+ for (int i = 0; i < size(); ++i)
+ total += data(i)->val(params);
+ return total;
+ }
+
+ public:
+ VectorBase() : VectorStat(true), vec(NULL) {}
+ ~VectorBase() { if (vec) delete vec; }
+
+ VectorBase &init(size_t size) {
+ bin.init(size, params);
+ setInit();
+
+ return *this;
+ }
+
+ friend class ScalarProxy<T, Storage, Bin>;
+ ScalarProxy<T, Storage, Bin> operator[](int index);
+
+ virtual size_t size() const { return bin.size(); }
+};
+
+template <typename T, template <typename T> class Storage, class Bin>
+class ScalarProxy : public ScalarStat
+{
+ protected:
+ typedef Storage<T> storage_t;
+ typedef typename storage_t::Params params_t;
+ typedef typename Bin::VectorBin<storage_t> bin_t;
+
+ private:
+ bin_t *bin;
+ params_t *params;
+ int index;
+
+ protected:
+ storage_t *data() { return bin->data(index, *params); }
+ const storage_t *data() const { return bin->data(index, *params); }
+
+ public:
+ result_t val() const { return data()->val(*params); }
+ T value() const { return data()->value(*params); }
+
+ public:
+ ScalarProxy(bin_t &b, params_t &p, int i)
+ : ScalarStat(false), bin(&b), params(&p), index(i) {}
+ ScalarProxy(const ScalarProxy &sp)
+ : ScalarStat(false), bin(sp.bin), params(sp.params), index(sp.index) {}
+ const ScalarProxy &operator=(const ScalarProxy &sp) {
+ bin = sp.bin;
+ params = sp.params;
+ index = sp.index;
+ return *this;
+ }
+
+ public:
+ // Common operators for stats
+ void operator++() { data()->inc(1, *params); }
+ void operator--() { data()->dec(1, *params); }
+
+ void operator++(int) { ++*this; }
+ void operator--(int) { --*this; }
+
+ template <typename U>
+ void operator=(const U& v) { data()->set(v, *params); }
+
+ template <typename U>
+ void operator+=(const U& v) { data()->inc(v, *params); }
+
+ template <typename U>
+ void operator-=(const U& v) { data()->dec(v, *params); }
+
+ virtual size_t size() const { return 1; }
+};
+
+template <typename T, template <typename T> class Storage, class Bin>
+inline ScalarProxy<T, Storage, Bin>
+VectorBase<T, Storage, Bin>::operator[](int index)
+{
+ assert (index >= 0 && index < size());
+ return ScalarProxy<T, Storage, Bin>(bin, params, index);
+}
+
+template <typename T, template <typename T> class Storage, class Bin>
+class VectorProxy;
+
+template <typename T, template <typename T> class Storage, class Bin>
+class Vector2dBase : public Stat
+{
+ protected:
+ typedef Storage<T> storage_t;
+ typedef typename storage_t::Params params_t;
+ typedef typename Bin::VectorBin<storage_t> bin_t;
+
+ protected:
+ size_t x;
+ size_t y;
+ bin_t bin;
+ params_t params;
+ std::vector<std::string> *y_subnames;
+
+ protected:
+ storage_t *data(int index) { return bin.data(index, params); }
+ const storage_t *data(int index) const {
+ return (const_cast<bin_t *>(&bin))->data(index, params);
+ }
+
+ protected:
+ // Copying stats is not allowed
+ Vector2dBase(const Vector2dBase &stat);
+ const Vector2dBase &operator=(const Vector2dBase &);
+
+ public:
+ Vector2dBase() : Stat(true) {}
+ ~Vector2dBase() { }
+
+ Vector2dBase &init(size_t _x, size_t _y) {
+ x = _x;
+ y = _y;
+ bin.init(x * y, params);
+ setInit();
+ y_subnames = new std::vector<std::string>(y);
+
+ return *this;
+ }
+
+ /**
+ * This makes the assumption that if you're gonna subnames a 2d vector,
+ * you're subnaming across all y
+ */
+ Vector2dBase &ysubnames(const char **names)
+ {
+ for (int i=0; i < y; ++i) {
+ (*y_subnames)[i] = names[i];
+ }
+ return *this;
+ }
+ Vector2dBase &ysubname(int index, const std::string subname)
+ {
+ (*y_subnames)[i] = subname.c_str();
+ return *this;
+ }
+ std::string ysubname(int i) const { return (*y_subnames)[i]; }
+
+ friend class VectorProxy<T, Storage, Bin>;
+ VectorProxy<T, Storage, Bin> operator[](int index);
+
+ virtual size_t size() const { return bin.size(); }
+ virtual bool zero() const { return data(0)->value(params) == 0.0; }
+
+ virtual void
+ display(std::ostream &out) const
+ {
+ bool have_subname = false;
+ for (int i = 0; i < x; ++i) {
+ if (!mysubname(i).empty())
+ have_subname = true;
+ }
+
+ rvec_t tot_vec(y);
+ result_t super_total = 0.0;
+ for (int i = 0; i < x; ++i) {
+ std::string subname;
+ if (have_subname) {
+ subname = mysubname(i);
+ if (subname.empty())
+ continue;
+ } else
+ subname = to_string(i);
+
+ int iy = i * y;
+ rvec_t vec(y);
+
+ result_t total = 0.0;
+ for (int j = 0; j < y; ++j) {
+ vec[j] = data(iy + j)->val(params);
+ tot_vec[j] += vec[j];
+ total += vec[j];
+ super_total += vec[j];
+ }
+
+ std::string desc;
+ if (mysubdesc(i).empty()) {
+ desc = mydesc();
+ } else {
+ desc = mysubdesc(i);
+ }
+
+ VectorDisplay(out, myname() + "_" + subname, y_subnames, desc, 0,
+ myprecision(), myflags(), vec, total);
+
+ }
+ if ((myflags() & ::Statistics::total) && (x > 1)) {
+ VectorDisplay(out, myname(), y_subnames, mydesc(), 0,
+ myprecision(), myflags(), tot_vec, super_total);
+
+ }
+ }
+};
+
+template <typename T, template <typename T> class Storage, class Bin>
+class VectorProxy : public VectorStat
+{
+ protected:
+ typedef Storage<T> storage_t;
+ typedef typename storage_t::Params params_t;
+ typedef typename Bin::VectorBin<storage_t> bin_t;
+
+ private:
+ bin_t *bin;
+ params_t *params;
+ int offset;
+ int len;
+
+ private:
+ mutable rvec_t *vec;
+
+ storage_t *data(int index) {
+ assert(index < len);
+ return bin->data(offset + index, *params);
+ }
+
+ const storage_t *data(int index) const {
+ return (const_cast<bin_t *>(bin))->data(offset + index, *params);
+ }
+
+ public:
+ const rvec_t &val() const {
+ if (vec)
+ vec->resize(size());
+ else
+ vec = new rvec_t(size());
+
+ for (int i = 0; i < size(); ++i)
+ (*vec)[i] = data(i)->val(*params);
+
+ return *vec;
+ }
+
+ result_t total() const {
+ result_t total = 0.0;
+ for (int i = 0; i < size(); ++i)
+ total += data(i)->val(*params);
+ return total;
+ }
+
+ public:
+ VectorProxy(bin_t &b, params_t &p, int o, int l)
+ : VectorStat(false), bin(&b), params(&p), offset(o), len(l), vec(NULL)
+ { }
+ VectorProxy(const VectorProxy &sp)
+ : VectorStat(false), bin(sp.bin), params(sp.params), offset(sp.offset),
+ len(sp.len), 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;
+ if (vec)
+ delete vec;
+ vec = NULL;
+ return *this;
+ }
+
+ virtual size_t size() const { return len; }
+
+ ScalarProxy<T, Storage, Bin> operator[](int index) {
+ assert (index >= 0 && index < size());
+ return ScalarProxy<T, Storage, Bin>(*bin, *params, offset + index);
+ }
+};
+
+template <typename T, template <typename T> class Storage, class Bin>
+inline VectorProxy<T, Storage, Bin>
+Vector2dBase<T, Storage, Bin>::operator[](int index)
+{
+ int offset = index * y;
+ assert (index >= 0 && offset < size());
+ return VectorProxy<T, Storage, Bin>(bin, params, offset, y);
+}
+
+//////////////////////////////////////////////////////////////////////
+//
+// Non formula statistics
+//
+//////////////////////////////////////////////////////////////////////
+
+void DistDisplay(std::ostream &stream, const std::string &name,
+ const std::string &desc, int precision, FormatFlags flags,
+ result_t min_val, result_t max_val,
+ result_t underflow, result_t overflow,
+ const rvec_t &vec, int min, int max, int bucket_size,
+ int size);
+
+template <typename T>
+struct DistStor
+{
+ public:
+ struct Params
+ {
+ int min;
+ int max;
+ int bucket_size;
+ int size;
+ };
+
+ private:
+ T min_val;
+ T max_val;
+ T underflow;
+ T overflow;
+ std::vector<T> vec;
+
+ public:
+ DistStor(const Params &params)
+ : min_val(INT_MAX), max_val(INT_MIN), underflow(0), overflow(0),
+ vec(params.size) {
+ }
+ void sample(T val, int number, const Params &params) {
+ if (val < params.min)
+ underflow += number;
+ else if (val > params.max)
+ overflow += number;
+ else {
+ int index = (val - params.min) / params.bucket_size;
+ assert(index < size(params));
+ vec[index] += number;
+ }
+
+ if (val < min_val)
+ min_val = val;
+
+ if (val > max_val)
+ max_val = val;
+ }
+
+ size_t size(const Params &) const { return vec.size(); }
+
+ bool zero(const Params &params) const {
+ if (underflow != 0 || overflow != 0)
+ return true;
+
+ int s = size(params);
+ for (int i = 0; i < s; i++)
+ if (vec[i] != 0)
+ return true;
+
+ return false;
+ }
+
+ void display(std::ostream &stream, const std::string &name,
+ const std::string &desc, int precision, FormatFlags flags,
+ const Params &params) const {
+
+#ifdef STAT_DISPLAY_COMPAT
+ result_t min = params.min;
+#else
+ result_t min = (min_val == INT_MAX) ? params.min : min_val;
+#endif
+ result_t max = (max_val == INT_MIN) ? 0 : max_val;
+
+ rvec_t rvec(params.size);
+ for (int i = 0; i < params.size; ++i)
+ rvec[i] = vec[i];
+
+ DistDisplay(stream, name, desc, precision, flags,
+ (result_t)min, (result_t)max,
+ (result_t)underflow, (result_t)overflow,
+ rvec, params.min, params.max, params.bucket_size,
+ params.size);
+ }
+};
+
+void FancyDisplay(std::ostream &stream, const std::string &name,
+ const std::string &desc, int precision, FormatFlags flags,
+ result_t mean, result_t variance);
+template <typename T>
+struct FancyStor
+{
+ public:
+ struct Params {};
+
+ private:
+ T sum;
+ T squares;
+ int total;
+
+ public:
+ FancyStor(const Params &) : sum(0), squares(0), total(0) {}
+
+ void sample(T val, int number, const Params &) {
+ T value = val * number;
+ sum += value;
+ squares += value * value;
+ total += number;
+ }
+ void display(std::ostream &stream, const std::string &name,
+ const std::string &desc, int precision, FormatFlags flags,
+ const Params &) const {
+
+ result_t mean = NAN;
+ result_t variance = NAN;
+
+ if (total != 0) {
+ result_t fsum = sum;
+ result_t fsq = squares;
+ result_t ftot = total;
+
+ mean = fsum / ftot;
+ variance = (ftot * fsq - (fsum * fsum)) / (ftot * (ftot - 1.0));
+ }
+
+ FancyDisplay(stream, name, desc, precision, flags, mean, variance);
+ }
+
+ size_t size(const Params &) const { return 1; }
+ bool zero(const Params &) const { return total == 0; }
+};
+
+template <typename T>
+struct AvgFancy
+{
+ public:
+ struct Params {};
+
+ private:
+ T sum;
+ T squares;
+
+ public:
+ AvgFancy(const Params &) : sum(0), squares(0) {}
+
+ void sample(T val, int number, const Params& p) {
+ T value = val * number;
+ sum += value;
+ squares += value * value;
+ }
+ void display(std::ostream &stream, const std::string &name,
+ const std::string &desc, int precision, FormatFlags flags,
+ const Params &params) const {
+ result_t mean = sum / curTick;
+ result_t variance = (squares - sum * sum) / curTick;
+
+ FancyDisplay(stream, name, desc, precision, flags, mean, variance);
+ }
+
+ size_t size(const Params &params) const { return 1; }
+ bool zero(const Params &params) const { return sum == 0; }
+};
+
+template <typename T, template <typename T> class Storage, class Bin>
+class DistBase : public Stat
+{
+ protected:
+ typedef Storage<T> storage_t;
+ typedef typename storage_t::Params params_t;
+ typedef typename Bin::Bin<storage_t> bin_t;
+
+ protected:
+ bin_t bin;
+ params_t params;
+
+ protected:
+ storage_t *data() { return bin.data(params); }
+ const storage_t *data() const {
+ return (const_cast<bin_t *>(&bin))->data(params);
+ }
+
+ protected:
+ // Copying stats is not allowed
+ DistBase(const DistBase &stat);
+ const DistBase &operator=(const DistBase &);
+
+ public:
+ DistBase() : Stat(true) { }
+ ~DistBase() { }
+
+ template <typename U>
+ void sample(const U& v, int n = 1) { data()->sample(v, n, params); }
+
+ virtual size_t size() const { return data()->size(params); }
+ virtual bool zero() const { return data()->zero(params); }
+ virtual void display(std::ostream &stream) const {
+ data()->display(stream, myname(), mydesc(), myprecision(), myflags(),
+ params);
+ }
+};
+
+template <typename T, template <typename T> class Storage, class Bin>
+class VectorDistProxy;
+
+template <typename T, template <typename T> class Storage, class Bin>
+class VectorDistBase : public Stat
+{
+ protected:
+ typedef Storage<T> storage_t;
+ typedef typename storage_t::Params params_t;
+ typedef typename Bin::VectorBin<storage_t> bin_t;
+
+ protected:
+ bin_t bin;
+ params_t params;
+
+ protected:
+ storage_t *data(int index) { return bin.data(index, params); }
+ const storage_t *data(int index) const {
+ return (const_cast<bin_t *>(&bin))->data(index, params);
+ }
+
+ protected:
+ // Copying stats is not allowed
+ VectorDistBase(const VectorDistBase &stat);
+ const VectorDistBase &operator=(const VectorDistBase &);
+
+ public:
+ VectorDistBase() : Stat(true) { }
+ ~VectorDistBase() { }
+
+ friend class VectorDistProxy<T, Storage, Bin>;
+ VectorDistProxy<T, Storage, Bin> operator[](int index);
+ const VectorDistProxy<T, Storage, Bin> operator[](int index) const;
+
+ virtual size_t size() const { return bin.size(); }
+ virtual bool zero() const { return false; }
+ virtual void display(std::ostream &stream) const;
+};
+
+template <typename T, template <typename T> class Storage, class Bin>
+class VectorDistProxy : public Stat
+{
+ protected:
+ typedef Storage<T> storage_t;
+ typedef typename storage_t::Params params_t;
+ typedef typename Bin::Bin<storage_t> bin_t;
+ typedef VectorDistBase<T, Storage, Bin> base_t;
+
+ private:
+ union {
+ base_t *stat;
+ const base_t *cstat;
+ };
+ int index;
+
+ protected:
+ storage_t *data() { return stat->data(index); }
+ const storage_t *data() const { return cstat->data(index); }
+
+ public:
+ VectorDistProxy(const VectorDistBase<T, Storage, Bin> &s, int i)
+ : Stat(false), cstat(&s), index(i) {}
+ VectorDistProxy(const VectorDistProxy &sp)
+ : Stat(false), cstat(sp.cstat), index(sp.index) {}
+ const VectorDistProxy &operator=(const VectorDistProxy &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); }
+
+ virtual size_t size() const { return 1; }
+ virtual bool zero() const {
+ return data()->zero(cstat->params);
+ }
+ virtual void display(std::ostream &stream) const {
+ std::stringstream name, desc;
+
+ if (!(cstat->mysubname(index).empty())) {
+ name << cstat->myname() << cstat->mysubname(index);
+ } else {
+ name << cstat->myname() << "_" << index;
+ }
+ if (!(cstat->mysubdesc(index).empty())) {
+ desc << cstat->mysubdesc(index);
+ } else {
+ desc << cstat->mydesc();
+ }
+
+ data()->display(stream, name.str(), desc.str(),
+ cstat->myprecision(), cstat->myflags(), cstat->params);
+ }
+};
+
+template <typename T, template <typename T> class Storage, class Bin>
+inline VectorDistProxy<T, Storage, Bin>
+VectorDistBase<T, Storage, Bin>::operator[](int index)
+{
+ assert (index >= 0 && index < size());
+ return VectorDistProxy<T, Storage, Bin>(*this, index);
+}
+
+template <typename T, template <typename T> class Storage, class Bin>
+inline const VectorDistProxy<T, Storage, Bin>
+VectorDistBase<T, Storage, Bin>::operator[](int index) const
+{
+ assert (index >= 0 && index < size());
+ return VectorDistProxy<T, Storage, Bin>(*this, index);
+}
+
+/**
+ * @todo Need a way to print Distribution totals across the Vector
+ */
+template <typename T, template <typename T> class Storage, class Bin>
+void
+VectorDistBase<T, Storage, Bin>::display(std::ostream &stream) const
+{
+ for (int i = 0; i < size(); ++i) {
+ VectorDistProxy<T, Storage, Bin> proxy(*this, i);
+ proxy.display(stream);
+ }
+}
+
+#if 0
+result_t
+VectorDistBase<T, Storage, Bin>::total(int index) const
+{
+ int total = 0;
+ for (int i=0; i < x_size(); ++i) {
+ total += data(i)->val(*params);
+ }
+}
+#endif
+
+//////////////////////////////////////////////////////////////////////
+//
+// Formula Details
+//
+//////////////////////////////////////////////////////////////////////
+class Node : public RefCounted
+{
+ public:
+ virtual size_t size() const = 0;
+ virtual const rvec_t &val() const = 0;
+ virtual result_t total() const = 0;
+};
+
+typedef RefCountingPtr<Node> NodePtr;
+
+class ScalarStatNode : public Node
+{
+ private:
+ const ScalarStat &stat;
+ mutable rvec_t result;
+
+ public:
+ ScalarStatNode(const ScalarStat &s) : stat(s), result(1) {}
+ const rvec_t &val() const { result[0] = stat.val(); return result; }
+ virtual result_t total() const { return stat.val(); };
+
+ virtual size_t size() const { return 1; }
+};
+
+template <typename T, template <typename T> class Storage, class Bin>
+class ScalarProxyNode : public Node
+{
+ private:
+ const ScalarProxy<T, Storage, Bin> proxy;
+ mutable rvec_t result;
+
+ public:
+ ScalarProxyNode(const ScalarProxy<T, Storage, Bin> &p)
+ : proxy(p), result(1) { }
+ const rvec_t &val() const { result[0] = proxy.val(); return result; }
+ virtual result_t total() const { return proxy.val(); };
+
+ virtual size_t size() const { return 1; }
+};
+
+class VectorStatNode : public Node
+{
+ private:
+ const VectorStat &stat;
+
+ public:
+ VectorStatNode(const VectorStat &s) : stat(s) {}
+ const rvec_t &val() const { return stat.val(); }
+ virtual result_t total() const { return stat.total(); };
+
+ virtual size_t size() const { return stat.size(); }
+};
+
+template <typename T>
+class ConstNode : public Node
+{
+ private:
+ rvec_t data;
+
+ public:
+ ConstNode(T s) : data(1, (result_t)s) {}
+ const rvec_t &val() const { return data; }
+ virtual result_t total() const { return data[0]; };
+
+ virtual size_t size() const { return 1; }
+};
+
+template <typename T>
+class FunctorNode : public Node
+{
+ private:
+ T &functor;
+ mutable rvec_t result;
+
+ public:
+ FunctorNode(T &f) : functor(f) { result.resize(1); }
+ const rvec_t &val() const {
+ result[0] = (result_t)functor();
+ return result;
+ }
+ virtual result_t total() const { return (result_t)functor(); };
+
+ virtual size_t size() const { return 1; }
+};
+
+template <typename T>
+class ScalarNode : public Node
+{
+ private:
+ T &scalar;
+ mutable rvec_t result;
+
+ public:
+ ScalarNode(T &s) : scalar(s) { result.resize(1); }
+ const rvec_t &val() const {
+ result[0] = (result_t)scalar;
+ return result;
+ }
+ virtual result_t total() const { return (result_t)scalar; };
+
+ virtual size_t size() const { return 1; }
+};
+
+template <class Op>
+class UnaryNode : public Node
+{
+ public:
+ NodePtr l;
+ mutable rvec_t result;
+
+ public:
+ UnaryNode(NodePtr p) : l(p) {}
+
+ const rvec_t &val() const {
+ const rvec_t &lvec = l->val();
+ int size = lvec.size();
+
+ assert(size > 0);
+
+ result.resize(size);
+ Op op;
+ for (int i = 0; i < size; ++i)
+ result[i] = op(lvec[i]);
+
+ return result;
+ }
+
+ result_t total() const {
+ Op op;
+ return op(l->total());
+ }
+
+ virtual size_t size() const { return l->size(); }
+};
+
+template <class Op>
+class BinaryNode : public Node
+{
+ public:
+ NodePtr l;
+ NodePtr r;
+ mutable rvec_t result;
+
+ public:
+ BinaryNode(NodePtr a, NodePtr b) : l(a), r(b) {}
+
+ const rvec_t &val() const {
+ Op op;
+ const rvec_t &lvec = l->val();
+ const rvec_t &rvec = r->val();
+
+ assert(lvec.size() > 0 && rvec.size() > 0);
+
+ if (lvec.size() == 1 && rvec.size() == 1) {
+ result.resize(1);
+ result[0] = op(lvec[0], rvec[0]);
+ } else if (lvec.size() == 1) {
+ int size = rvec.size();
+ result.resize(size);
+ for (int i = 0; i < size; ++i)
+ result[i] = op(lvec[0], rvec[i]);
+ } else if (rvec.size() == 1) {
+ int size = lvec.size();
+ result.resize(size);
+ for (int i = 0; i < size; ++i)
+ result[i] = op(lvec[i], rvec[0]);
+ } else if (rvec.size() == lvec.size()) {
+ int size = rvec.size();
+ result.resize(size);
+ for (int i = 0; i < size; ++i)
+ result[i] = op(lvec[i], rvec[i]);
+ }
+
+ return result;
+ }
+
+ result_t 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;
+ }
+ }
+};
+
+template <class Op>
+class SumNode : public Node
+{
+ public:
+ NodePtr l;
+ mutable rvec_t result;
+
+ public:
+ SumNode(NodePtr p) : l(p), result(1) {}
+
+ const rvec_t &val() const {
+ const rvec_t &lvec = l->val();
+ int size = lvec.size();
+ assert(size > 0);
+
+ result[0] = 0.0;
+
+ Op op;
+ for (int i = 0; i < size; ++i)
+ result[0] = op(result[0], lvec[i]);
+
+ return result;
+ }
+
+ result_t total() const {
+ const rvec_t &lvec = l->val();
+ int size = lvec.size();
+ assert(size > 0);
+
+ result_t result = 0.0;
+
+ Op op;
+ for (int i = 0; i < size; ++i)
+ result = op(result, lvec[i]);
+
+ return result;
+ }
+
+ virtual size_t size() const { return 1; }
+};
+
+class Temp
+{
+ private:
+ NodePtr node;
+
+ public:
+ Temp(NodePtr n) : node(n) {}
+ Temp(const ScalarStat &s) : node(new ScalarStatNode(s)) {}
+ template <typename T, template <typename T> class Storage, class Bin>
+ Temp(const ScalarProxy<T, Storage, Bin> &p)
+ : node(new ScalarProxyNode<T, Storage, Bin>(p)) {}
+ Temp(const VectorStat &s) : node(new VectorStatNode(s)) {}
+
+#define TempSCALAR(T) \
+ Temp(T value) : node(new ConstNode<T>(value)) {}
+
+ TempSCALAR( signed char);
+ TempSCALAR(unsigned char);
+ TempSCALAR( signed short);
+ TempSCALAR(unsigned short);
+ TempSCALAR( signed int);
+ TempSCALAR(unsigned int);
+ TempSCALAR( signed long);
+ TempSCALAR(unsigned long);
+ TempSCALAR( signed long long);
+ TempSCALAR(unsigned long long);
+ TempSCALAR(float);
+ TempSCALAR(double);
+#undef TempSCALAR
+
+ operator NodePtr() { return node;}
+};
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Binning Interface
+//
+//////////////////////////////////////////////////////////////////////
+
+class BinBase
+{
+ private:
+ off_t memsize;
+ char *mem;
+
+ protected:
+ off_t size() const { return memsize; }
+ char *memory();
+
+ public:
+ BinBase(size_t size);
+ ~BinBase();
+};
+
+} // namespace Detail
+
+template <class BinType>
+struct StatBin : public Detail::BinBase
+{
+ static StatBin *&curBin() {
+ static StatBin *current = NULL;
+ return current;
+ }
+
+ static void setCurBin(StatBin *bin) { curBin() = bin; }
+ static StatBin *current() { assert(curBin()); return curBin(); }
+
+ static off_t &offset() {
+ static off_t offset = 0;
+ return offset;
+ }
+
+ static off_t new_offset(size_t size) {
+ size_t mask = sizeof(u_int64_t) - 1;
+ off_t off = offset();
+
+ // That one is for the last trailing flags byte.
+ offset() += (size + 1 + mask) & ~mask;
+
+ return off;
+ }
+
+ explicit StatBin(size_t size = 1024) : Detail::BinBase(size) {}
+
+ char *memory(off_t off) {
+ assert(offset() <= size());
+ return Detail::BinBase::memory() + off;
+ }
+
+ static void activate(StatBin &bin) { setCurBin(&bin); }
+
+ class BinBase
+ {
+ private:
+ int offset;
+
+ public:
+ BinBase() : offset(-1) {}
+ void allocate(size_t size) {
+ offset = new_offset(size);
+ }
+ char *access() {
+ assert(offset != -1);
+ return current()->memory(offset);
+ }
+ };
+
+ template <class Storage>
+ class Bin : public BinBase
+ {
+ public:
+ typedef typename Storage::Params Params;
+
+ public:
+ Bin() { allocate(sizeof(Storage)); }
+ bool initialized() const { return true; }
+ void init(const Params &params) { }
+
+ int size() const { return 1; }
+
+ Storage *data(const Params &params) {
+ assert(initialized());
+ char *ptr = access();
+ char *flags = ptr + sizeof(Storage);
+ if (!(*flags & 0x1)) {
+ *flags |= 0x1;
+ new (ptr) Storage(params);
+ }
+ return reinterpret_cast<Storage *>(ptr);
+ }
+ };
+
+ template <class Storage>
+ class VectorBin : public BinBase
+ {
+ public:
+ typedef typename Storage::Params Params;
+
+ private:
+ int _size;
+
+ public:
+ VectorBin() : _size(0) {}
+
+ bool initialized() const { return _size > 0; }
+ void init(int s, const Params &params) {
+ assert(!initialized());
+ assert(s > 0);
+ _size = s;
+ allocate(_size * sizeof(Storage));
+ }
+
+ int size() const { return _size; }
+
+ Storage *data(int index, const Params &params) {
+ assert(initialized());
+ assert(index >= 0 && index < size());
+ char *ptr = access();
+ char *flags = ptr + size() * sizeof(Storage);
+ if (!(*flags & 0x1)) {
+ *flags |= 0x1;
+ for (int i = 0; i < size(); ++i)
+ new (ptr + i * sizeof(Storage)) Storage(params);
+ }
+ return reinterpret_cast<Storage *>(ptr + index * sizeof(Storage));
+ }
+ };
+};
+
+class MainBinType {};
+typedef StatBin<MainBinType> MainBin;
+
+struct NoBin
+{
+ template <class Storage>
+ struct Bin
+ {
+ public:
+ typedef typename Storage::Params Params;
+
+ private:
+ char ptr[sizeof(Storage)];
+
+ public:
+ bool initialized() const { return true; }
+ void init(const Params &params) {
+ new (ptr) Storage(params);
+ }
+ int size() const{ return 1; }
+ Storage *data(const Params &params) {
+ assert(initialized());
+ return reinterpret_cast<Storage *>(ptr);
+ }
+ };
+
+ template <class Storage>
+ struct VectorBin
+ {
+ public:
+ typedef typename Storage::Params Params;
+
+ private:
+ char *ptr;
+ int _size;
+
+ public:
+ VectorBin() : ptr(NULL) { }
+ ~VectorBin() {
+ if (initialized())
+ delete [] ptr;
+ }
+ bool initialized() const { return ptr != NULL; }
+ void init(int s, const Params &params) {
+ assert(s > 0 && "size must be positive!");
+ assert(!initialized());
+ _size = s;
+ ptr = new char[_size * sizeof(Storage)];
+ for (int i = 0; i < _size; ++i)
+ new (ptr + i * sizeof(Storage)) Storage(params);
+ }
+
+ int size() const { return _size; }
+
+ Storage *data(int index, const Params &params) {
+ assert(initialized());
+ assert(index >= 0 && index < size());
+ return reinterpret_cast<Storage *>(ptr + index * sizeof(Storage));
+ }
+ };
+};
+
+//////////////////////////////////////////////////////////////////////
+//
+// Visible Statistics Types
+//
+//////////////////////////////////////////////////////////////////////
+template <typename T = Counter, class Bin = NoBin>
+class Scalar : public Detail::ScalarBase<T, Detail::StatStor, Bin>
+{
+ public:
+ typedef Detail::ScalarBase<T, Detail::StatStor, Bin> Base;
+
+ template <typename U>
+ void operator=(const U& v) { Base::operator=(v); }
+};
+
+template <typename T = Counter, class Bin = NoBin>
+class Average : public Detail::ScalarBase<T, Detail::AvgStor, Bin>
+{
+ public:
+ typedef Detail::ScalarBase<T, Detail::AvgStor, Bin> Base;
+
+ template <typename U>
+ void operator=(const U& v) { Base::operator=(v); }
+};
+
+template <typename T = Counter, class Bin = NoBin>
+class Vector : public Detail::VectorBase<T, Detail::StatStor, Bin>
+{ };
+
+template <typename T = Counter, class Bin = NoBin>
+class AverageVector : public Detail::VectorBase<T, Detail::AvgStor, Bin>
+{ };
+
+template <typename T = Counter, class Bin = NoBin>
+class Vector2d : public Detail::Vector2dBase<T, Detail::StatStor, Bin>
+{ };
+
+template <typename T = Counter, class Bin = NoBin>
+class Distribution : public Detail::DistBase<T, Detail::DistStor, Bin>
+{
+ private:
+ typedef Detail::DistBase<T, Detail::DistStor, Bin> Base;
+ typedef typename Detail::DistStor<T>::Params Params;
+
+ public:
+ Distribution &init(T min, T max, int bkt) {
+ params.min = min;
+ params.max = max;
+ params.bucket_size = bkt;
+ params.size = (max - min) / bkt + 1;
+ bin.init(params);
+ setInit();
+
+ return *this;
+ }
+};
+
+template <typename T = Counter, class Bin = NoBin>
+class StandardDeviation : public Detail::DistBase<T, Detail::FancyStor, Bin>
+{
+ private:
+ typedef Detail::DistBase<T, Detail::DistStor, Bin> Base;
+ typedef typename Detail::DistStor<T>::Params Params;
+
+ public:
+ StandardDeviation() {
+ bin.init(params);
+ setInit();
+ }
+};
+
+template <typename T = Counter, class Bin = NoBin>
+class AverageDeviation : public Detail::DistBase<T, Detail::AvgFancy, Bin>
+{
+ private:
+ typedef Detail::DistBase<T, Detail::DistStor, Bin> Base;
+ typedef typename Detail::DistStor<T>::Params Params;
+
+ public:
+ AverageDeviation() {
+ bin.init(params);
+ setInit();
+ }
+};
+
+template <typename T = Counter, class Bin = NoBin>
+class VectorDistribution
+ : public Detail::VectorDistBase<T, Detail::DistStor, Bin>
+{
+ private:
+ typedef Detail::VectorDistBase<T, Detail::DistStor, Bin> Base;
+ typedef typename Detail::DistStor<T>::Params Params;
+
+ public:
+ VectorDistribution &init(int size, T min, T max, int bkt) {
+ params.min = min;
+ params.max = max;
+ params.bucket_size = bkt;
+ params.size = (max - min) / bkt + 1;
+ bin.init(size, params);
+ setInit();
+
+ return *this;
+ }
+};
+
+template <typename T = Counter, class Bin = NoBin>
+class VectorStandardDeviation
+ : public Detail::VectorDistBase<T, Detail::FancyStor, Bin>
+{
+ private:
+ typedef Detail::VectorDistBase<T, Detail::FancyStor, Bin> Base;
+ typedef typename Detail::DistStor<T>::Params Params;
+
+ public:
+ VectorStandardDeviation &init(int size) {
+ bin.init(size, params);
+ setInit();
+
+ return *this;
+ }
+};
+
+template <typename T = Counter, class Bin = NoBin>
+class VectorAverageDeviation
+ : public Detail::VectorDistBase<T, Detail::AvgFancy, Bin>
+{
+ private:
+ typedef Detail::VectorDistBase<T, Detail::AvgFancy, Bin> Base;
+ typedef typename Detail::DistStor<T>::Params Params;
+
+ public:
+ VectorAverageDeviation &init(int size) {
+ bin.init(size, params);
+ setInit();
+
+ return *this;
+ }
+};
+
+class Formula : public Detail::VectorStat
+{
+ private:
+ Detail::NodePtr root;
+ friend class Detail::Temp;
+
+ public:
+ Formula() : VectorStat(true) { setInit(); }
+ Formula(Detail::Temp r) : VectorStat(true) {
+ root = r;
+ assert(size());
+ }
+
+ const Formula &operator=(Detail::Temp r) {
+ assert(!root && "Can't change formulas");
+ root = r;
+ assert(size());
+ return *this;
+ }
+
+ const Formula &operator+=(Detail::Temp r) {
+ using namespace Detail;
+ if (root)
+ root = NodePtr(new BinaryNode<std::plus<result_t> >(root, r));
+ else
+ root = r;
+ assert(size());
+ return *this;
+ }
+
+ const rvec_t &val() const { return root->val(); }
+ result_t total() const { return root->total(); }
+
+ size_t size() const {
+ if (!root)
+ return 0;
+ else
+ return root->size();
+ }
+};
+
+void check();
+void dump(std::ostream &stream);
+
+inline Detail::Temp
+operator+(Detail::Temp l, Detail::Temp r)
+{
+ using namespace Detail;
+ return NodePtr(new BinaryNode<std::plus<result_t> >(l, r));
+}
+
+inline Detail::Temp
+operator-(Detail::Temp l, Detail::Temp r)
+{
+ using namespace Detail;
+ return NodePtr(new BinaryNode<std::minus<result_t> >(l, r));
+}
+
+inline Detail::Temp
+operator*(Detail::Temp l, Detail::Temp r)
+{
+ using namespace Detail;
+ return NodePtr(new BinaryNode<std::multiplies<result_t> >(l, r));
+}
+
+inline Detail::Temp
+operator/(Detail::Temp l, Detail::Temp r)
+{
+ using namespace Detail;
+ return NodePtr(new BinaryNode<std::divides<result_t> >(l, r));
+}
+
+inline Detail::Temp
+operator%(Detail::Temp l, Detail::Temp r)
+{
+ using namespace Detail;
+ return NodePtr(new BinaryNode<std::modulus<result_t> >(l, r));
+}
+
+inline Detail::Temp
+operator-(Detail::Temp l)
+{
+ using namespace Detail;
+ return NodePtr(new UnaryNode<std::negate<result_t> >(l));
+}
+
+template <typename T>
+inline Detail::Temp
+constant(T val)
+{
+ using namespace Detail;
+ return NodePtr(new ConstNode<T>(val));
+}
+
+template <typename T>
+inline Detail::Temp
+functor(T &val)
+{
+ using namespace Detail;
+ return NodePtr(new FunctorNode<T>(val));
+}
+
+template <typename T>
+inline Detail::Temp
+scalar(T &val)
+{
+ using namespace Detail;
+ return NodePtr(new ScalarNode<T>(val));
+}
+
+inline Detail::Temp
+sum(Detail::Temp val)
+{
+ using namespace Detail;
+ return NodePtr(new SumNode<std::plus<result_t> >(val));
+}
+
+extern bool PrintDescriptions;
+
+} // namespace statistics
+
+#endif // __STATISTICS_HH__
diff --git a/base/str.cc b/base/str.cc
new file mode 100644
index 000000000..f54729813
--- /dev/null
+++ b/base/str.cc
@@ -0,0 +1,332 @@
+/*
+ * 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.
+ */
+
+#include <iostream>
+
+#include <string.h>
+#include <ctype.h>
+
+#include <string>
+#include <vector>
+
+#include "intmath.h"
+#include "str.hh"
+
+using namespace std;
+
+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 (ignore) {
+ if (last == first) {
+ while (last == first)
+ last = s.find_first_of(token, ++first);
+
+ if (last == string::npos) {
+ v.push_back(s);
+ 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));
+}
+
+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 T hexmax = maxnum & (((T)1 << (sizeof(T) * 8 - 4)) - 1);
+ static const T octmax = maxnum & (((T)1 << (sizeof(T) * 8 - 3)) - 1);
+ static const T signmax =
+ (sign) ? maxnum & (((T)1 << (sizeof(T) * 8 - 1)) - 1) : maxnum;
+ static const T decmax = signmax / 10 - 1;
+
+#if 0
+ cout << "maxnum = 0x" << hex << maxnum << "\n"
+ << "sign = 0x" << hex << sign << "\n"
+ << "hexmax = 0x" << hex << hexmax << "\n"
+ << "octmax = 0x" << hex << octmax << "\n"
+ << "signmax = 0x" << hex << signmax << "\n"
+ << "decmax = 0x" << hex << 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;
+ retval *= 10;
+ retval += c - '0';
+ if (sign && (retval & ((T)1 << (sizeof(T) * 8 - 1))))
+ return false;
+ }
+
+ c = value[last];
+ if (IsDec(c)) {
+
+ if (retval > decmax) return false;
+ retval *= 10;
+ retval += c - '0';
+ 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/base/str.hh b/base/str.hh
new file mode 100644
index 000000000..29d2c03db
--- /dev/null
+++ b/base/str.hh
@@ -0,0 +1,127 @@
+/*
+ * 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.
+ */
+
+#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;
+}
+
+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>
+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/base/symtab.cc b/base/symtab.cc
new file mode 100644
index 000000000..7beee182b
--- /dev/null
+++ b/base/symtab.cc
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ */
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+
+#include "host.hh"
+#include "misc.hh"
+#include "str.hh"
+#include "symtab.hh"
+
+using namespace std;
+
+bool
+SymbolTable::insert(Addr address, string symbol)
+{
+ 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) {
+ cerr << "Can't open symbol table file " << filename << endl;
+ fatal("file error");
+ }
+
+ 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;
+}
+
+bool
+SymbolTable::findSymbol(Addr address, string &symbol) const
+{
+ ATable::const_iterator i = addrTable.find(address);
+ if (i == addrTable.end())
+ return false;
+
+ symbol = (*i).second;
+ return true;
+}
+
+bool
+SymbolTable::findAddress(const string &symbol, Addr &address) const
+{
+ STable::const_iterator i = symbolTable.find(symbol);
+ if (i == symbolTable.end())
+ return false;
+
+ address = (*i).second;
+ return true;
+}
+
+string
+SymbolTable::find(Addr addr) const
+{
+ string s;
+ findSymbol(addr, s);
+ return s;
+}
+
+Addr
+SymbolTable::find(const string &symbol) const
+{
+ Addr a = 0;
+ findAddress(symbol, a);
+ return a;
+}
diff --git a/base/symtab.hh b/base/symtab.hh
new file mode 100644
index 000000000..073325eba
--- /dev/null
+++ b/base/symtab.hh
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#ifndef __SYMTAB_HH__
+#define __SYMTAB_HH__
+
+#include "hashmap.hh"
+#include "isa_traits.hh" // for Addr
+
+class SymbolTable
+{
+ private:
+ typedef m5::hash_map<Addr, std::string> ATable;
+ typedef m5::hash_map<std::string, Addr> STable;
+
+ ATable addrTable;
+ STable symbolTable;
+
+ public:
+ SymbolTable() {}
+ SymbolTable(const std::string &file) { load(file); }
+ ~SymbolTable() {}
+
+ bool insert(Addr address, std::string symbol);
+ bool load(const std::string &file);
+
+ bool findSymbol(Addr address, std::string &symbol) const;
+ bool findAddress(const std::string &symbol, Addr &address) const;
+
+ std::string find(Addr addr) const;
+ Addr find(const std::string &symbol) const;
+};
+
+#endif // __SYMTAB_HH__
diff --git a/base/trace.cc b/base/trace.cc
new file mode 100644
index 000000000..d1baf3000
--- /dev/null
+++ b/base/trace.cc
@@ -0,0 +1,325 @@
+/*
+ * 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.
+ */
+
+#include <ctype.h>
+#include <fstream>
+#include <iostream>
+#include <list>
+#include <string>
+#include <vector>
+
+#include "misc.hh"
+#include "trace.hh"
+#include "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 = NULL;
+
+int dprintf_ignore_size;
+vector<string> dprintf_ignore;
+vector<vector<string> > ignore_tokens;
+vector<int> ignore_size;
+
+bool
+dprintf_ignore_name(const string &name)
+{
+ vector<string> name_tokens;
+ tokenize(name_tokens, name, '.');
+ int ntsize = name_tokens.size();
+
+ for (int i = 0; i < dprintf_ignore_size; ++i) {
+ bool match = true;
+ int jstop = ignore_size[i];
+ for (int j = 0; j < jstop; ++j) {
+ if (j >= ntsize)
+ break;
+
+ const string &ignore = ignore_tokens[i][j];
+ if (ignore != "*" && ignore != name_tokens[j]) {
+ match = false;
+ break;
+ }
+ }
+
+ if (match == true)
+ return true;
+ }
+
+ return false;
+}
+
+
+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);
+ }
+
+ // 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();
+}
+
+
+
+RawDataRecord::RawDataRecord(Tick _cycle,
+ const uint8_t *_data, int _len)
+ : Record(_cycle), len(_len)
+{
+ data = new uint8_t[len];
+ memcpy(data, _data, len);
+}
+
+
+RawDataRecord::~RawDataRecord()
+{
+ delete [] data;
+}
+
+
+void
+RawDataRecord::dump(ostream &os)
+{
+ int c, i, j;
+
+ for (i = 0; i < len; i += 16) {
+ ccprintf(os, "%08x ", 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()
+{
+ if (Trace::dprintf_stream)
+ return *Trace::dprintf_stream;
+ else
+ return cerr;
+}
+
+/////////////////////////////////////////////
+//
+// 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;
+ }
+ }
+}
diff --git a/base/trace.hh b/base/trace.hh
new file mode 100644
index 000000000..42cd1722b
--- /dev/null
+++ b/base/trace.hh
@@ -0,0 +1,218 @@
+/*
+ * 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.
+ */
+
+#ifndef __TRACE_HH__
+#define __TRACE_HH__
+
+#include <vector>
+
+#include "cprintf.hh"
+#include "host.hh"
+#include "universe.hh"
+
+#ifndef TRACING_ON
+#ifdef DEBUG
+#define TRACING_ON 1
+#else
+#define TRACING_ON 0
+#endif
+#endif
+
+#include "trace_flags.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 RawDataRecord : public Record
+ {
+ private:
+ uint8_t *data;
+ int len;
+
+ public:
+ RawDataRecord(Tick cycle, const uint8_t *_data, int _len);
+ virtual ~RawDataRecord();
+
+ 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 int dprintf_ignore_size;
+
+ bool
+ dprintf_ignore_name(const std::string &name);
+
+ inline void
+ dprintf(const char *format, cp::ArgList &args, Tick cycle,
+ const std::string &name)
+ {
+ if (!dprintf_ignore_size || name.empty() || !dprintf_ignore_name(name))
+ theLog.append(new Trace::PrintfRecord(format, args, cycle, name));
+ }
+
+ inline void
+ rawDump(const uint8_t *data, int len)
+ {
+ theLog.append(new Trace::RawDataRecord(curTick, data, len));
+ }
+
+ extern const std::string DefaultName;
+};
+
+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 { \
+ using namespace Trace; \
+ if (Trace::IsOn(Trace::x)) \
+ rawDump(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, string(), args, cp::ArgListNull()); \
+} while (0)
+
+#define DPRINTFN(args...) \
+do { \
+ __dprintf(curTick, name(), 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 DDUMP(x, data, count) do {} while(0)
+
+#endif // TRACING_ON
+
+#endif // __TRACE_HH__
diff --git a/dev/alpha_access.h b/dev/alpha_access.h
new file mode 100644
index 000000000..ef33633e5
--- /dev/null
+++ b/dev/alpha_access.h
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+#ifndef __ALPHA_ACCESS_H__
+#define __ALPHA_ACCESS_H__
+
+/* @file
+ * System Console Memory Mapped Register Definition
+ */
+
+#define ALPHA_ACCESS_VERSION (1291+1) /* CH++*/
+
+#ifdef CONSOLE
+typedef uint32 UINT32;
+typedef uint64 UINT64;
+#else
+typedef uint32_t UINT32;
+typedef uint64_t UINT64;
+#endif
+
+// This structure hacked up from simos
+struct AlphaAccess
+{
+ UINT32 last_offset; // 00: must be first field
+ UINT32 version; // 04:
+ UINT32 numCPUs; // 08:
+ UINT32 align0; // 0C: Placeholder for alignment
+ UINT64 mem_size; // 10:
+ UINT64 cpuClock; // 18: MHz
+ UINT32 intrClockFrequency; // 20: Hz
+ UINT32 align1; // 24: Placeholder for alignment
+
+ // Loaded kernel
+ UINT64 kernStart; // 28:
+ UINT64 kernEnd; // 30:
+ UINT64 entryPoint; // 38:
+
+ // console disk stuff
+ UINT64 diskUnit; // 40:
+ UINT64 diskCount; // 48:
+ UINT64 diskPAddr; // 50:
+ UINT64 diskBlock; // 58:
+ UINT64 diskOperation; // 60:
+
+ // console simple output stuff
+ UINT64 outputChar; // 68:
+
+ // MP boot
+ UINT64 bootStrapImpure; // 70:
+ UINT32 bootStrapCPU; // 78:
+ UINT32 align2; // 7C: Dummy placeholder for alignment
+};
+
+#endif // __ALPHA_ACCESS_H__
diff --git a/dev/alpha_console.cc b/dev/alpha_console.cc
new file mode 100644
index 000000000..6a1e2b169
--- /dev/null
+++ b/dev/alpha_console.cc
@@ -0,0 +1,273 @@
+/*
+ * 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
+ * System Console Definition
+ */
+
+#include <stddef.h>
+#include <stdio.h>
+
+#include <string>
+
+#include "alpha_console.hh"
+#include "base_cpu.hh"
+#include "console.hh"
+#include "exec_context.hh"
+#include "memory_control.hh"
+#include "simple_disk.hh"
+#include "tlaser_clock.hh"
+#include "system.hh"
+#include "trace.hh"
+#include "inifile.hh"
+#include "str.hh" // for to_number()
+
+using namespace std;
+
+AlphaConsole::AlphaConsole(const string &name, SimConsole *cons,
+ SimpleDisk *d, int size, System *system,
+ BaseCPU *cpu, TlaserClock *clock, int num_cpus,
+ Addr addr, Addr mask, MemoryController *mmu)
+ : MmapDevice(name, addr, mask, mmu), disk(d), console(cons)
+{
+ consoleData = new uint8_t[size];
+ memset(consoleData, 0, size);
+
+ alphaAccess->last_offset = size - 1;
+ alphaAccess->kernStart = system->getKernelStart();
+ alphaAccess->kernEnd = system->getKernelEnd();
+ alphaAccess->entryPoint = system->getKernelEntry();
+
+ alphaAccess->version = ALPHA_ACCESS_VERSION;
+ alphaAccess->numCPUs = num_cpus;
+ alphaAccess->mem_size = system->physmem->getSize();
+ alphaAccess->cpuClock = cpu->getFreq() / 1000000;
+ alphaAccess->intrClockFrequency = clock->frequency();
+
+ alphaAccess->diskUnit = 1;
+}
+
+Fault
+AlphaConsole::read(MemReqPtr req, uint8_t *data)
+{
+ memset(data, 0, req->size);
+
+ if (req->size == sizeof(uint32_t)) {
+ Addr daddr = req->paddr & addr_mask;
+ *(uint32_t *)data = *(uint32_t *)(consoleData + daddr);
+
+#if 0
+ DPRINTF(AlphaConsole, "read: offset=%#x val=%#x\n",
+ daddr, *(uint32_t *)data);
+#endif
+ }
+
+ return No_Fault;
+}
+
+Fault
+AlphaConsole::write(MemReqPtr req, const uint8_t *data)
+{
+ uint64_t val;
+
+ switch (req->size) {
+ case sizeof(uint32_t):
+ val = *(uint32_t *)data;
+ break;
+ case sizeof(uint64_t):
+ val = *(uint64_t *)data;
+ break;
+ default:
+ return Machine_Check_Fault;
+ }
+
+ Addr paddr = req->paddr & addr_mask;
+
+ if (paddr == offsetof(AlphaAccess, diskUnit)) {
+ alphaAccess->diskUnit = val;
+ return No_Fault;
+ }
+
+ if (paddr == offsetof(AlphaAccess, diskCount)) {
+ alphaAccess->diskCount = val;
+ return No_Fault;
+ }
+
+ if (paddr == offsetof(AlphaAccess, diskPAddr)) {
+ alphaAccess->diskPAddr = val;
+ return No_Fault;
+ }
+
+ if (paddr == offsetof(AlphaAccess, diskBlock)) {
+ alphaAccess->diskBlock = val;
+ return No_Fault;
+ }
+
+ if (paddr == offsetof(AlphaAccess, diskOperation)) {
+ if (val == 0x13)
+ disk->read(alphaAccess->diskPAddr, alphaAccess->diskBlock,
+ alphaAccess->diskCount);
+ else
+ panic("Invalid disk operation!");
+
+ return No_Fault;
+ }
+
+ if (paddr == offsetof(AlphaAccess, outputChar)) {
+ console->simple((char)(val & 0xff));
+ return No_Fault;
+ }
+
+ if (paddr == offsetof(AlphaAccess, bootStrapImpure)) {
+ alphaAccess->bootStrapImpure = val;
+ return No_Fault;
+ }
+
+ if (paddr == offsetof(AlphaAccess, bootStrapCPU)) {
+ warn("%d: Trying to launch another CPU!", curTick);
+ int cpu = val;
+ assert(cpu > 0 && "Must not access primary cpu");
+
+ ExecContext *other_xc = req->xc->system->xc_array[cpu];
+ other_xc->regs.intRegFile[16] = cpu;
+ other_xc->regs.ipr[TheISA::IPR_PALtemp16] = cpu;
+ other_xc->regs.intRegFile[0] = cpu;
+ other_xc->regs.intRegFile[30] = alphaAccess->bootStrapImpure;
+ other_xc->setStatus(ExecContext::Active); //Start the cpu
+ return No_Fault;
+ }
+
+ return No_Fault;
+}
+
+void
+AlphaConsole::serialize()
+{
+ nameOut();
+ // assumes full AlphaAccess size
+ // might have unnecessary fields here
+ paramOut("last_offset",alphaAccess->last_offset);
+ paramOut("version",alphaAccess->version);
+ paramOut("numCPUs",alphaAccess->numCPUs);
+ paramOut("mem_size",alphaAccess->mem_size);
+ paramOut("cpuClock",alphaAccess->cpuClock);
+ paramOut("intrClockFrequency",alphaAccess->intrClockFrequency);
+ paramOut("kernStart",alphaAccess->kernStart);
+ paramOut("kernEnd",alphaAccess->kernEnd);
+ paramOut("entryPoint",alphaAccess->entryPoint);
+ paramOut("diskUnit",alphaAccess->diskUnit);
+ paramOut("diskCount",alphaAccess->diskCount);
+ paramOut("diskPAddr",alphaAccess->diskPAddr);
+ paramOut("diskBlock",alphaAccess->diskBlock);
+ paramOut("diskOperation",alphaAccess->diskOperation);
+ paramOut("outputChar",alphaAccess->outputChar);
+ paramOut("bootStrapImpure",alphaAccess->bootStrapImpure);
+ paramOut("bootStrapCPU",alphaAccess->bootStrapCPU);
+}
+
+void
+AlphaConsole::unserialize(IniFile &db, const std::string &category,
+ ConfigNode *node)
+{
+ string data;
+ db.findDefault(category,"last_offset",data);
+ to_number(data,alphaAccess->last_offset);
+ db.findDefault(category,"version",data);
+ to_number(data,alphaAccess->version);
+ db.findDefault(category,"numCPUs",data);
+ to_number(data,alphaAccess->numCPUs);
+ db.findDefault(category,"mem_size",data);
+ to_number(data,alphaAccess->mem_size);
+ db.findDefault(category,"cpuClock",data);
+ to_number(data,alphaAccess->cpuClock);
+ db.findDefault(category,"intrClockFrequency",data);
+ to_number(data,alphaAccess->intrClockFrequency);
+ db.findDefault(category,"kernStart",data);
+ to_number(data,alphaAccess->kernStart);
+ db.findDefault(category,"kernEnd",data);
+ to_number(data,alphaAccess->kernEnd);
+ db.findDefault(category,"entryPoint",data);
+ to_number(data,alphaAccess->entryPoint);
+ db.findDefault(category,"diskUnit",data);
+ to_number(data,alphaAccess->diskUnit);
+ db.findDefault(category,"diskCount",data);
+ to_number(data,alphaAccess->diskCount);
+ db.findDefault(category,"diskPAddr",data);
+ to_number(data,alphaAccess->diskPAddr);
+ db.findDefault(category,"diskBlock",data);
+ to_number(data,alphaAccess->diskBlock);
+ db.findDefault(category,"diskOperation",data);
+ to_number(data,alphaAccess->diskOperation);
+ db.findDefault(category,"outputChar",data);
+ to_number(data,alphaAccess->outputChar);
+ db.findDefault(category,"bootStrapImpure",data);
+ to_number(data,alphaAccess->bootStrapImpure);
+ db.findDefault(category,"bootStrapCPU",data);
+ to_number(data,alphaAccess->bootStrapCPU);
+
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaConsole)
+
+ SimObjectParam<SimConsole *> sim_console;
+ SimObjectParam<SimpleDisk *> disk;
+ Param<int> size;
+ Param<int> num_cpus;
+ SimObjectParam<MemoryController *> mmu;
+ Param<Addr> addr;
+ Param<Addr> mask;
+ SimObjectParam<System *> system;
+ SimObjectParam<BaseCPU *> cpu;
+ SimObjectParam<TlaserClock *> clock;
+
+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_DFLT(size, "AlphaConsole size", sizeof(AlphaAccess)),
+ INIT_PARAM_DFLT(num_cpus, "Number of CPU's", 1),
+ INIT_PARAM(mmu, "Memory Controller"),
+ INIT_PARAM(addr, "Device Address"),
+ INIT_PARAM(mask, "Address Mask"),
+ INIT_PARAM(system, "system object"),
+ INIT_PARAM(cpu, "Processor"),
+ INIT_PARAM(clock, "Turbolaser Clock")
+
+END_INIT_SIM_OBJECT_PARAMS(AlphaConsole)
+
+CREATE_SIM_OBJECT(AlphaConsole)
+{
+ return new AlphaConsole(getInstanceName(), sim_console,
+ disk, size, system,
+ cpu, clock, num_cpus,
+ addr, mask, mmu);
+}
+
+REGISTER_SIM_OBJECT("AlphaConsole", AlphaConsole)
diff --git a/dev/alpha_console.hh b/dev/alpha_console.hh
new file mode 100644
index 000000000..518f5fccb
--- /dev/null
+++ b/dev/alpha_console.hh
@@ -0,0 +1,108 @@
+/*
+ * 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
+ * System Console Interface
+ */
+
+#ifndef __ALPHA_CONSOLE_HH__
+#define __ALPHA_CONSOLE_HH__
+
+#include "host.hh"
+#include "alpha_access.h"
+#include "mmap_device.hh"
+
+class BaseCPU;
+class SimConsole;
+class System;
+class TlaserClock;
+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 MmapDevice
+{
+ protected:
+ union {
+ AlphaAccess *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;
+
+ public:
+ /** Standard Constructor */
+ AlphaConsole(const std::string &name, SimConsole *cons,
+ SimpleDisk *d, int size,
+ System *system, BaseCPU *cpu,
+ TlaserClock *clock, int num_cpus,
+ Addr addr, Addr mask, MemoryController *mmu);
+
+ public:
+ /**
+ * memory mapped reads and writes
+ */
+ virtual Fault read(MemReqPtr req, uint8_t *data);
+ virtual Fault write(MemReqPtr req, const uint8_t *data);
+
+ /**
+ * standard serialization routines for checkpointing
+ */
+ virtual void serialize();
+ virtual void unserialize(IniFile &db, const std::string &category,
+ ConfigNode *node);
+};
+
+#endif // __ALPHA_CONSOLE_HH__
diff --git a/dev/console.cc b/dev/console.cc
new file mode 100644
index 000000000..8141a6508
--- /dev/null
+++ b/dev/console.cc
@@ -0,0 +1,478 @@
+/* $Id$ */
+
+/* @file
+ * User Console Definitions
+ */
+
+#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 "misc.hh"
+#include "ev5.hh"
+
+#include "console.hh"
+#include "socket.hh"
+#include "trace.hh"
+#include "memory_control.hh"
+
+using namespace std;
+
+// check whether an int is pending
+inline bool
+IntPending(int status, int mask)
+{ return (status & mask) != 0; }
+
+inline bool
+IntTransition(int ostaus, int omask, int nstatus, int nmask)
+{ return IntPending(ostaus, omask) != IntPending(nstatus, nmask); }
+
+////////////////////////////////////////////////////////////////////////
+//
+//
+
+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, const string &file, int num)
+ : SimObject(name), event(NULL), number(num), in_fd(-1), out_fd(-1),
+ listener(NULL), txbuf(16384), rxbuf(16384), outfile(NULL),
+ intr_status(0), intr_enable(0), intr(NULL)
+{
+ if (!file.empty())
+ outfile = new ofstream(file.c_str());
+
+ if (outfile)
+ outfile->setf(ios::unitbuf);
+}
+
+SimConsole::~SimConsole()
+{
+ close();
+
+ if (outfile)
+ delete outfile;
+}
+
+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, "==== Simplescalar 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);
+ raiseInt(ReceiveInterrupt);
+ }
+}
+
+size_t
+SimConsole::read(uint8_t *buf, size_t len)
+{
+ if (in_fd < 0)
+ panic("SimConsole(read): Console not properly attached.\n");
+
+ size_t ret;
+ do {
+ ret = ::read(in_fd, buf, len);
+ } while (ret == -1 && errno == EINTR);
+
+
+ if (ret < 0)
+ DPRINTFN("SimConsole(read): 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("SimConsole(write): 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;
+}
+
+///////////////////////////////////////////////////////////////////////
+// ConfigureTerm turns off all character processing by the host OS so
+// the launched OS can control it.
+//
+// We ignore anything except stdin; the sconsole program runs this
+// same code on the ttys for the slave consoles before connecting.
+//
+void
+SimConsole::configTerm()
+{
+ struct termios ios;
+
+ if (isatty(out_fd)) {
+ if (tcgetattr(out_fd, &ios) < 0) {
+ panic( "tcgetattr\n");
+ }
+ ios.c_iflag &= ~(ISTRIP|ICRNL|IGNCR|ICRNL|IXOFF|IXON);
+ ios.c_oflag &= ~(OPOST);
+ ios.c_oflag &= (ONLCR);
+ ios.c_lflag &= ~(ISIG|ICANON|ECHO);
+ ios.c_cc[VMIN] = 1;
+ ios.c_cc[VTIME] = 0;
+ if (tcsetattr(out_fd, TCSANOW, &ios) < 0) {
+ panic( "tcsetattr\n");
+ }
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////
+// console i/o
+//
+
+///////////////////////////////////////////////////////////////////////
+//
+// Console input.
+// Returns -1 if there is no character pending, otherwise returns the
+// char. Calling this function clears the input int (if no further
+// chars are pending).
+//
+int
+SimConsole::in()
+{
+ if (rxbuf.empty()) {
+ clearInt(ReceiveInterrupt);
+ return -1;
+ }
+
+ char c;
+ rxbuf.read(&c, 1);
+
+ DPRINTF(Console, "in: \'%c\' %#02x status: %#x\n",
+ isprint(c) ? c : ' ', c, intr_status);
+
+ return c;
+}
+
+///////////////////////////////////////////////////////////////////////
+//
+// Console output.
+// NOTE: this very rudimentary device generates a TX int as soon as
+// a character is output, since it has unlimited TX buffer capacity.
+//
+// Console output.
+// Uses sim_console_out to perform functionality similar to 'write'
+void
+SimConsole::out(char c)
+{
+ txbuf.write(c);
+
+ if (out_fd >= 0)
+ write(c);
+
+ if (outfile)
+ outfile->write(&c, 1);
+
+ raiseInt(TransmitInterrupt);
+
+ DPRINTF(Console, "out: \'%c\' %#02x status: %#x\n",
+ isprint(c) ? c : ' ', (int)c, intr_status);
+}
+
+// Simple console output used by Alpha firmware (not by the OS) -
+// outputs the character to console n, and doesn't raise any
+// interrupts
+void
+SimConsole::simple(char c)
+{
+ txbuf.write(c);
+
+ if (out_fd >= 0)
+ write(c);
+
+ if (outfile)
+ outfile->write(&c, 1);
+
+ DPRINTF(Console, "simple char: \'%c\' %#02x\n",
+ isprint(c) ? c : ' ', (int)c);
+}
+
+// Read the current interrupt status of this console.
+int
+SimConsole::intStatus()
+{
+#if 0
+ DPRINTF(Console, "interrupt %d status: %#x\n",
+ number, intr_status);
+#endif
+
+ return intr_status;
+}
+
+int
+SimConsole::clearInt(int i)
+{
+ int old_status = intr_status;
+ intr_status &= ~i;
+ if (IntTransition(old_status, intr_enable, intr_status, intr_enable) &&
+ intr)
+ intr->clear(TheISA::INTLEVEL_IRQ0);
+ return old_status;
+}
+
+void
+SimConsole::raiseInt(int i)
+{
+ int old = intr_status;
+ intr_status |= i;
+ if (IntTransition(old, intr_enable, intr_status, intr_enable) && intr)
+ intr->post(TheISA::INTLEVEL_IRQ0);
+}
+
+void
+SimConsole::initInt(IntrControl *i)
+{
+ if (intr)
+ panic("Console has already been initialized.");
+
+ // note: intr_status and intr_enable will normally be 0, since
+ // cs is statically allocated. When restoring from a checkpoint,
+ // these fields will be set, so don't touch them here.
+ intr = i; // interrupt handler
+}
+
+// Set the interrupt enable bits.
+void
+SimConsole::setInt(int bits)
+{
+ int old_enable;
+
+ if (bits & ~(TransmitInterrupt | ReceiveInterrupt))
+ panic("An interrupt was not set!");
+
+ old_enable = intr_enable;
+ intr_enable |= bits;
+
+ if (IntTransition(intr_status, old_enable, intr_status, intr_enable) &&
+ intr) {
+ if (IntPending(intr_status, intr_enable))
+ intr->post(TheISA::INTLEVEL_IRQ0);
+ else
+ intr->clear(TheISA::INTLEVEL_IRQ0);
+ }
+}
+
+
+void
+SimConsole::serialize()
+{
+ panic("Unimplemented");
+}
+
+void
+SimConsole::unserialize(IniFile &db, const std::string &category,
+ ConfigNode *node)
+{
+ panic("Unimplemented");
+}
+
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimConsole)
+
+ SimObjectParam<ConsoleListener *> listener;
+ SimObjectParam<IntrControl *> intr_control;
+ Param<string> output;
+ 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_DFLT(output, "file to dump output to", ""),
+ INIT_PARAM_DFLT(number, "console number", 0)
+
+END_INIT_SIM_OBJECT_PARAMS(SimConsole)
+
+CREATE_SIM_OBJECT(SimConsole)
+{
+ SimConsole *console = new SimConsole(getInstanceName(), output, number);
+ ((ConsoleListener *)listener)->add(console);
+ ((SimConsole *)console)->initInt(intr_control);
+ ((SimConsole *)console)->setInt(SimConsole::TransmitInterrupt |
+ SimConsole::ReceiveInterrupt);
+
+ 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++;
+ }
+
+ cerr << "Listening for console connection on port " << port << endl;
+ 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 we're 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/dev/console.hh b/dev/console.hh
new file mode 100644
index 000000000..092e6ea53
--- /dev/null
+++ b/dev/console.hh
@@ -0,0 +1,147 @@
+/* $Id$ */
+
+/* @file
+ * User Console Interface
+ */
+
+#ifndef __CONSOLE_HH__
+#define __CONSOLE_HH__
+
+#include <iostream>
+
+#include "circlebuf.hh"
+#include "intr_control.hh"
+#include "pollevent.hh"
+#include "socket.hh"
+#include "sim_object.hh"
+
+class ConsoleListener;
+class SimConsole : public SimObject
+{
+ 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;
+
+ protected:
+ ConsoleListener *listener;
+
+ public:
+ SimConsole(const std::string &name, const std::string &file, int num);
+ ~SimConsole();
+
+ protected:
+ CircleBuf txbuf;
+ CircleBuf rxbuf;
+ std::ostream *outfile;
+
+ 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);
+
+ void configTerm();
+
+ protected:
+ // interrupt status/enable
+ int intr_status;
+ int intr_enable;
+
+ // interrupt handle
+ IntrControl *intr;
+
+ public:
+ /////////////////
+ // OS interface
+
+ // Input a character from the console. Returns the character (if
+ // any) or -1 if there is no character pending on this console. If
+ // no further characters are pending, the (input) interrupt is
+ // cleared.
+ int in();
+
+ // Output a character to the console. This never fails, as this
+ // device doesn't model finite buffering capacity.
+ void out(char c);
+ void simple(char c);
+
+ enum {
+ TransmitInterrupt = 1,
+ ReceiveInterrupt = 2
+ };
+
+ // Read the current interrupt status of this console.
+ int intStatus();
+
+ // Set the interrupt enable bits.
+ int clearInt(int i);
+ void raiseInt(int i);
+
+ void initInt(IntrControl *i);
+ void setInt(int bits);
+
+ virtual void serialize();
+ virtual void unserialize(IniFile &db, const std::string &category,
+ ConfigNode *node);
+};
+
+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/dev/disk_image.cc b/dev/disk_image.cc
new file mode 100644
index 000000000..17a7f3e9d
--- /dev/null
+++ b/dev/disk_image.cc
@@ -0,0 +1,427 @@
+/*
+ * 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
+ * Disk Image Definitions
+ */
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <cstdio>
+#include <fstream>
+#include <string>
+
+#include "disk_image.hh"
+#include "misc.hh"
+#include "trace.hh"
+#include "sim_exit.hh"
+#include "callback.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");
+
+ off_t 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);
+
+ off_t 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()) {
+ 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)); }
+
+bool
+CowDiskImage::open()
+{
+ ifstream stream(filename.c_str());
+ if (!stream.is_open())
+ return false;
+
+ if (stream.fail() || stream.bad())
+ panic("Error opening %s", filename);
+
+ uint64_t magic;
+ SafeRead(stream, magic);
+
+ if (memcmp(&magic, "COWDISK!", sizeof(magic)) != 0)
+ panic("Could not open %s: Invalid magic", filename);
+
+ uint32_t major, minor;
+ SafeRead(stream, major);
+ SafeRead(stream, minor);
+
+ if (major != VersionMajor && minor != VersionMinor)
+ panic("Could not open %s: invalid version %d.%d != %d.%d",
+ filename, major, minor, VersionMajor, VersionMinor);
+
+ uint64_t sector_count;
+ SafeRead(stream, sector_count);
+ table = new SectorTable(sector_count);
+
+
+ for (uint64_t i = 0; i < sector_count; i++) {
+ uint64_t offset;
+ SafeRead(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)); }
+
+void
+CowDiskImage::save()
+{
+ if (!initialized)
+ panic("RawDiskImage not initialized");
+
+ ofstream stream(filename.c_str());
+ if (!stream.is_open() || stream.fail() || stream.bad())
+ panic("Error opening %s", filename);
+
+ uint64_t magic;
+ memcpy(&magic, "COWDISK!", sizeof(magic));
+ SafeWrite(stream, magic);
+
+ SafeWrite(stream, (uint32_t)VersionMajor);
+ SafeWrite(stream, (uint32_t)VersionMinor);
+ SafeWrite(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");
+
+ SafeWrite(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;
+}
+
+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/dev/disk_image.hh b/dev/disk_image.hh
new file mode 100644
index 000000000..2cfa1490a
--- /dev/null
+++ b/dev/disk_image.hh
@@ -0,0 +1,130 @@
+/*
+ * 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
+ * Disk Image Interfaces
+ */
+
+#ifndef __DISK_IMAGE_HH__
+#define __DISK_IMAGE_HH__
+
+#include <fstream>
+
+#include "hashmap.hh"
+#include "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();
+ void save();
+ void writeback();
+
+ 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/dev/etherbus.cc b/dev/etherbus.cc
new file mode 100644
index 000000000..fa5a62208
--- /dev/null
+++ b/dev/etherbus.cc
@@ -0,0 +1,128 @@
+/*
+ * 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
+ * Device module for modelling an ethernet hub
+ */
+
+#include <deque>
+#include <string>
+#include <vector>
+
+#include <math.h>
+
+#include "etherbus.hh"
+#include "etherdump.hh"
+#include "etherint.hh"
+#include "etherpkt.hh"
+#include "trace.hh"
+#include "universe.hh"
+
+using namespace std;
+
+EtherBus::EtherBus(const string &name, double rate, bool loop,
+ EtherDump *packet_dump)
+ : SimObject(name), ticks_per_byte(rate), 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, PacketPtr 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 * ticks_per_byte) + 1.0);
+ DPRINTF(Ethernet, "scheduling packet: delay=%d, (rate=%f)\n",
+ delay, ticks_per_byte);
+ event.schedule(curTick + delay);
+
+ return true;
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherBus)
+
+ Param<bool> loopback;
+ Param<int> speed;
+ SimObjectParam<EtherDump *> packet_dump;
+
+END_DECLARE_SIM_OBJECT_PARAMS(EtherBus)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(EtherBus)
+
+ INIT_PARAM_DFLT(loopback,
+ "send the packet back to the interface from which it came",
+ true),
+ INIT_PARAM_DFLT(speed, "bus speed in bits per second", 100000000),
+ INIT_PARAM_DFLT(packet_dump, "object to dump network packets to", NULL)
+
+END_INIT_SIM_OBJECT_PARAMS(EtherBus)
+
+CREATE_SIM_OBJECT(EtherBus)
+{
+ double rate = ((double)ticksPerSecond * 8.0) / (double)speed;
+ return new EtherBus(getInstanceName(), rate, loopback, packet_dump);
+}
+
+REGISTER_SIM_OBJECT("EtherBus", EtherBus)
diff --git a/dev/etherbus.hh b/dev/etherbus.hh
new file mode 100644
index 000000000..f64aa45e1
--- /dev/null
+++ b/dev/etherbus.hh
@@ -0,0 +1,79 @@
+/*
+ * 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
+ * Device module for modelling an ethernet hub
+ */
+
+#ifndef __ETHERBUS_H__
+#define __ETHERBUS_H__
+
+#include "eventq.hh"
+#include "etherpkt.hh"
+#include "sim_object.hh"
+
+class EtherDump;
+class EtherInt;
+class EtherBus : public SimObject
+{
+ protected:
+ typedef std::list<EtherInt *> devlist_t;
+ devlist_t devlist;
+ double ticks_per_byte;
+ 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;
+ PacketPtr packet;
+ EtherInt *sender;
+ EtherDump *dump;
+
+ public:
+ EtherBus(const std::string &name, double ticks_per_byte, bool loopback,
+ EtherDump *dump);
+ virtual ~EtherBus() {}
+
+ void txDone();
+ void reg(EtherInt *dev);
+ bool busy() const { return (bool)packet; }
+ bool send(EtherInt *sender, PacketPtr packet);
+};
+
+#endif // __ETHERBUS_H__
diff --git a/dev/etherdump.cc b/dev/etherdump.cc
new file mode 100644
index 000000000..034db86aa
--- /dev/null
+++ b/dev/etherdump.cc
@@ -0,0 +1,138 @@
+/*
+ * 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
+ * Simple object for creating a simple pcap style packet trace
+ */
+
+#include <sys/time.h>
+
+#include <string>
+
+#include "universe.hh"
+#include "etherdump.hh"
+#include "universe.hh"
+
+using std::string;
+
+EtherDump::EtherDump(const string &name, const string &file)
+ : SimObject(name)
+{
+ if (!file.empty()) {
+ stream.open(file.c_str());
+ if (stream.is_open())
+ init();
+ }
+}
+
+#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 {
+ struct timeval ts; // time stamp
+ uint32_t caplen; // length of portion present
+ uint32_t len; // length this packet (off wire)
+};
+
+void
+EtherDump::init()
+{
+ curtime = time(NULL);
+ s_freq = ticksPerSecond;
+ us_freq = ticksPerSecond / ULL(1000000);
+
+ 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.ts.tv_sec = curtime;
+ pkthdr.ts.tv_usec = 0;
+ pkthdr.caplen = 0;
+ pkthdr.len = 0;
+ stream.write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr));
+
+ stream.flush();
+}
+
+void
+EtherDump::dumpPacket(PacketPtr packet)
+{
+ pcap_pkthdr pkthdr;
+ pkthdr.ts.tv_sec = curtime + (curTick / s_freq);
+ pkthdr.ts.tv_usec = (curTick / us_freq) % ULL(1000000);
+ pkthdr.caplen = packet->length;
+ pkthdr.len = packet->length;
+ stream.write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr));
+ stream.write(reinterpret_cast<char *>(packet->data), packet->length);
+ stream.flush();
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherDump)
+
+ Param<string> file;
+
+END_DECLARE_SIM_OBJECT_PARAMS(EtherDump)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(EtherDump)
+
+ INIT_PARAM_DFLT(file, "file to dump packets to", "")
+
+END_INIT_SIM_OBJECT_PARAMS(EtherDump)
+
+CREATE_SIM_OBJECT(EtherDump)
+{
+ return new EtherDump(getInstanceName(), file);
+}
+
+REGISTER_SIM_OBJECT("EtherDump", EtherDump)
diff --git a/dev/etherdump.hh b/dev/etherdump.hh
new file mode 100644
index 000000000..87824c470
--- /dev/null
+++ b/dev/etherdump.hh
@@ -0,0 +1,60 @@
+/*
+ * 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
+ * Simple object for creating a simple pcap style packet trace
+ */
+
+#ifndef __ETHERDUMP_H__
+#define __ETHERDUMP_H__
+
+#include <fstream>
+#include "etherpkt.hh"
+#include "sim_object.hh"
+
+/*
+ * Simple object for creating a simple pcap style packet trace
+ */
+class EtherDump : public SimObject
+{
+ private:
+ std::ofstream stream;
+ void dumpPacket(PacketPtr packet);
+ void init();
+
+ Tick curtime;
+ Tick s_freq;
+ Tick us_freq;
+
+ public:
+ EtherDump(const std::string &name, const std::string &file);
+
+ inline void dump(PacketPtr pkt) { if (stream.is_open()) dumpPacket(pkt); }
+};
+
+#endif // __ETHERDUMP_H__
diff --git a/dev/etherint.cc b/dev/etherint.cc
new file mode 100644
index 000000000..51b18c6aa
--- /dev/null
+++ b/dev/etherint.cc
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+#include "etherint.hh"
+#include "misc.hh"
+#include "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/dev/etherint.hh b/dev/etherint.hh
new file mode 100644
index 000000000..00e291fc9
--- /dev/null
+++ b/dev/etherint.hh
@@ -0,0 +1,63 @@
+/*
+ * 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
+ * Class representing the actual interface between two ethernet
+ * components.
+ */
+
+#ifndef __ETHERINT_HH__
+#define __ETHERINT_HH__
+
+#include <string>
+
+#include "etherpkt.hh"
+#include "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);
+ virtual bool recvPacket(PacketPtr packet) = 0;
+ void recvDone() { peer->sendDone(); }
+ bool sendPacket(PacketPtr packet) { return peer->recvPacket(packet); }
+ virtual void sendDone() = 0;
+};
+
+#endif // __ETHERINT_HH__
diff --git a/dev/etherlink.cc b/dev/etherlink.cc
new file mode 100644
index 000000000..1d3578e58
--- /dev/null
+++ b/dev/etherlink.cc
@@ -0,0 +1,148 @@
+/*
+ * 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
+ * Device module for modelling a fixed bandwidth full duplex ethernet link
+ */
+
+#include <deque>
+#include <string>
+#include <vector>
+
+#include <math.h>
+
+#include "etherlink.hh"
+#include "etherdump.hh"
+#include "etherint.hh"
+#include "etherpkt.hh"
+#include "trace.hh"
+#include "universe.hh"
+
+using namespace std;
+
+EtherLink::EtherLink(const std::string &name, EtherInt *i1, EtherInt *i2,
+ Tick speed, EtherDump *dump)
+ : SimObject(name)
+{
+ double rate = ((double)ticksPerSecond * 8.0) / (double)speed;
+
+ link1 = new Link(name + ".link1", rate, dump);
+ link2 = new Link(name + ".link2", rate, dump);
+
+ int1 = new Interface(name + ".int1", link1, link2);
+ int2 = new Interface(name + ".int2", link2, link1);
+
+ int1->setPeer(i1);
+ i1->setPeer(int1);
+ int2->setPeer(i2);
+ i2->setPeer(int2);
+}
+
+EtherLink::~EtherLink()
+{
+ delete link1;
+ delete link2;
+
+ delete int1;
+ delete int2;
+}
+
+EtherLink::Interface::Interface(const std::string &name, Link *tx, Link *rx)
+ : EtherInt(name), txlink(tx)
+{
+ tx->setTxInt(this);
+ rx->setRxInt(this);
+}
+
+EtherLink::Link::Link(const std::string &name, double rate, EtherDump *d)
+ : Serializeable(name), txint(NULL), rxint(NULL), ticks_per_byte(rate),
+ dump(d), event(&mainEventQueue, this)
+{}
+
+void
+EtherLink::Link::txDone()
+{
+ rxint->sendPacket(packet);
+
+ if (dump)
+ dump->dump(packet);
+
+ DPRINTF(Ethernet, "EtherLink packet received: len=%d\n", packet->length);
+ DDUMP(EthernetData, packet->data, packet->length);
+
+ packet = 0;
+ assert(!busy());
+
+ txint->sendDone();
+}
+
+bool
+EtherLink::Link::transmit(PacketPtr pkt)
+{
+ if (busy()) {
+ DPRINTF(Ethernet, "EtherLink packet not sent, link busy\n");
+ return false;
+ }
+
+ DPRINTF(Ethernet, "EtherLink packet sent: len=%d\n", pkt->length);
+ DDUMP(EthernetData, pkt->data, pkt->length);
+
+ packet = pkt;
+ int delay = (int)ceil(((double)pkt->length * ticks_per_byte) + 1.0);
+ DPRINTF(Ethernet, "EtherLink scheduling packet: delay=%d, (rate=%f)\n",
+ delay, ticks_per_byte);
+ event.schedule(curTick + delay);
+
+ return true;
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherLink)
+
+ SimObjectParam<EtherInt *> interface1;
+ SimObjectParam<EtherInt *> interface2;
+ Param<int> link_speed;
+ SimObjectParam<EtherDump *> packet_dump;
+
+END_DECLARE_SIM_OBJECT_PARAMS(EtherLink)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(EtherLink)
+
+ INIT_PARAM(interface1, "interface 1"),
+ INIT_PARAM(interface2, "interface 2"),
+ INIT_PARAM_DFLT(link_speed, "link speed in bits per second", 100000000),
+ INIT_PARAM_DFLT(packet_dump, "object to dump network packets to", NULL)
+
+END_INIT_SIM_OBJECT_PARAMS(EtherLink)
+
+CREATE_SIM_OBJECT(EtherLink)
+{
+ return new EtherLink(getInstanceName(), interface1, interface2, link_speed,
+ packet_dump);
+}
+
+REGISTER_SIM_OBJECT("EtherLink", EtherLink)
diff --git a/dev/etherlink.hh b/dev/etherlink.hh
new file mode 100644
index 000000000..b88d80420
--- /dev/null
+++ b/dev/etherlink.hh
@@ -0,0 +1,123 @@
+/*
+ * 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
+ * Device module for modelling a fixed bandwidth full duplex ethernet link
+ */
+
+#ifndef __ETHERLINK_HH__
+#define __ETHERLINK_HH__
+
+#include "host.hh"
+#include "eventq.hh"
+#include "etherint.hh"
+#include "etherpkt.hh"
+#include "sim_object.hh"
+
+class EtherDump;
+
+/*
+ * Model for a fixed bandwidth full duplex ethernet link
+ */
+class EtherLink : public SimObject
+{
+ protected:
+ class Interface;
+
+ /*
+ * Model for a single uni-directional link
+ */
+ class Link : public Serializeable {
+ protected:
+ Interface *txint;
+ Interface *rxint;
+
+ double ticks_per_byte;
+ EtherDump *dump;
+
+ protected:
+ /*
+ * Transfer is complete
+ */
+ class DoneEvent : public Event
+ {
+ protected:
+ Link *link;
+
+ public:
+ DoneEvent(EventQueue *q, Link *l)
+ : Event(q), link(l) {}
+ virtual void process() { link->txDone(); }
+ virtual const char *description()
+ { return "ethernet link completion"; }
+ };
+
+ friend class DoneEvent;
+ DoneEvent event;
+ PacketPtr packet;
+
+ void txDone();
+
+ public:
+ Link(const std::string &name, double rate, EtherDump *dump);
+ ~Link() {}
+
+ bool busy() const { return (bool)packet; }
+ bool transmit(PacketPtr packet);
+
+ void setTxInt(Interface *i) { assert(!txint); txint = i; }
+ void setRxInt(Interface *i) { assert(!rxint); rxint = i; }
+ };
+
+ /*
+ * 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(PacketPtr packet) { return txlink->transmit(packet); }
+ void sendDone() { }
+ };
+
+ Link *link1;
+ Link *link2;
+
+ EtherInt *int1;
+ EtherInt *int2;
+
+ public:
+ EtherLink(const std::string &name, EtherInt *i1, EtherInt *i2,
+ Tick speed, EtherDump *dump);
+ virtual ~EtherLink();
+};
+
+#endif // __ETHERLINK_HH__
diff --git a/dev/etherpkt.hh b/dev/etherpkt.hh
new file mode 100644
index 000000000..4927cc779
--- /dev/null
+++ b/dev/etherpkt.hh
@@ -0,0 +1,65 @@
+/*
+ * 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
+ * Reference counted class containing ethernet packet data
+ */
+
+#ifndef __ETHERPKT_HH__
+#define __ETHERPKT_HH__
+
+#include <memory>
+
+#include "host.hh"
+
+#include "refcnt.hh"
+
+/*
+ * Reference counted class containing ethernet packet data
+ */
+class EtherPacket : public RefCounted
+{
+ public:
+ uint8_t *data;
+ int length;
+
+ public:
+ EtherPacket() : data(NULL), length(0) {}
+ EtherPacket(std::auto_ptr<uint8_t> d, int l)
+ : data(d.release()), length(l) {}
+ ~EtherPacket() { if (data) delete [] data; }
+
+ public:
+ bool IsUnicast() { return data[0] == 0x00; }
+ bool IsMulticast() { return data[0] == 0x01; }
+ bool IsBroadcast() { return data[0] == 0xff; }
+};
+
+typedef RefCountingPtr<EtherPacket> PacketPtr;
+
+#endif // __ETHERPKT_HH__
diff --git a/dev/ethertap.cc b/dev/ethertap.cc
new file mode 100644
index 000000000..6643cab30
--- /dev/null
+++ b/dev/ethertap.cc
@@ -0,0 +1,295 @@
+/*
+ * 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
+ * Interface to connect a simulated ethernet device to the real world
+ */
+
+#if defined(__OpenBSD__)
+#include <sys/param.h>
+#endif
+#include <netinet/in.h>
+
+#include <unistd.h>
+
+#include <deque>
+#include <string>
+
+#include "etherdump.hh"
+#include "etherint.hh"
+#include "etherpkt.hh"
+#include "ethertap.hh"
+#include "pollevent.hh"
+#include "socket.hh"
+#include "trace.hh"
+#include "misc.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;
+ close(socket);
+ socket = -1;
+}
+
+bool
+EtherTap::recvPacket(PacketPtr 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)) {
+ PacketPtr packet;
+ packet = new EtherPacket;
+ packet->data = new uint8_t[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 + 1000);
+ } else if (dump)
+ dump->dump(packet);
+ }
+}
+
+void
+EtherTap::retransmit()
+{
+ if (packetBuffer.empty())
+ return;
+
+ PacketPtr 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 + 1000);
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherTap)
+
+ SimObjectParam<EtherInt *> peer;
+ SimObjectParam<EtherDump *> packet_dump;
+ Param<uint16_t> port;
+ Param<uint16_t> bufsz;
+
+END_DECLARE_SIM_OBJECT_PARAMS(EtherTap)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(EtherTap)
+
+ INIT_PARAM_DFLT(peer, "peer interface", NULL),
+ INIT_PARAM_DFLT(packet_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(), packet_dump, port, bufsz);
+
+ if (peer) {
+ tap->setPeer(peer);
+ peer->setPeer(tap);
+ }
+
+ return tap;
+}
+
+REGISTER_SIM_OBJECT("EtherTap", EtherTap)
diff --git a/dev/ethertap.hh b/dev/ethertap.hh
new file mode 100644
index 000000000..434df47b0
--- /dev/null
+++ b/dev/ethertap.hh
@@ -0,0 +1,101 @@
+/*
+ * 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
+ * Interface to connect a simulated ethernet device to the real world
+ */
+
+#ifndef __ETHERTAP_HH__
+#define __ETHERTAP_HH__
+
+#include <queue>
+#include <string>
+
+#include "etherint.hh"
+#include "etherpkt.hh"
+#include "eventq.hh"
+#include "pollevent.hh"
+#include "sim_object.hh"
+
+/*
+ * 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<PacketPtr> packetBuffer;
+
+ void process(int revent);
+ void enqueue(EtherPacket *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(PacketPtr packet);
+ virtual void sendDone();
+};
+
+#endif // __ETHERTAP_HH__
diff --git a/dev/pcireg.h b/dev/pcireg.h
new file mode 100644
index 000000000..2921c30be
--- /dev/null
+++ b/dev/pcireg.h
@@ -0,0 +1,175 @@
+/*
+ * 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
+ * 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 hdr {
+ 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 {
+ 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;
+ } pci0;
+
+ struct {
+ uint32_t baseAddr0;
+ uint32_t baseAddr1;
+ uint8_t priBusNum;
+ uint8_t secBusNum;
+ uint8_t subBusNum;
+ uint8_t secLatency;
+ uint8_t ioBase;
+ uint8_t minimumGrantioLimit;
+ uint16_t secStatus;
+ uint16_t memBase;
+ uint16_t memLimit;
+ uint16_t prefetchMemBase;
+ uint16_t prefetchMemLimit;
+ uint32_t prfBaseUpper32;
+ uint32_t prfLimitUpper32;
+ uint16_t ioBaseUpper16;
+ uint16_t ioLimitUpper16;
+ uint32_t reserved0;
+ uint32_t expansionROM;
+ uint8_t interruptLine;
+ uint8_t interruptPin;
+ uint16_t bridgeControl;
+ } pci1;
+ };
+ } hdr;
+};
+
+// 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
+
+// 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/dev/simple_disk.cc b/dev/simple_disk.cc
new file mode 100644
index 000000000..25645db5f
--- /dev/null
+++ b/dev/simple_disk.cc
@@ -0,0 +1,108 @@
+/*
+ * 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
+ * Simple disk interface for the system console
+ */
+
+#include <string>
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "disk_image.hh"
+#include "misc.hh"
+#include "physical_memory.hh"
+#include "simple_disk.hh"
+#include "trace.hh"
+
+using namespace std;
+
+SimpleDisk::SimpleDisk(const string &name, PhysicalMemory *pmem,
+ DiskImage *img)
+ : SimObject(name), physmem(pmem), image(img)
+{}
+
+SimpleDisk::~SimpleDisk()
+{}
+
+
+void
+SimpleDisk::read(Addr addr, baddr_t block, int count) const
+{
+ uint8_t *data = physmem->dma_addr(addr, count);
+ if (!data)
+ panic("dma out of range! read addr=%#x count=%d\n", addr, 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);
+
+ DPRINTF(SimpleDisk, "read block=%#x len=%d\n", (uint64_t)block, count);
+ DDUMP(SimpleDiskData, data, count);
+}
+
+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<PhysicalMemory *> physmem;
+ SimObjectParam<DiskImage *> disk;
+
+END_DECLARE_SIM_OBJECT_PARAMS(SimpleDisk)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleDisk)
+
+ INIT_PARAM(physmem, "Physical Memory"),
+ INIT_PARAM(disk, "Disk Image")
+
+END_INIT_SIM_OBJECT_PARAMS(SimpleDisk)
+
+CREATE_SIM_OBJECT(SimpleDisk)
+{
+ return new SimpleDisk(getInstanceName(), physmem, disk);
+}
+
+REGISTER_SIM_OBJECT("SimpleDisk", SimpleDisk)
diff --git a/dev/simple_disk.hh b/dev/simple_disk.hh
new file mode 100644
index 000000000..bf684950d
--- /dev/null
+++ b/dev/simple_disk.hh
@@ -0,0 +1,60 @@
+/*
+ * 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
+ * Simple disk interface for the system console
+ */
+
+#ifndef __SIMPLE_DISK_HH__
+#define __SIMPLE_DISK_HH__
+
+#include "physical_memory.hh"
+#include "sim_object.hh"
+
+class DiskImage;
+
+/*
+ * Trivial interface to a disk image used by the System Console
+ */
+class SimpleDisk : public SimObject
+{
+public:
+ typedef uint64_t baddr_t;
+
+protected:
+ PhysicalMemory *physmem;
+ DiskImage *image;
+
+public:
+ SimpleDisk(const std::string &name, PhysicalMemory *pmem, DiskImage *img);
+ ~SimpleDisk();
+
+ void read(Addr addr, baddr_t block, int count) const;
+ void write(Addr addr, baddr_t block, int count);
+};
+#endif // __SIMPLE_DISK_HH__
diff --git a/kern/tru64/tru64.hh b/kern/tru64/tru64.hh
new file mode 100644
index 000000000..f8bb8ee43
--- /dev/null
+++ b/kern/tru64/tru64.hh
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#ifndef __TRU64_HH__
+#define __TRU64_HH__
+
+class Tru64 {};
+
+#endif // __TRU64_HH__
diff --git a/kern/tru64/tru64_syscalls.cc b/kern/tru64/tru64_syscalls.cc
new file mode 100644
index 000000000..dbaf4dbff
--- /dev/null
+++ b/kern/tru64/tru64_syscalls.cc
@@ -0,0 +1,438 @@
+/*
+ * 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.
+ */
+
+#include "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/kern/tru64/tru64_syscalls.hh b/kern/tru64/tru64_syscalls.hh
new file mode 100644
index 000000000..2e76234c0
--- /dev/null
+++ b/kern/tru64/tru64_syscalls.hh
@@ -0,0 +1,355 @@
+/*
+ * 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.
+ */
+
+#ifndef __TRU64_SYSCALLS_HH__
+#define __TRU64_SYSCALLS_HH__
+
+#include "syscalls.hh"
+#include "tru64.hh"
+
+struct SystemCalls<Tru64>
+{
+ 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 // __TRU64_SYSCALLS_HH__
diff --git a/sim/async.hh b/sim/async.hh
new file mode 100644
index 000000000..fb0e2ee06
--- /dev/null
+++ b/sim/async.hh
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+#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/sim/base_cpu.cc b/sim/base_cpu.cc
new file mode 100644
index 000000000..43caa1fe4
--- /dev/null
+++ b/sim/base_cpu.cc
@@ -0,0 +1,158 @@
+/*
+ * 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.
+ */
+
+#include <string>
+#include <sstream>
+#include <iostream>
+
+#include "base_cpu.hh"
+#include "cprintf.hh"
+#include "stats.hh"
+#include "exec_context.hh"
+#include "misc.hh"
+#include "sim_events.hh"
+
+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;
+
+#ifdef FULL_SYSTEM
+BaseCPU::BaseCPU(const string &_name, int _number_of_threads,
+ Counter max_insts_any_thread,
+ Counter max_insts_all_threads,
+ System *_system, int num, Tick freq)
+ : SimObject(_name), number(num), frequency(freq),
+ number_of_threads(_number_of_threads), system(_system)
+#else
+BaseCPU::BaseCPU(const string &_name, int _number_of_threads,
+ Counter max_insts_any_thread,
+ Counter max_insts_all_threads)
+ : SimObject(_name), number_of_threads(_number_of_threads)
+#endif
+{
+ // add self to global list of CPUs
+ cpuList.push_back(this);
+
+ if (number_of_threads > maxThreadsPerCPU)
+ maxThreadsPerCPU = number_of_threads;
+
+ // allocate per-thread instruction-based event queues
+ comInsnEventQueue = new (EventQueue *)[number_of_threads];
+ for (int i = 0; i < number_of_threads; ++i)
+ comInsnEventQueue[i] = new EventQueue("instruction-based event queue");
+
+ //
+ // set up instruction-count-based termination events, if any
+ //
+ if (max_insts_any_thread != 0)
+ for (int i = 0; i < number_of_threads; ++i)
+ new SimExitEvent(comInsnEventQueue[i], max_insts_any_thread,
+ "a thread reached the max instruction count");
+
+ if (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(comInsnEventQueue[i],
+ "all threads reached the max instruction count",
+ max_insts_all_threads, *counter);
+ }
+
+#ifdef FULL_SYSTEM
+ memset(interrupts, 0, sizeof(interrupts));
+ intstatus = 0;
+#endif
+}
+
+void
+BaseCPU::regStats()
+{
+ int size = contexts.size();
+ if (size > 1) {
+ for (int i = 0; i < size; ++i) {
+ stringstream namestr;
+ ccprintf(namestr, "%s.ctx%d", name(), i);
+ contexts[i]->regStats(namestr.str());
+ }
+ } else if (size == 1)
+ contexts[0]->regStats(name());
+}
+
+#ifdef FULL_SYSTEM
+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 >= NumInterruptLevels)
+ panic("int_num out of bounds\n");
+
+ if (index < 0 || index >= sizeof(uint8_t) * 8)
+ panic("int_num out of bounds\n");
+
+ AlphaISA::check_interrupts = 1;
+ 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 >= NumInterruptLevels)
+ panic("int_num out of bounds\n");
+
+ if (index < 0 || index >= sizeof(uint8_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;
+}
+
+#endif // FULL_SYSTEM
+
+DEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU)
diff --git a/sim/base_cpu.hh b/sim/base_cpu.hh
new file mode 100644
index 000000000..745220d85
--- /dev/null
+++ b/sim/base_cpu.hh
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+
+#ifndef __BASE_CPU_HH__
+#define __BASE_CPU_HH__
+
+#include <vector>
+
+#include "eventq.hh"
+#include "sim_object.hh"
+
+#include "isa_traits.hh" // for Addr
+
+#ifdef FULL_SYSTEM
+class System;
+#endif
+
+class BranchPred;
+class ExecContext;
+
+class BaseCPU : public SimObject
+{
+#ifdef FULL_SYSTEM
+ protected:
+ int number;
+ Tick frequency;
+ uint8_t interrupts[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 check_interrupt(int int_num) const {
+ if (int_num > 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; }
+
+ Tick getFreq() const { return frequency; }
+#endif
+
+ protected:
+ std::vector<ExecContext *> contexts;
+
+ public:
+ virtual void execCtxStatusChg() {}
+
+ public:
+
+#ifdef FULL_SYSTEM
+ BaseCPU(const std::string &_name, int _number_of_threads,
+ Counter max_insts_any_thread, Counter max_insts_all_threads,
+ System *_system,
+ int num, Tick freq);
+#else
+ BaseCPU(const std::string &_name, int _number_of_threads,
+ Counter max_insts_any_thread = 0,
+ Counter max_insts_all_threads = 0);
+#endif
+
+ virtual ~BaseCPU() {}
+
+ virtual void regStats();
+
+ /// 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 **comInsnEventQueue;
+
+#ifdef FULL_SYSTEM
+ System *system;
+#endif
+
+ virtual bool filterThisInstructionPrefetch(int thread_number,
+ short asid, Addr prefetchTarget) const { return true; }
+
+ /// Return pointer to CPU's branch predictor (NULL if none).
+ virtual BranchPred *getBranchPred() { return NULL; };
+
+ private:
+ static std::vector<BaseCPU *> cpuList; //!< Static global cpu list
+
+ public:
+ static int numSimulatedCPUs() { return cpuList.size(); }
+};
+
+#endif // __BASE_CPU_HH__
diff --git a/sim/cache/lzss_compression.cc b/sim/cache/lzss_compression.cc
new file mode 100644
index 000000000..a1933215a
--- /dev/null
+++ b/sim/cache/lzss_compression.cc
@@ -0,0 +1,166 @@
+/*
+ * 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
+ * LZSSCompression definitions.
+ */
+
+#include <assert.h>
+
+#include "lzss_compression.hh"
+
+#include "misc.hh" //for fatal
+
+int
+LZSSCompression::findSubString(uint8_t *src, int front, int back, int size)
+{
+ int subSize = 0;
+ int max_length = 2048;
+ if (size - back < max_length) {
+ max_length = size - back;
+ }
+ for (int i = 0; i < max_length; ++i) {
+ if (src[front+i] != src[back+i]) {
+ return subSize;
+ }
+ ++subSize;
+ }
+ return subSize;
+}
+
+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;
+ }
+ for (int j = 0; j < i; ++j) {
+ int sub_size = findSubString(src, j, i, size);
+ if (sub_size >= L) {
+ L = sub_size;
+ P = j;
+ }
+ }
+ 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/sim/cache/lzss_compression.hh b/sim/cache/lzss_compression.hh
new file mode 100644
index 000000000..5fb47d3f1
--- /dev/null
+++ b/sim/cache/lzss_compression.hh
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+#ifndef __LZSS_COMPRESSION_HH__
+#define __LZSS_COMPRESSION_HH__
+
+/** @file
+ * LZSSCompression declarations.
+ */
+
+#include "host.hh" // for uint8_t
+
+/**
+ * Simple LZSS compression scheme.
+ */
+class LZSSCompression
+{
+ /**
+ * Finds the longest substrings that start at the given offsets.
+ * @param src The source block that we search for substrings.
+ * @param front The smaller offset.
+ * @param back The larger offset.
+ * @param size The size of the source block.
+ * @return The size of the longest substring.
+ */
+ int findSubString(uint8_t *src, int front, int back, int size);
+
+ /**
+ * 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/sim/cache/null_compression.hh b/sim/cache/null_compression.hh
new file mode 100644
index 000000000..d2bc76eef
--- /dev/null
+++ b/sim/cache/null_compression.hh
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#ifndef __NULL_COMPRESSION_HH__
+#define __NULL_COMPRESSION_HH__
+
+/**
+ * @file
+ * This file defines a doNothing compression algorithm.
+ */
+
+/**
+ * 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 //__NULL_COMPRESSION_HH__
diff --git a/sim/debug.cc b/sim/debug.cc
new file mode 100644
index 000000000..bfc5c9987
--- /dev/null
+++ b/sim/debug.cc
@@ -0,0 +1,137 @@
+/*
+ * 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.
+ */
+
+#include <sys/types.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+#include "debug.hh"
+#include "eventq.hh"
+#include "param.hh"
+#include "sim_events.hh"
+
+using namespace std;
+
+void
+debug_break()
+{
+ kill(getpid(), SIGTRAP);
+}
+
+//
+// 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)
+{
+ schedule(_when, -20000);
+}
+
+//
+// handle debug event: set debugger breakpoint on this function
+//
+void
+DebugBreakEvent::process()
+{
+ debug_break();
+ delete this;
+}
+
+
+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 dump_stats()
+{
+ new DumpStatsEvent();
+}
+
+extern "C" void eventq_dump()
+{
+ mainEventQueue.dump();
+}
+
diff --git a/sim/debug.hh b/sim/debug.hh
new file mode 100644
index 000000000..eb0be772e
--- /dev/null
+++ b/sim/debug.hh
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#ifndef __DEBUG_HH__
+#define __DEBUG_HH__
+
+void debug_break();
+
+#endif // __DEBUG_HH__
diff --git a/sim/eventq.cc b/sim/eventq.cc
new file mode 100644
index 000000000..36ef8aab2
--- /dev/null
+++ b/sim/eventq.cc
@@ -0,0 +1,212 @@
+/*
+ * 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.
+ */
+
+#include <assert.h>
+
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <vector>
+
+#include "smt.hh"
+#include "misc.hh"
+
+#include "eventq.hh"
+#include "trace.hh"
+#include "universe.hh"
+
+using namespace std;
+
+const string Event::defaultName("event");
+
+//
+// Main Event Queue
+//
+// Events on this queue are processed at the *beginning* of each
+// cycle, before the pipeline simulation is performed.
+//
+EventQueue mainEventQueue("Main Event Queue");
+
+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))
+ delete event;
+}
+
+void
+EventQueue::nameChildren()
+{
+ int j = 0;
+
+ Event *event = head;
+ while (event) {
+ stringstream stream;
+ ccprintf(stream, "%s.event%d", name(), j++);
+ event->setName(stream.str());
+
+ event = event->next;
+ }
+}
+
+void
+EventQueue::serialize()
+{
+ string objects = "";
+
+ Event *event = head;
+ while (event) {
+ objects += event->name();
+ objects += " ";
+ event->serialize();
+
+ event = event->next;
+ }
+ nameOut("Serialized");
+ paramOut("objects",objects);
+}
+
+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");
+}
+
+
+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()
+{
+#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\n", when());
+ }
+ else {
+ cprintf(" Not Scheduled\n");
+ }
+}
diff --git a/sim/eventq.hh b/sim/eventq.hh
new file mode 100644
index 000000000..71b027768
--- /dev/null
+++ b/sim/eventq.hh
@@ -0,0 +1,351 @@
+/*
+ * 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
+ * EventQueue interfaces
+ */
+
+#ifndef __EVENTQ_HH__
+#define __EVENTQ_HH__
+
+#include <assert.h>
+
+#include <algorithm>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "host.hh" // for Tick
+
+#include "fast_alloc.hh"
+#include "serialize.hh"
+#include "trace.hh"
+
+class EventQueue; // forward declaration
+
+/*
+ * 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 Serializeable, 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
+ };
+
+ 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:
+
+ static const std::string defaultName;
+
+ /*
+ * Event constructor
+ * @param queue that the event gets scheduled on
+ */
+ Event(EventQueue *q, int p = 0)
+ : Serializeable(defaultName), queue(q), next(NULL),
+ _priority(p), _flags(None),
+#if TRACING_ON
+ when_created(curTick), when_scheduled(0),
+#endif
+ annotated_value(0)
+ {
+ }
+
+ ~Event() {}
+
+ /// 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);
+
+ /// Schedule the event with a specific priority
+ void schedule(Tick t, int priority);
+
+ /// Reschedule the event with the current priority
+ void reschedule(Tick t);
+
+ /// Reschedule the event with a specific priority
+ void reschedule(Tick t, int priority);
+
+ /// 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();
+ }
+ };
+};
+
+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(AutoDestroy); schedule(when); }
+ void process() { (object->*F)(); }
+ const char *description() { return "delay"; }
+ };
+
+ new DelayEvent(when, object);
+}
+
+/*
+ * Queue of events sorted in time order
+ */
+class EventQueue : public Serializeable
+{
+ private:
+ Event *head;
+
+ void insert(Event *event);
+ void remove(Event *event);
+
+ public:
+
+ // constructor
+ EventQueue(const std::string &n)
+ : Serializeable(n), head(NULL)
+ {}
+
+ // 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;
+
+ 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 nameChildren();
+ virtual void serialize();
+};
+
+
+//////////////////////
+//
+// 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());
+ setFlags(Scheduled);
+#if TRACING_ON
+ when_scheduled = curTick;
+#endif
+ _when = t;
+ queue->schedule(this);
+}
+
+inline void
+Event::schedule(Tick t, int p)
+{
+ _priority = p;
+ schedule(t);
+}
+
+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
+Event::reschedule(Tick t, int p)
+{
+ _priority = p;
+ reschedule(t);
+}
+
+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");
+}
+
+
+//////////////////////
+//
+// 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;
+
+#endif // __EVENTQ_HH__
diff --git a/sim/exec_context.cc b/sim/exec_context.cc
new file mode 100644
index 000000000..c81d172a8
--- /dev/null
+++ b/sim/exec_context.cc
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ */
+
+#include <string>
+
+#include "base_cpu.hh"
+#include "exec_context.hh"
+
+#ifdef FULL_SYSTEM
+#include "system.hh"
+#else
+#include "prog.hh"
+#endif
+
+using namespace std;
+
+// constructor
+#ifdef FULL_SYSTEM
+ExecContext::ExecContext(BaseCPU *_cpu, int _thread_num, System *_sys,
+ AlphaItb *_itb, AlphaDtb *_dtb,
+ FunctionalMemory *_mem, int _cpu_id)
+ : kernelStats(this, _cpu), cpu(_cpu), thread_num(_thread_num), mem(_mem),
+ itb(_itb), dtb(_dtb), cpu_id(_cpu_id), system(_sys),
+ memCtrl(_sys->memCtrl), physmem(_sys->physmem)
+{
+ memset(&regs, 0, sizeof(RegFile));
+ _status = Active;
+ func_exe_insn = 0;
+ storeCondFailures = 0;
+ system->registerExecContext(this);
+}
+#else
+ExecContext::ExecContext(BaseCPU *_cpu, int _thread_num,
+ Process *_process, int _asid)
+ : cpu(_cpu), thread_num(_thread_num), process(_process), asid (_asid)
+{
+
+ // Register with process object. Our 'active' will be set by the
+ // process iff we're the initial context. Others are reserved for
+ // dynamically created threads.
+ process->registerExecContext(this);
+
+ mem = process->getMemory();
+
+ func_exe_insn = 0;
+ storeCondFailures = 0;
+}
+
+ExecContext::ExecContext(BaseCPU *_cpu, int _thread_num,
+ FunctionalMemory *_mem, int _asid)
+ : cpu(_cpu), thread_num(_thread_num), process(NULL), mem(_mem),
+ asid(_asid)
+{
+}
+#endif
+
+void
+ExecContext::setStatus(Status new_status)
+{
+#ifdef FULL_SYSTEM
+ if (status() == new_status)
+ return;
+
+ // Don't change the status from active if there are pending interrupts
+ if (new_status == Suspended && cpu->check_interrupts()) {
+ assert(status() == Active);
+ return;
+ }
+#endif
+
+ _status = new_status;
+ cpu->execCtxStatusChg();
+}
+
+void
+ExecContext::regStats(const string &name)
+{
+#ifdef FULL_SYSTEM
+ kernelStats.regStats(name + ".kern");
+#endif
+}
diff --git a/sim/exec_context.hh b/sim/exec_context.hh
new file mode 100644
index 000000000..56bce0aa9
--- /dev/null
+++ b/sim/exec_context.hh
@@ -0,0 +1,360 @@
+/*
+ * 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.
+ */
+
+#ifndef __EXEC_CONTEXT_HH__
+#define __EXEC_CONTEXT_HH__
+
+#include "host.hh"
+#include "stats.hh"
+#include "mem_req.hh"
+
+// forward declaration: see functional_memory.hh
+class FunctionalMemory;
+class PhysicalMemory;
+class BaseCPU;
+
+#ifdef FULL_SYSTEM
+
+#include "alpha_memory.hh"
+class MemoryController;
+
+#include "kernel_stats.hh"
+#include "system.hh"
+
+#else // !FULL_SYSTEM
+
+#include "prog.hh"
+
+#endif // FULL_SYSTEM
+
+//
+// The ExecContext object represents a functional context for
+// instruction execution. It incorporates everything required for
+// architecture-level functional simulation of a single thread.
+//
+
+class ExecContext
+{
+ public:
+ enum Status { Unallocated, Active, Suspended, Halted };
+
+ private:
+ Status _status;
+
+ public:
+ Status status() const { return _status; }
+ void setStatus(Status new_status);
+
+#ifdef FULL_SYSTEM
+ public:
+ KernelStats kernelStats;
+#endif
+
+ public:
+ RegFile regs; // correct-path register context
+
+ // pointer to CPU associated with this context
+ BaseCPU *cpu;
+
+ // Index of hardware thread context on the CPU that this represents.
+ int thread_num;
+
+#ifdef FULL_SYSTEM
+
+ FunctionalMemory *mem;
+ AlphaItb *itb;
+ AlphaDtb *dtb;
+ int cpu_id;
+ System *system;
+
+ // the following two fields are redundant, since we can always
+ // look them up through the system pointer, but we'll leave them
+ // here for now for convenience
+ MemoryController *memCtrl;
+ PhysicalMemory *physmem;
+
+#else
+ Process *process;
+
+ FunctionalMemory *mem; // functional storage for process address space
+
+ // 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
+
+
+ /*
+ * number of executed instructions, for matching with syscall trace
+ * points in EIO files.
+ */
+ Counter func_exe_insn;
+
+ //
+ // Count failed store conditionals so we can warn of apparent
+ // application deadlock situations.
+ unsigned storeCondFailures;
+
+ // constructor: initialize context from given process structure
+#ifdef FULL_SYSTEM
+ ExecContext(BaseCPU *_cpu, int _thread_num, System *_system,
+ AlphaItb *_itb, AlphaDtb *_dtb, FunctionalMemory *_dem,
+ int _cpu_id);
+#else
+ ExecContext(BaseCPU *_cpu, int _thread_num, Process *_process, int _asid);
+ ExecContext(BaseCPU *_cpu, int _thread_num, FunctionalMemory *_mem,
+ int _asid);
+#endif
+ virtual ~ExecContext() {}
+
+ void regStats(const std::string &name);
+
+#ifdef FULL_SYSTEM
+ bool validInstAddr(Addr addr) { return true; }
+ bool validDataAddr(Addr addr) { return true; }
+ int getInstAsid() { return ITB_ASN_ASN(regs.ipr[TheISA::IPR_ITB_ASN]); }
+ int getDataAsid() { return DTB_ASN_ASN(regs.ipr[TheISA::IPR_DTB_ASN]); }
+
+ 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 process->validInstAddr(addr); }
+
+ bool validDataAddr(Addr addr)
+ { return process->validDataAddr(addr); }
+
+ int getInstAsid() { return asid; }
+ int getDataAsid() { return 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 No_Fault;
+ }
+ 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(MemReqPtr req, T& data)
+ {
+#if defined(TARGET_ALPHA) && defined(FULL_SYSTEM)
+ if (req->flags & LOCKED) {
+ MiscRegFile *cregs = &req->xc->regs.miscRegs;
+ cregs->lock_addr = req->paddr;
+ cregs->lock_flag = true;
+ }
+#endif
+ return mem->read(req, data);
+ }
+
+ template <class T>
+ Fault write(MemReqPtr req, T& data)
+ {
+#if defined(TARGET_ALPHA) && defined(FULL_SYSTEM)
+
+ MiscRegFile *cregs;
+
+ // If this is a store conditional, act appropriately
+ if (req->flags & LOCKED) {
+ cregs = &req->xc->regs.miscRegs;
+
+ if (req->flags & UNCACHEABLE) {
+ // Don't update result register (see machine.def)
+ req->result = 2;
+ req->xc->storeCondFailures = 0;//Needed? [RGD]
+ } else {
+ req->result = cregs->lock_flag;
+ if (!cregs->lock_flag ||
+ ((cregs->lock_addr & ~0xf) != (req->paddr & ~0xf))) {
+ cregs->lock_flag = false;
+ if (((++req->xc->storeCondFailures) % 100000) == 0) {
+ std::cerr << "Warning: "
+ << req->xc->storeCondFailures
+ << " consecutive store conditional failures "
+ << "on cpu " << req->xc->cpu_id
+ << std::endl;
+ }
+ return No_Fault;
+ }
+ else req->xc->storeCondFailures = 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?)
+ // Unsuccesful Store Conditionals would have returned above,
+ // and wouldn't fall through
+ for(int i = 0; i < system->num_cpus; i++){
+ cregs = &system->xc_array[i]->regs.miscRegs;
+ if((cregs->lock_addr & ~0xf) == (req->paddr & ~0xf)) {
+ cregs->lock_flag = false;
+ }
+ }
+
+#endif
+ return mem->write(req, data);
+ }
+
+ virtual bool misspeculating();
+
+
+ //
+ // New accessors for new decoder.
+ //
+ uint64_t readIntReg(int reg_idx)
+ {
+ return regs.intRegFile[reg_idx];
+ }
+
+ float readFloatRegSingle(int reg_idx)
+ {
+ return (float)regs.floatRegFile.d[reg_idx];
+ }
+
+ double readFloatRegDouble(int reg_idx)
+ {
+ return regs.floatRegFile.d[reg_idx];
+ }
+
+ uint64_t readFloatRegInt(int reg_idx)
+ {
+ return regs.floatRegFile.q[reg_idx];
+ }
+
+ void setIntReg(int reg_idx, uint64_t val)
+ {
+ regs.intRegFile[reg_idx] = val;
+ }
+
+ void setFloatRegSingle(int reg_idx, float val)
+ {
+ regs.floatRegFile.d[reg_idx] = (double)val;
+ }
+
+ void setFloatRegDouble(int reg_idx, double val)
+ {
+ regs.floatRegFile.d[reg_idx] = val;
+ }
+
+ void setFloatRegInt(int reg_idx, uint64_t val)
+ {
+ regs.floatRegFile.q[reg_idx] = val;
+ }
+
+ uint64_t readPC()
+ {
+ return regs.pc;
+ }
+
+ void setNextPC(uint64_t val)
+ {
+ regs.npc = val;
+ }
+
+ uint64_t readUniq()
+ {
+ return regs.miscRegs.uniq;
+ }
+
+ void setUniq(uint64_t val)
+ {
+ regs.miscRegs.uniq = val;
+ }
+
+ uint64_t readFpcr()
+ {
+ return regs.miscRegs.fpcr;
+ }
+
+ void setFpcr(uint64_t val)
+ {
+ regs.miscRegs.fpcr = val;
+ }
+
+#ifdef FULL_SYSTEM
+ uint64_t readIpr(int idx, Fault &fault);
+ Fault setIpr(int idx, uint64_t val);
+ Fault hwrei();
+ void ev5_trap(Fault fault);
+ bool simPalCheck(int palFunc);
+#endif
+
+#ifndef FULL_SYSTEM
+ void syscall()
+ {
+ process->syscall(this);
+ }
+#endif
+};
+
+
+// for non-speculative execution context, spec_mode is always false
+inline bool
+ExecContext::misspeculating()
+{
+ return false;
+}
+
+#endif // __EXEC_CONTEXT_HH__
diff --git a/sim/exetrace.cc b/sim/exetrace.cc
new file mode 100644
index 000000000..4c5d14893
--- /dev/null
+++ b/sim/exetrace.cc
@@ -0,0 +1,190 @@
+/*
+ * 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.
+ */
+
+#include <fstream>
+#include <iomanip>
+
+#include "dyn_inst.hh"
+#include "spec_state.hh"
+#include "issue.hh"
+#include "exetrace.hh"
+#include "exec_context.hh"
+#include "symtab.hh"
+#include "base_cpu.hh"
+#include "static_inst.hh"
+
+using namespace std;
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Methods for the InstRecord object
+//
+
+
+const SymbolTable *debugSymbolTable = NULL;
+
+void
+Trace::InstRecord::dump(ostream &outs)
+{
+ 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 << " : ";
+
+ 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() < 25)
+ mc += " ";
+ outs << mc;
+#else
+ outs << setw(25) << 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 < 32;)
+ for (int j = i + 1; i <= j; i++)
+ ccprintf(outs, "r%02d = %#018x%s", i, iregs->regs[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;
+ outs.flush();
+}
+
+
+vector<bool> Trace::InstRecord::flags(NUM_BITS);
+
+////////////////////////////////////////////////////////////////////////
+//
+// 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", false);
+
+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);
+
+//
+// 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;
+}
+
+void
+ExecutionTraceParamContext::checkParams()
+{
+ Trace::InstRecord::setParams();
+}
+
diff --git a/sim/exetrace.hh b/sim/exetrace.hh
new file mode 100644
index 000000000..d5b9dc218
--- /dev/null
+++ b/sim/exetrace.hh
@@ -0,0 +1,197 @@
+/*
+ * 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.
+ */
+
+#ifndef __EXETRACE_HH__
+#define __EXETRACE_HH__
+
+#include <fstream>
+#include <vector>
+
+#include "host.hh"
+#include "std_types.hh" // for InstSeqNum
+#include "trace.hh"
+#include "exec_context.hh"
+#include "static_inst.hh"
+
+class BaseCPU;
+
+
+namespace Trace {
+
+#if 0
+ static const FlagVec ALL = ULL(0x1);
+ static const FlagVec FULL = ULL(0x2);
+ static const FlagVec SYMBOLS = ULL(0x4);
+ static const FlagVec EXTENDED = ULL(0x8);
+ static const FlagVec BRANCH_TAKEN = ULL(0x10);
+ static const FlagVec BRANCH_NOTTAKEN = ULL(0x20);
+ static const FlagVec CALLPAL = ULL(0x40);
+ static const FlagVec SPECULATIVE = ULL(0x100);
+ static const FlagVec OMIT_COUNT = ULL(0x200);
+ static const FlagVec INCLUDE_THREAD_NUM = ULL(0x400);
+#endif
+
+class InstRecord : public Record
+{
+ protected:
+
+ // 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<TheISA> 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, StaticInstPtr<TheISA> _staticInst,
+ Addr _pc, bool spec, unsigned _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,
+ NUM_BITS
+ };
+
+ static std::vector<bool> flags;
+
+ 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<TheISA> 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/sim/host.hh b/sim/host.hh
new file mode 100644
index 000000000..489c4e042
--- /dev/null
+++ b/sim/host.hh
@@ -0,0 +1,57 @@
+/*
+ * 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
+ * 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) N##ULL
+/** int64_t constant */
+#define LL(N) 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;
+
+#endif // __HOST_H__
diff --git a/sim/hybrid_pred.cc b/sim/hybrid_pred.cc
new file mode 100644
index 000000000..6a8384083
--- /dev/null
+++ b/sim/hybrid_pred.cc
@@ -0,0 +1,275 @@
+/*
+ * 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.
+ */
+
+#include <string>
+#include <sstream>
+
+#include "stats.hh"
+#include "hybrid_pred.hh"
+
+#include "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 Statistics;
+
+ 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 Statistics;
+
+ 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/sim/hybrid_pred.hh b/sim/hybrid_pred.hh
new file mode 100644
index 000000000..f6e14e3e3
--- /dev/null
+++ b/sim/hybrid_pred.hh
@@ -0,0 +1,203 @@
+/*
+ * 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.
+ */
+
+//==========================================================================
+//
+// 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 "sat_counter.hh"
+
+#include "statistics.hh"
+#include "sim_stats.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
+ //
+ Statistics::Scalar<> pred_one; //num_one_preds
+ Statistics::Scalar<> pred_zero; //num_zero_preds
+ Statistics::Scalar<> correct_pred_one; //num_one_correct
+ Statistics::Scalar<> correct_pred_zero; //num_zero_correct
+ Statistics::Scalar<> record_one; //num_one_updates
+ Statistics::Scalar<> record_zero; //num_zero_updates
+
+ Statistics::Formula total_preds;
+ Statistics::Formula frac_preds_zero;
+ Statistics::Formula frac_preds_one;
+ Statistics::Formula total_correct;
+ Statistics::Formula total_accuracy;
+ Statistics::Formula zero_accuracy;
+ Statistics::Formula one_accuracy;
+ Statistics::Formula zero_coverage;
+ Statistics::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/sim/intr_control.cc b/sim/intr_control.cc
new file mode 100644
index 000000000..7ad32a2b9
--- /dev/null
+++ b/sim/intr_control.cc
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#include <string>
+#include <vector>
+
+#include "base_cpu.hh"
+#include "intr_control.hh"
+#include "sim_object.hh"
+
+using namespace std;
+
+IntrControl::IntrControl(const string &name, BaseCPU *c)
+ : SimObject(name), cpu(c)
+{}
+
+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 processor")
+
+END_INIT_SIM_OBJECT_PARAMS(IntrControl)
+
+CREATE_SIM_OBJECT(IntrControl)
+{
+ return new IntrControl(getInstanceName(), cpu);
+}
+
+REGISTER_SIM_OBJECT("IntrControl", IntrControl)
diff --git a/sim/intr_control.hh b/sim/intr_control.hh
new file mode 100644
index 000000000..660d6d704
--- /dev/null
+++ b/sim/intr_control.hh
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#ifndef __INTR_CONTROL_HH__
+#define __INTR_CONTROL_HH__
+
+#include "misc.hh"
+#include "base_cpu.hh"
+#include "sim_object.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);
+};
+
+inline void
+IntrControl::post(int int_num, int index)
+{ cpu->post_interrupt(int_num, index); }
+
+inline void
+IntrControl::clear(int int_num, int index)
+{ cpu->clear_interrupt(int_num, index); }
+
+#endif // __INTR_CONTROL_HH__
+
+
+
+
+
+
+
diff --git a/sim/main.cc b/sim/main.cc
new file mode 100644
index 000000000..84f8e78cc
--- /dev/null
+++ b/sim/main.cc
@@ -0,0 +1,429 @@
+/*
+ * 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 sim/main.cc
+///
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <signal.h>
+
+#include <string>
+#include <vector>
+
+#include "host.hh"
+#include "misc.hh"
+#include "stats.hh"
+
+#include "copyright.hh"
+#include "inifile.hh"
+#include "configfile.hh"
+#include "pollevent.hh"
+#include "statistics.hh"
+#include "sim_events.hh"
+#include "sim_exit.hh"
+#include "sim_object.hh"
+#include "sim_stats.hh"
+#include "sim_time.hh"
+#include "smt.hh"
+
+#include "base_cpu.hh"
+#include "async.hh"
+
+using namespace std;
+
+// See async.h.
+volatile bool async_event = false;
+volatile bool async_dump = 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;
+}
+
+/// Exit signal handler.
+void
+exitNowHandler(int sigtype)
+{
+ async_event = true;
+ async_exit = true;
+}
+
+/// Simulator executable name
+const char *myProgName = "";
+
+/// Show brief help message.
+static void
+showBriefHelp(ostream &out)
+{
+ out << "Usage: " << myProgName
+ << " [-hn] [-Dname[=def]] [-Uname] [-I[dir]] "
+ << "[--<section>:<param>=<value>] [<config file> ...]" << endl
+ << " -h: print long help (including parameter listing)" << endl
+ << " -n: don't load default.ini" << endl
+ << " -u: don't quit on unreferenced parameters" << endl
+ << " -D,-U,-I: passed to cpp for preprocessing .ini files" << endl;
+}
+
+/// Show verbose help message. Includes parameter listing from
+/// showBriefHelp(), plus an exhaustive list of ini-file parameters
+/// and SimObjects (with their parameters).
+static void
+showLongHelp(ostream &out)
+{
+ showBriefHelp(out);
+
+ out << endl
+ << endl
+ << "-----------------" << endl
+ << "Global Parameters" << endl
+ << "-----------------" << endl
+ << endl;
+
+ ParamContext::describeAllContexts(out);
+
+ out << endl
+ << endl
+ << "-----------------" << endl
+ << "Simulator Objects" << endl
+ << "-----------------" << endl
+ << endl;
+
+ SimObjectClass::describeAllClasses(out);
+}
+
+/// Print welcome message.
+static 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).
+///
+static 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;
+}
+
+
+///
+/// The simulator configuration database. This is the union of all
+/// specified .ini files. This shouldn't need to be visible outside
+/// this file, as it is passed as a parameter to all the param-parsing
+/// routines.
+///
+static IniFile simConfigDB;
+
+/// Check for a default.ini file and load it if necessary.
+static void
+handleDefaultIni(bool &loadIt, vector<char *> &cppArgs)
+{
+ struct stat sb;
+
+ if (loadIt) {
+ if (stat("default.ini", &sb) == 0) {
+ if (!simConfigDB.loadCPP("default.ini", cppArgs)) {
+ cout << "Error processing file default.ini" << endl;
+ exit(1);
+ }
+ }
+
+ // set this whether it actually was found or not, so we don't
+ // bother to check again next time
+ loadIt = false;
+ }
+}
+
+
+/// M5 entry point.
+int
+main(int argc, char **argv)
+{
+ // Save off program name
+ myProgName = argv[0];
+
+ signal(SIGFPE, SIG_IGN); // may occur on misspeculated paths
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGTRAP, SIG_IGN);
+ signal(SIGUSR1, dumpStatsHandler); // dump intermediate stats
+ signal(SIGINT, exitNowHandler); // dump final stats and exit
+
+ sayHello(cerr);
+
+ // Initialize statistics database
+ init_old_stats();
+ initBaseStats();
+
+ vector<char *> cppArgs;
+
+ // Should we use default.ini if it exists? By default, yes. (Use
+ // -n to override.)
+ bool loadDefaultIni = true;
+
+ // Should we quit if there are unreferenced parameters? By
+ // default, yes... it's a good way of catching typos in
+ // section/parameter names (which otherwise go by silently). Use
+ // -u to override.
+ bool quitOnUnreferenced = true;
+
+ // Parse command-line options. The tricky part here is figuring
+ // out whether to look for & load default.ini, and if needed,
+ // doing so at the right time w.r.t. processing the other
+ // parameters.
+ //
+ // 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 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 'h':
+ // -h: show help
+ showLongHelp(cerr);
+ exit(1);
+
+ case 'n':
+ // -n: don't load default.ini
+ if (!loadDefaultIni) {
+ cerr << "Warning: -n option needs to precede any "
+ << "explicit configuration file name " << endl
+ << " or command-line configuration parameter."
+ << endl;
+ }
+ loadDefaultIni = false;
+ break;
+
+ case 'u':
+ // -u: don't quit on unreferenced parameters
+ quitOnUnreferenced = false;
+ break;
+
+ 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>'
+
+ // Load default.ini if necessary -- see comment in
+ // else clause below.
+ handleDefaultIni(loadDefaultIni, cppArgs);
+
+ 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:
+ showBriefHelp(cerr);
+ ccprintf(cerr, "Fatal: invalid argument '%s'\n", arg_str);
+ exit(0);
+ }
+ }
+ else {
+ // no '-', treat as config file name
+
+ // If we haven't loaded default.ini yet, and we want to,
+ // now is the time. Can't do it sooner because we need to
+ // look for '-n', can't do it later since we want
+ // default.ini loaded first (so that any other settings
+ // override it).
+ handleDefaultIni(loadDefaultIni, cppArgs);
+
+ if (!simConfigDB.loadCPP(arg_str, cppArgs)) {
+ cprintf("Error processing file %s\n", arg_str);
+ exit(1);
+ }
+ }
+ }
+
+ // Final check for default.ini, in case no config files or
+ // command-line config parameters were given.
+ handleDefaultIni(loadDefaultIni, cppArgs);
+
+ // The configuration database is now complete; start processing it.
+
+ // Parse and check all non-config-hierarchy parameters.
+ ParamContext::parseAllContexts(simConfigDB);
+ ParamContext::checkAllContexts();
+
+ // Print header info into stats file. Can't do this sooner since
+ // the stat file name is set via a .ini param... thus it just got
+ // opened above during 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 (statStreamIsFile)
+ sayHello(*statStream);
+
+ // Echo command line and all parameter settings to stats file as well.
+ echoCommandLine(argc, argv, *statStream);
+ ParamContext::showAllContexts(*statStream);
+
+ // Now process the configuration hierarchy and create the SimObjects.
+ ConfigHierarchy configHierarchy(simConfigDB);
+ configHierarchy.build();
+ configHierarchy.createSimObjects();
+
+ // Restore checkpointed state, if any.
+ configHierarchy.unserializeSimObjects();
+
+ // Done processing the configuration database.
+ // Check for unreferenced entries.
+ if (simConfigDB.printUnreferenced() && quitOnUnreferenced) {
+ cerr << "Fatal: unreferenced .ini sections/entries." << endl
+ << "If this is not an error, add 'unref_section_ok=y' or "
+ << "'unref_entries_ok=y' to the appropriate sections "
+ << "to suppress this message." << endl;
+ exit(1);
+ }
+
+ 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
+ Statistics::check();
+
+ // Nothing to simulate if we don't have at least one CPU somewhere.
+ if (BaseCPU::numSimulatedCPUs() == 0) {
+ cerr << "Fatal: no CPUs to simulate." << endl;
+ exit(1);
+ }
+
+ 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;
+ new DumpStatsEvent();
+ }
+
+ 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("improperly exited event loop!", 1);
+
+ return 0;
+}
diff --git a/sim/memtest.cc b/sim/memtest.cc
new file mode 100644
index 000000000..70b6fbf13
--- /dev/null
+++ b/sim/memtest.cc
@@ -0,0 +1,324 @@
+/*
+ * 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.
+ */
+
+// FIX ME: make trackBlkAddr use blocksize from actual cache, not hard coded
+
+#include <string>
+#include <sstream>
+#include <iomanip>
+#include <vector>
+
+#include "memtest.hh"
+#include "misc.hh"
+#include "sim_events.hh"
+#include "main_memory.hh"
+#include "base_cache.hh"
+
+#include "statistics.hh"
+#include "sim_stats.hh"
+
+using namespace std;
+
+MemTest::MemTest(const string &name,
+ MemInterface *_cache_interface,
+ FunctionalMemory *main_mem,
+ FunctionalMemory *check_mem,
+ unsigned _memorySize,
+ unsigned _percentReads,
+ unsigned _percentUncacheable,
+ unsigned _maxReads,
+ unsigned _progressInterval,
+ Addr _traceAddr)
+ : BaseCPU(name, 1),
+ tickEvent(this),
+ cacheInterface(_cache_interface),
+ mainMem(main_mem),
+ checkMem(check_mem),
+ size(_memorySize),
+ percentReads(_percentReads),
+ percentUncacheable(_percentUncacheable),
+ maxReads(_maxReads),
+ progressInterval(_progressInterval),
+ nextProgressMessage(_progressInterval)
+{
+ vector<string> cmd;
+ cmd.push_back("/bin/ls");
+ vector<string> null_vec;
+ xc = new ExecContext(this ,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;
+ numWrites = 0;
+ tickEvent.schedule(0);
+}
+
+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)
+{
+ switch (req->cmd) {
+ case Read:
+ if (memcmp(req->data, data, req->size) != 0) {
+ cerr << name() << ": on read of 0x" << hex << 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++;
+
+ if (numReads.val() == nextProgressMessage) {
+ cerr << name() << ": completed " << numReads.val()
+ << " read accesses @ " << curTick << endl;
+ nextProgressMessage += progressInterval;
+ }
+
+ if (numReads.val() == maxReads) {
+ stringstream stream;
+ stream << name() << " reached max read count (" << maxReads
+ << ")" << endl;
+
+ new SimExitEvent(stream.str());
+ }
+ break;
+
+ case Write:
+ numWrites++;
+ break;
+
+
+ default:
+ panic("invalid command");
+ }
+
+ if (blockAddr(req->paddr) == traceBlockAddr) {
+ cerr << name() << ": completed "
+ << (req->cmd.isWrite() ? "write" : "read") << " access of "
+ << req->size << " bytes at address 0x"
+ << hex << req->paddr << ", value = 0x";
+ printData(cerr, req->data, req->size);
+ cerr << endl;
+ }
+
+ noResponseCycles = 0;
+ delete [] data;
+}
+
+
+void
+MemTest::regStats()
+{
+ using namespace Statistics;
+
+ numReads
+ .name(name() + ".num_reads")
+ .desc("number of read accesses completed")
+ ;
+
+ numWrites
+ .name(name() + ".num_writes")
+ .desc("number of write accesses completed")
+ ;
+
+ numCopies
+ .name(name() + ".num_copies")
+ .desc("number of copy accesses completed")
+ ;
+}
+
+void
+MemTest::tick()
+{
+ if (!tickEvent.scheduled())
+ tickEvent.schedule(curTick + 1);
+
+ if (++noResponseCycles >= 5000) {
+ cerr << name() << ": deadlocked at cycle " << curTick << endl;
+ fatal("");
+ }
+
+ if (cacheInterface->isBlocked()) {
+ return;
+ }
+
+ //make new request
+ unsigned cmd = rand() % 100;
+ unsigned offset1 = random() % size;
+ unsigned base = random() % 2;
+ uint64_t data = random();
+ unsigned access_size = random() % 4;
+ unsigned cacheable = rand() % 100;
+
+ MemReqPtr req = new MemReq();
+
+ if (cacheable < percentUncacheable) {
+ req->flags |= UNCACHEABLE;
+ req->paddr = uncacheAddr + offset1;
+ } else {
+ req->paddr = ((base) ? baseAddr1 : baseAddr2) + offset1;
+ }
+
+ req->size = 1 << access_size;
+ req->data = new uint8_t[req->size];
+ req->paddr &= ~(req->size - 1);
+ req->time = curTick;
+ req->xc = xc;
+
+ if (cmd < percentReads) {
+ // read
+ 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 of "
+ << req->size << " bytes from addr 0x"
+ << hex << req->paddr << " at cycle "
+ << dec << curTick << endl;
+ }
+
+ req->completionEvent = new MemCompleteEvent(req, result, this);
+ cacheInterface->access(req);
+ } else {
+ // write
+ 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 of "
+ << req->size << " bytes (value = 0x";
+ printData(cerr, req->data, req->size);
+ cerr << ") to addr 0x"
+ << hex << req->paddr << " at cycle "
+ << dec << curTick << endl;
+ }
+ req->completionEvent = new MemCompleteEvent(req, NULL, this);
+ cacheInterface->access(req);
+ }
+}
+
+
+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_uncacheable;
+ Param<unsigned> max_reads;
+ Param<unsigned> progress_interval;
+ Param<Addr> trace_addr;
+
+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_DFLT(memory_size, "memory size", 65536),
+ INIT_PARAM_DFLT(percent_reads, "target read percentage", 65),
+ INIT_PARAM_DFLT(percent_uncacheable, "target uncacheable percentage", 10),
+ INIT_PARAM_DFLT(max_reads, "number of reads to simulate", 0),
+ INIT_PARAM_DFLT(progress_interval,
+ "progress report interval (in accesses)", 1000000),
+ INIT_PARAM_DFLT(trace_addr, "address to trace", 0)
+
+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_uncacheable, max_reads, progress_interval,
+ trace_addr);
+}
+
+REGISTER_SIM_OBJECT("MemTest", MemTest)
diff --git a/sim/memtest.hh b/sim/memtest.hh
new file mode 100644
index 000000000..aa652abbd
--- /dev/null
+++ b/sim/memtest.hh
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ */
+
+#ifndef __MEMTEST_HH__
+#define __MEMTEST_HH__
+
+#include "sim_object.hh"
+#include "mem_interface.hh"
+#include "functional_memory.hh"
+#include "base_cpu.hh"
+#include "exec_context.hh"
+
+#include "statistics.hh"
+#include "sim_stats.hh"
+
+class MemTest : public BaseCPU
+{
+ public:
+
+ MemTest(const std::string &name,
+ MemInterface *_cache_interface,
+ FunctionalMemory *main_mem,
+ FunctionalMemory *check_mem,
+ unsigned _memorySize,
+ unsigned _percentReads,
+ unsigned _percentUncacheable,
+ unsigned _maxReads,
+ unsigned _progressInterval,
+ Addr _traceAddr);
+
+ // register statistics
+ virtual void regStats();
+ // main simulation loop (one cycle)
+ void tick();
+
+ protected:
+ class TickEvent : public Event
+ {
+ private:
+ MemTest *cpu;
+ public:
+ TickEvent(MemTest *c)
+ : Event(&mainEventQueue, 100), cpu(c) {}
+ void process() {cpu->tick();}
+ virtual const char *description() { return "tick event"; }
+ };
+
+ TickEvent tickEvent;
+
+ MemInterface *cacheInterface;
+ FunctionalMemory *mainMem;
+ FunctionalMemory *checkMem;
+ ExecContext *xc;
+
+ unsigned size; // size of testing memory region
+
+ unsigned percentReads; // target percentage of read accesses
+ unsigned percentUncacheable;
+
+ Tick maxReads; // max # of reads to perform (then quit)
+
+ 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
+
+ Tick noResponseCycles;
+
+ Statistics::Scalar<long long int> numReads;
+ Statistics::Scalar<long long int> numWrites;
+ Statistics::Scalar<long long int> numCopies;
+
+ // 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 // __MEMTEST_HH__
+
+
+
diff --git a/sim/op_class.hh b/sim/op_class.hh
new file mode 100644
index 000000000..67ccaabad
--- /dev/null
+++ b/sim/op_class.hh
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+#ifndef __OP_CLASS_HH__
+#define __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, /* inst does not use a functional unit */
+ IntALU, /* integer ALU */
+ IntMULT, /* integer multiplier */
+ IntDIV, /* integer divider */
+ FloatADD, /* floating point adder/subtractor */
+ FloatCMP, /* floating point comparator */
+ FloatCVT, /* floating point<->integer converter */
+ FloatMULT, /* floating point multiplier */
+ FloatDIV, /* floating point divider */
+ FloatSQRT, /* floating point square root */
+ RdPort, /* memory read port */
+ WrPort, /* memory write port */
+ LvqPort, /* load value queue read port (redundant threading) */
+ IPrefPort,
+ Num_OpClasses /* total functional unit classes */
+};
+
+/**
+ * Array mapping OpClass enum values to strings.
+ */
+extern const char *opClassStrings[];
+
+#endif // __OP_CLASS_HH__
diff --git a/sim/param.cc b/sim/param.cc
new file mode 100644
index 000000000..432953670
--- /dev/null
+++ b/sim/param.cc
@@ -0,0 +1,760 @@
+/*
+ * 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.
+ */
+
+#include <algorithm>
+#include <list>
+#include <string>
+#include <vector>
+#include <stdio.h> // for sscanf()
+
+#include <assert.h>
+
+#include "param.hh"
+#include "sim_object.hh"
+#include "inifile.hh"
+#include "configfile.hh"
+#include "config_node.hh"
+#include "misc.hh"
+#include "str.hh"
+#include "trace.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.
+//
+////////////////////////////////////////////////////////////////////////
+
+//
+// Integer types all use to_number for parsing and '<<' for
+// displaying
+//
+#define INT_PARAM(type) \
+bool \
+parseParam(const string &s, type &value) \
+{ \
+ return to_number(s, value); \
+} \
+ \
+void \
+showParam(ostream &os, type value) \
+{ \
+ os << value; \
+}
+
+INT_PARAM(unsigned long long)
+INT_PARAM(signed long long)
+INT_PARAM(unsigned long)
+INT_PARAM(signed long)
+INT_PARAM(unsigned int)
+INT_PARAM(signed int)
+INT_PARAM(unsigned short)
+INT_PARAM(signed short)
+INT_PARAM(unsigned char)
+INT_PARAM(signed char)
+
+#undef INT_PARAM
+
+//
+// Floating-point types
+//
+bool
+parseParam(const string &s, float &value)
+{
+ return (sscanf(s.c_str(), "%f", &value) == 1);
+}
+
+bool
+parseParam(const string &s, double &value)
+{
+ return (sscanf(s.c_str(), "%lf", &value) == 1);
+}
+
+void showParam(ostream &os, float value) { os << value; }
+void showParam(ostream &os, double value) { os << value; }
+
+//
+// bool
+//
+bool
+parseParam(const string &s, bool &value)
+{
+ const string &lower = to_lower(s);
+
+ if (lower == "true" || lower == "t" || lower == "yes" || lower == "y") {
+ value = true;
+ return true;
+ }
+
+ if (lower == "false" || lower == "f" || lower == "no" || lower == "n") {
+ value = false;
+ return true;
+ }
+
+ return false;
+}
+
+
+void
+showParam(ostream &os, bool value)
+{
+ os << (value ? "true" : "false");
+}
+
+
+//
+// string
+//
+bool
+parseParam(const string &s, string &value)
+{
+ value = s;
+ return true;
+}
+
+
+void
+showParam(ostream &os, const string &value)
+{
+ os << value;
+}
+
+//
+// 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)
+{
+ 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 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; \
+void Param<type>::showType(ostream &os) const { os << typestr; } \
+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")
+
+#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;
+
+ 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 EnumParam<const char *>;
+template EnumVectorParam<const char *>;
+
+template EnumParam<EnumParamMap>;
+template 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, bool noAutoParse)
+ : iniFilePtr(NULL), // initialized on call to parseParams()
+ iniSection(_iniSection), paramList(NULL)
+{
+ if (!noAutoParse) {
+ if (ctxList == NULL)
+ ctxList = new list<ParamContext *>();
+
+ (*ctxList).push_back(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.findDefault(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)
+{
+ // look for a colon
+ string::size_type i = _name.find(':');
+ string name = _name;
+ if (i != string::npos) {
+ // colon found: local object
+ // add as child to current node and create it
+ name = _name.substr(0, i);
+ string objConfigClassName = _name.substr(i + 1);
+ getConfigNode()->addChild(name, objConfigClassName);
+ }
+ 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/sim/param.hh b/sim/param.hh
new file mode 100644
index 000000000..983032854
--- /dev/null
+++ b/sim/param.hh
@@ -0,0 +1,757 @@
+/*
+ * 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.
+ */
+
+#ifndef __PARAM_HH__
+#define __PARAM_HH__
+
+#include <list>
+#include <string>
+#include <vector>
+
+#include "configfile.hh"
+
+// forward decls
+class BaseParam;
+class SimObject;
+struct stat_sdb_t;
+
+//
+// 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
+{
+ 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:
+
+ // Second arg, if set to true, says don't put on paramContextList
+ // (i.e. don't automatically parse params). Used by derived
+ // SimObjectBuilder class, where parsing is done in
+ // SimObject::create()
+ ParamContext(const std::string &_iniSection, bool noAutoParse = false);
+
+ 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[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) \
+void \
+SimObjectParam<OBJ_CLASS *>::showType(std::ostream &os) const \
+{ \
+ os << CLASS_NAME; \
+} \
+ \
+void \
+SimObjectVectorParam<OBJ_CLASS *>::showType(std::ostream &os) const \
+{ \
+ os << "vector of " << CLASS_NAME; \
+}
+
+#endif // _PARAM_HH
diff --git a/sim/pc_event.cc b/sim/pc_event.cc
new file mode 100644
index 000000000..4de425199
--- /dev/null
+++ b/sim/pc_event.cc
@@ -0,0 +1,231 @@
+/*
+ * 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.
+ */
+
+#include <algorithm>
+#include <map>
+#include <string>
+#include <utility>
+
+#include "debug.hh"
+#include "exec_context.hh"
+#include "pc_event.hh"
+#include "trace.hh"
+#include "universe.hh"
+
+#ifdef FULL_SYSTEM
+#include "arguments.hh"
+#include "pmap.h"
+#include "kernel.hh"
+#include "memory_control.hh"
+#include "cpu.hh"
+#include "system.hh"
+#include "bpred.hh"
+#endif
+
+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::service(ExecContext *xc)
+{
+ Addr pc = xc->regs.pc;
+ 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->regs.pc)
+ 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());
+}
+
+#ifdef FULL_SYSTEM
+void
+SkipFuncEvent::process(ExecContext *xc)
+{
+ Addr newpc = xc->regs.intRegFile[ReturnAddressReg];
+
+ DPRINTF(PCEvent, "skipping %s: pc=%x, newpc=%x\n", description,
+ xc->regs.pc, newpc);
+
+ xc->regs.pc = newpc;
+ xc->regs.npc = xc->regs.pc + sizeof(MachInst);
+
+ BranchPred *bp = xc->cpu->getBranchPred();
+ if (bp != NULL) {
+ bp->popRAS(xc->thread_num);
+ }
+}
+
+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->regs.intRegFile[ArgumentReg0];
+
+ if (a0 < ALPHA_K0SEG_BASE || a0 >= ALPHA_K1SEG_BASE ||
+ xc->memCtrl->badaddr(ALPHA_K0SEG_TO_PHYS(a0) & PA_IMPL_MASK)) {
+
+ DPRINTF(BADADDR, "badaddr arg=%#x bad\n", a0);
+ xc->regs.intRegFile[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->cpu->name() << ": ";
+
+ AlphaArguments args(xc);
+ Kernel::Printf(args);
+ }
+}
+
+void
+DebugPrintfEvent::process(ExecContext *xc)
+{
+ if (DTRACE(DebugPrintf)) {
+ if (!raw)
+ DebugOut() << curTick << ": " << xc->cpu->name() << ": ";
+
+ AlphaArguments args(xc);
+ Kernel::Printf(args);
+ }
+}
+
+void
+DumpMbufEvent::process(ExecContext *xc)
+{
+ if (DTRACE(DebugPrintf)) {
+ AlphaArguments args(xc);
+ Kernel::DumpMbuf(args);
+ }
+}
+#endif
+
+BreakPCEvent::BreakPCEvent(PCEventQueue *q, const std::string &desc, bool del)
+ : PCEvent(q, desc), remove(del)
+{
+}
+
+void
+BreakPCEvent::process(ExecContext *xc)
+{
+ debug_break();
+ if (remove)
+ delete this;
+}
+
+#ifdef FULL_SYSTEM
+extern "C"
+void
+sched_break_pc_sys(System *sys, Addr addr)
+{
+ PCEvent *event = new BreakPCEvent(&sys->pcEventQueue, "debug break", true);
+ event->schedule(addr);
+}
+
+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/sim/pc_event.hh b/sim/pc_event.hh
new file mode 100644
index 000000000..24442f5f4
--- /dev/null
+++ b/sim/pc_event.hh
@@ -0,0 +1,215 @@
+/*
+ * 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.
+ */
+
+#ifndef __PC_EVENT_HH__
+#define __PC_EVENT_HH__
+
+#include <vector>
+
+#include "mem_req.hh"
+
+class ExecContext;
+class PCEventQueue;
+
+class PCEvent
+{
+ protected:
+ static const Addr badpc = MemReq::inval_addr;
+
+ protected:
+ std::string description;
+ PCEventQueue *queue;
+ Addr evpc;
+
+ public:
+ PCEvent() : queue(0), evpc(badpc) { }
+
+ PCEvent(const std::string &desc)
+ : description(desc), queue(0), evpc(badpc) { }
+
+ PCEvent(PCEventQueue *q, Addr pc = badpc) : queue(q), evpc(pc) { }
+
+ PCEvent(PCEventQueue *q, const std::string &desc, Addr pc = badpc)
+ : description(desc), queue(q), evpc(pc) { }
+
+ virtual ~PCEvent() { if (queue) remove(); }
+
+ std::string descr() const { return description; }
+ Addr pc() const { return evpc; }
+
+ bool remove();
+ bool schedule();
+ bool schedule(Addr pc);
+ bool schedule(PCEventQueue *q, Addr pc);
+ 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;
+
+ public:
+ PCEventQueue();
+ ~PCEventQueue();
+
+ bool remove(PCEvent *event);
+ bool schedule(PCEvent *event);
+ bool service(ExecContext *xc);
+
+ range_t equal_range(Addr pc);
+ range_t equal_range(PCEvent *event) { return equal_range(event->pc()); }
+
+ void dump() const;
+};
+
+inline bool
+PCEvent::remove()
+{
+ if (!queue)
+ panic("cannot remove an uninitialized event;");
+
+ return queue->remove(this);
+}
+
+inline bool
+PCEvent::schedule()
+{
+ if (!queue || evpc == badpc)
+ panic("cannot schedule an uninitialized event;");
+
+ return queue->schedule(this);
+}
+
+inline bool
+PCEvent::schedule(Addr pc)
+{
+ if (evpc != badpc)
+ panic("cannot switch PC");
+ evpc = pc;
+
+ return schedule();
+}
+
+inline bool
+PCEvent::schedule(PCEventQueue *q, Addr pc)
+{
+ if (queue)
+ panic("cannot switch event queues");
+
+ if (evpc != badpc)
+ panic("cannot switch addresses");
+
+ queue = q;
+ evpc = pc;
+
+ return schedule();
+}
+
+
+#ifdef FULL_SYSTEM
+class SkipFuncEvent : public PCEvent
+{
+ public:
+ SkipFuncEvent(PCEventQueue *q, const std::string &desc)
+ : PCEvent(q, desc) {}
+ virtual void process(ExecContext *xc);
+};
+
+class BadAddrEvent : public SkipFuncEvent
+{
+ public:
+ BadAddrEvent(PCEventQueue *q, const std::string &desc)
+ : SkipFuncEvent(q, desc) {}
+ virtual void process(ExecContext *xc);
+};
+
+class PrintfEvent : public PCEvent
+{
+ public:
+ PrintfEvent(PCEventQueue *q, const std::string &desc)
+ : PCEvent(q, desc) {}
+ virtual void process(ExecContext *xc);
+};
+
+class DebugPrintfEvent : public PCEvent
+{
+ private:
+ bool raw;
+
+ public:
+ DebugPrintfEvent(PCEventQueue *q, const std::string &desc, bool r = false)
+ : PCEvent(q, desc), raw(r) {}
+ virtual void process(ExecContext *xc);
+};
+
+class DumpMbufEvent : public PCEvent
+{
+ public:
+ DumpMbufEvent(PCEventQueue *q, const std::string &desc)
+ : PCEvent(q, desc) {}
+ virtual void process(ExecContext *xc);
+};
+#endif
+
+class BreakPCEvent : public PCEvent
+{
+ protected:
+ bool remove;
+
+ public:
+ BreakPCEvent(PCEventQueue *q, const std::string &desc, bool del = false);
+ virtual void process(ExecContext *xc);
+};
+
+
+#endif // __PC_EVENT_HH__
diff --git a/sim/predictor.hh b/sim/predictor.hh
new file mode 100644
index 000000000..7c446f26c
--- /dev/null
+++ b/sim/predictor.hh
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+//
+// Abstract base class for a generic predictor
+//
+//
+
+#ifndef __PREDICTOR_HH__
+#define __PREDICTOR_HH__
+
+struct stat_sdb_t;
+
+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/sim/prog.cc b/sim/prog.cc
new file mode 100644
index 000000000..8615cab68
--- /dev/null
+++ b/sim/prog.cc
@@ -0,0 +1,281 @@
+/*
+ * 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.
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#include <string>
+
+#include "main_memory.hh"
+#include "prog.hh"
+
+#include "eio.hh"
+#include "thread.hh"
+#include "fake_syscall.hh"
+#include "loader.hh"
+#include "exec_context.hh"
+#include "smt.hh"
+
+#include "statistics.hh"
+#include "sim_stats.hh"
+
+using namespace std;
+
+//
+// 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
+//
+#ifdef FULL_SYSTEM
+#error "prog.cc not compatible with FULL_SYSTEM"
+#endif
+
+// max allowable number of processes: should be no real cost to
+// cranking this up if necessary
+const int MAX_PROCESSES = 8;
+
+// current number of allocated processes
+int num_processes = 0;
+
+Process::Process(const string &name,
+ int stdin_fd, // initial I/O descriptors
+ int stdout_fd,
+ int stderr_fd)
+ : SimObject(name)
+{
+ // allocate memory space
+ memory = new MainMemory(name + ".MainMem");
+
+ // allocate initial register file
+ init_regs = new RegFile;
+
+ // 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;
+ }
+
+ numCpus = 0;
+
+ num_syscalls = 0;
+
+ // other parameters will be initialized when the program is loaded
+}
+
+void
+Process::regStats()
+{
+ using namespace Statistics;
+
+ 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;
+}
+
+
+void
+Process::registerExecContext(ExecContext *ec)
+{
+ if (execContexts.empty()) {
+ // first exec context for this process... initialize & enable
+
+ // copy process's initial regs struct
+ ec->regs = *init_regs;
+
+ // mark this context as active
+ ec->setStatus(ExecContext::Active);
+ }
+ else {
+ ec->setStatus(ExecContext::Unallocated);
+ }
+
+ // add to list
+ execContexts.push_back(ec);
+
+ // increment available CPU count
+ ++numCpus;
+}
+
+
+// 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::open_fd(int sim_fd)
+{
+ int free_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 (free_fd = 0; fd_map[free_fd] >= 0; ++free_fd) {
+ if (free_fd == MAX_FD)
+ panic("Process::open_fd: out of file descriptors!");
+ }
+
+ fd_map[free_fd] = sim_fd;
+
+ return free_fd;
+}
+
+
+// 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 object", Process)
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// LiveProcess member definitions
+//
+////////////////////////////////////////////////////////////////////////
+
+LiveProcess::LiveProcess(const string &name,
+ int stdin_fd, int stdout_fd, int stderr_fd,
+ vector<string> &argv, vector<string> &envp)
+ : Process(name, stdin_fd, stdout_fd, stderr_fd)
+{
+ smt_load_prog(argv, envp, init_regs, this);
+}
+
+
+void
+LiveProcess::syscall(ExecContext *xc)
+{
+ num_syscalls++;
+
+ fake_syscall(this, xc);
+}
+
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(LiveProcess)
+
+ VectorParam<string> cmd;
+ Param<string> input;
+ Param<string> output;
+ VectorParam<string> env;
+
+END_DECLARE_SIM_OBJECT_PARAMS(LiveProcess)
+
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(LiveProcess)
+
+ INIT_PARAM(cmd, "command line (executable plus arguments)"),
+ 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")
+
+END_INIT_SIM_OBJECT_PARAMS(LiveProcess)
+
+
+CREATE_SIM_OBJECT(LiveProcess)
+{
+ // initialize file descriptors to default: same as simulator
+ int stdin_fd = input.isValid() ? Process::openInputFile(input) : 0;
+ int stdout_fd = output.isValid() ? Process::openOutputFile(output) : 1;
+ int stderr_fd = output.isValid() ? stdout_fd : 2;
+
+ // dummy for default env
+ vector<string> null_vec;
+
+ // We do this with "temp" because of the bogus compiler warning
+ // you get with g++ 2.95 -O if you just "return new LiveProcess(..."
+ LiveProcess *temp = new LiveProcess(getInstanceName(),
+ stdin_fd, stdout_fd, stderr_fd,
+ cmd,
+ env.isValid() ? env : null_vec);
+
+ return temp;
+}
+
+
+REGISTER_SIM_OBJECT("LiveProcess", LiveProcess)
diff --git a/sim/prog.hh b/sim/prog.hh
new file mode 100644
index 000000000..a38afee14
--- /dev/null
+++ b/sim/prog.hh
@@ -0,0 +1,180 @@
+/*
+ * 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.
+ */
+
+#ifndef __PROG_HH__
+#define __PROG_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.
+//
+#ifndef FULL_SYSTEM
+
+#include <list>
+
+#include "stats.hh"
+#include "sim_object.hh"
+
+#include "statistics.hh"
+#include "sim_stats.hh"
+
+class ExecContext;
+class FunctionalMemory;
+class Process : public SimObject
+{
+ public:
+
+ // 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::list<ExecContext *> execContexts;
+ // number of CPUs assigned to this process: should match number of
+ // contexts in execContexts list
+ unsigned numCpus;
+
+ // 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;
+
+ RegFile *init_regs; // initial register contents
+
+ Addr text_base; // text (code) segment base
+ unsigned text_size; // text (code) size in bytes
+
+ Addr data_base; // initialized data segment base
+ unsigned data_size; // initialized data + bss size in bytes
+
+ Addr brk_point; // top of the data segment
+
+ Addr environ_base; // environment base address
+ 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;
+
+ std::string prog_fname; // file name
+ Addr prog_entry; // entry point (initial PC)
+
+ Statistics::Scalar<> num_syscalls; // number of syscalls executed
+
+
+ protected:
+ // constructor
+ Process(const std::string &name,
+ int stdin_fd, // initial I/O descriptors
+ int stdout_fd,
+ int stderr_fd);
+
+
+ protected:
+ FunctionalMemory *memory;
+
+ private:
+ // file descriptor remapping support
+ static const int MAX_FD = 100; // 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
+ void registerExecContext(ExecContext *);
+
+ // 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 open_fd(int sim_fd);
+
+ // look up simulator fd for given target fd
+ int sim_fd(int tgt_fd);
+
+ // is this a valid instruction fetch address?
+ bool validInstAddr(Addr addr)
+ {
+ return (text_base <= addr &&
+ addr < text_base + text_size &&
+ !(addr & (sizeof(MachInst)-1)));
+ }
+
+ // is this a valid address? (used to filter data fetches)
+ // note that we just assume stack size <= 16MB
+ // this may be alpha-specific
+ bool validDataAddr(Addr addr)
+ {
+ return ((data_base <= addr && addr < brk_point) ||
+ ((stack_base - 16*1024*1024) <= addr && addr < stack_base) ||
+ (text_base <= addr && addr < (text_base + text_size)));
+ }
+
+ virtual void syscall(ExecContext *xc) = 0;
+
+ virtual FunctionalMemory *getMemory() { return memory; }
+};
+
+//
+// "Live" process with system calls redirected to host system
+//
+class MainMemory;
+class LiveProcess : public Process
+{
+ public:
+ LiveProcess(const std::string &name,
+ int stdin_fd, int stdout_fd, int stderr_fd,
+ std::vector<std::string> &argv,
+ std::vector<std::string> &envp);
+
+ virtual void syscall(ExecContext *xc);
+};
+
+#endif // !FULL_SYSTEM
+
+#endif // __PROG_HH__
diff --git a/sim/sat_counter.cc b/sim/sat_counter.cc
new file mode 100644
index 000000000..bd1b6de0b
--- /dev/null
+++ b/sim/sat_counter.cc
@@ -0,0 +1,270 @@
+/*
+ * 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.
+ */
+
+#include <sstream>
+
+#include "stats.hh"
+#include "sat_counter.hh"
+
+#include "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 Statistics;
+ 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 Statistics;
+ 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/sim/sat_counter.hh b/sim/sat_counter.hh
new file mode 100644
index 000000000..18eab3574
--- /dev/null
+++ b/sim/sat_counter.hh
@@ -0,0 +1,192 @@
+/*
+ * 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.
+ */
+
+#ifndef __SAT_COUNTER_HH__
+#define __SAT_COUNTER_HH__
+
+#include <string>
+
+#include "predictor.hh"
+
+#include "statistics.hh"
+#include "sim_stats.hh"
+
+struct stat_sdb_t;
+
+//
+//
+// 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
+ Statistics::Scalar<> predicted_one; // Total predictions of one, preds_one
+ Statistics::Scalar<> predicted_zero; // Total predictions of zero, preds_zero
+ Statistics::Scalar<> correct_pred_one; // Total correct predictions of one, correct_one
+ Statistics::Scalar<> correct_pred_zero; // Total correct predictions of zero, correct_zero
+
+ Statistics::Scalar<> record_zero; //updates_zero
+ Statistics::Scalar<> record_one; //updates_one
+
+ Statistics::Formula preds_total;
+ Statistics::Formula pred_frac_zero;
+ Statistics::Formula pred_frac_one;
+ Statistics::Formula correct_total;
+ Statistics::Formula updates_total;
+ Statistics::Formula pred_rate;
+ Statistics::Formula frac_correct_zero;
+ Statistics::Formula frac_correct_one;
+ Statistics::Formula coverage_zero;
+ Statistics::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/sim/serialize.cc b/sim/serialize.cc
new file mode 100644
index 000000000..a2e3d7250
--- /dev/null
+++ b/sim/serialize.cc
@@ -0,0 +1,353 @@
+/*
+ * 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.
+ */
+
+#include <sys/time.h>
+
+#include <fstream>
+#include <list>
+#include <string>
+#include <vector>
+
+#include "misc.hh"
+
+#include "eventq.hh"
+#include "param.hh"
+#include "serialize.hh"
+#include "inifile.hh"
+#include "sim_events.hh"
+#include "sim_object.hh"
+#include "trace.hh"
+
+using namespace std;
+
+Serializer *Serializeable::serializer = NULL;
+
+Serializeable::Serializeable(const string &n)
+ : proxy(this), objName(n), serialized(false)
+{ }
+
+Serializeable::~Serializeable()
+{ }
+
+void
+Serializeable::mark()
+{
+ if (!serialized)
+ serializer->add_object(this);
+
+ serialized = true;
+}
+
+ostream &
+Serializeable::out() const
+{
+ return serializer->out();
+}
+
+void
+Serializeable::nameOut()
+{
+ out() << "\n[" << name() << "]\n";
+}
+
+void
+Serializeable::nameOut(const string &_name)
+{
+ out() << "\n[" << _name << "]\n";
+}
+
+template<> void
+Serializeable::paramOut(const string &name, const uint64_t& param)
+{
+ out() << name << "=0x" << hex << param << dec << "\n";
+}
+
+void
+Serializeable::childOut(const string &name, Serializeable *child)
+{
+ child->mark();
+ if (child->name() == "")
+ panic("child is unnamed");
+
+ out() << name << "=" << child->name() << "\n";
+}
+
+void
+Serializeable::setName(const string &name)
+{
+ if (objName != "")
+ panic("Cannot change object name");
+
+ objName = name;
+}
+
+Serializer::Serializer()
+{ }
+
+Serializer::~Serializer()
+{ }
+
+ostream &
+Serializer::out() const
+{
+ if (!output)
+ panic("must set output before serializing");
+
+ return *output;
+}
+
+void
+Serializer::add_object(Serializeable *obj)
+{
+ objects.push_back(obj);
+}
+
+void
+Serializer::add_objects()
+{
+ mainEventQueue.mark();
+
+ SimObject::SimObjectList::iterator i = SimObject::simObjectList.begin();
+ SimObject::SimObjectList::iterator end = SimObject::simObjectList.end();
+
+ while (i != end) {
+ (*i)->mark();
+ ++i;
+ }
+}
+
+void
+Serializer::serialize(const string &f)
+{
+ if (Serializeable::serializer != NULL)
+ panic("in process of serializing!");
+
+ Serializeable::serializer = this;
+
+ file = f;
+ string cpt_file = file + ".cpt";
+ output = new ofstream(cpt_file.c_str());
+ time_t t = time(NULL);
+ *output << "// checkpoint generated: " << ctime(&t);
+
+ serlist_t list;
+
+ add_objects();
+ while (!objects.empty()) {
+ Serializeable *serial = objects.front();
+ DPRINTF(Serialize, "Name Children of %s\n", serial->name());
+ serial->nameChildren();
+ objects.pop_front();
+ list.push_back(serial);
+ }
+
+ while (!list.empty()) {
+ list.front()->serialized = false;
+ list.pop_front();
+ }
+
+ add_objects();
+ while (!objects.empty()) {
+ Serializeable *serial = objects.front();
+ DPRINTF(Serialize, "Name Children of %s\n", serial->name());
+ serial->serialize();
+ objects.pop_front();
+ list.push_back(serial);
+ }
+
+ while (!list.empty()) {
+ list.front()->serialized = false;
+ list.pop_front();
+ }
+
+ Serializeable::serializer = NULL;
+
+ delete output;
+ output = NULL;
+ file = "";
+}
+
+class SerializeEvent : public Event
+{
+ protected:
+ string file;
+
+ public:
+ SerializeEvent(EventQueue *q, Tick when, const string &file);
+ ~SerializeEvent();
+
+ virtual void process();
+ virtual void serialize();
+};
+
+SerializeEvent::SerializeEvent(EventQueue *q, Tick when, const string &f)
+ : Event(q), file(f)
+{
+ setFlags(AutoDelete);
+ schedule(when);
+}
+
+SerializeEvent::~SerializeEvent()
+{
+}
+
+void
+SerializeEvent::process()
+{
+ Serializer serial;
+ serial.serialize(file);
+ new SimExitEvent("Serialization caused exit");
+}
+
+void
+SerializeEvent::serialize()
+{
+ panic("Cannot serialize the SerializeEvent");
+}
+
+class SerializeParamContext : public ParamContext
+{
+ private:
+ SerializeEvent *event;
+
+ public:
+ SerializeParamContext(const string &section);
+ ~SerializeParamContext();
+ void checkParams();
+};
+
+SerializeParamContext serialParams("serialize");
+
+Param<Counter> serialize_cycle(&serialParams,
+ "cycle",
+ "cycle to serialize",
+ 0);
+
+Param<string> serialize_file(&serialParams,
+ "file",
+ "file to write to", "");
+
+SerializeParamContext::SerializeParamContext(const string &section)
+ : ParamContext(section), event(NULL)
+{ }
+
+SerializeParamContext::~SerializeParamContext()
+{
+}
+
+void
+SerializeParamContext::checkParams()
+{
+ if (!((string)serialize_file).empty() && serialize_cycle > 0)
+ event = new SerializeEvent(&mainEventQueue, serialize_cycle,
+ serialize_file);
+}
+
+void
+debug_serialize(const char *file)
+{
+ Serializer serial;
+ serial.serialize(file);
+ new SimExitEvent("Serialization caused exit");
+}
+
+
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// SerializeableClass member definitions
+//
+////////////////////////////////////////////////////////////////////////
+
+// Map of class names to SerializeableBuilder creation functions.
+// Need to make this a pointer so we can force initialization on the
+// first reference; otherwise, some SerializeableClass constructors
+// may be invoked before the classMap constructor.
+map<string,SerializeableClass::CreateFunc> *SerializeableClass::classMap = 0;
+
+// SerializeableClass constructor: add mapping to classMap
+SerializeableClass::SerializeableClass(const string &className,
+ CreateFunc createFunc)
+{
+ if (classMap == NULL)
+ classMap = new map<string,SerializeableClass::CreateFunc>();
+
+ if ((*classMap)[className])
+ {
+ cerr << "Error: simulation object class " << className << " redefined"
+ << endl;
+ fatal("");
+ }
+
+ // add className --> createFunc to class map
+ (*classMap)[className] = createFunc;
+}
+
+
+//
+//
+Serializeable *
+SerializeableClass::createObject(IniFile &configDB,
+ const string &configClassName)
+{
+ // find simulation object class name from configuration class
+ // (specified by 'type=' parameter)
+ string simObjClassName;
+
+ if (!configDB.findDefault(configClassName, "type", simObjClassName)) {
+ cerr << "Configuration class '" << configClassName << "' not found."
+ << endl;
+ abort();
+ }
+
+ // look up className to get appropriate createFunc
+ if (classMap->find(simObjClassName) == classMap->end()) {
+ cerr << "Simulator object class '" << simObjClassName << "' not found."
+ << endl;
+ abort();
+ }
+
+ CreateFunc createFunc = (*classMap)[simObjClassName];
+
+ // builder instance
+ SerializeableBuilder *objectBuilder = (*createFunc)();
+
+ assert(objectBuilder != NULL);
+
+ // now create the actual simulation object
+ Serializeable *object = objectBuilder->create();
+
+ assert(object != NULL);
+
+ // done with the SerializeableBuilder now
+ delete objectBuilder;
+
+ return object;
+}
+
diff --git a/sim/serialize.hh b/sim/serialize.hh
new file mode 100644
index 000000000..c5fb86140
--- /dev/null
+++ b/sim/serialize.hh
@@ -0,0 +1,241 @@
+/*
+ * 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
+ * Serialization Interface Declarations
+ */
+
+#ifndef __SERIALIZE_HH__
+#define __SERIALIZE_HH__
+
+
+#include <list>
+#include <iostream>
+
+#include "host.hh"
+#include "configfile.hh"
+
+class IniFile;
+
+/*
+ * Basic support for object serialization.
+ */
+class Serializeable
+{
+ public:
+ // To allow other classes to do some of the serialization work.
+ class Proxy {
+ private:
+ Serializeable *obj;
+
+ // Make it so only Serializables can construct one of these.
+ Proxy(Serializeable *o) : obj(o) {};
+
+ friend class Serializeable;
+
+ public:
+ template <class T>
+ void paramOut(const std::string &name, const T& param) const {
+ obj->paramOut(name, param);
+ };
+ };
+
+ friend class Serializer;
+ friend class Proxy;
+
+ private:
+ Proxy proxy;
+
+ protected:
+ const Proxy &getProxy() { return(proxy); };
+
+ // object name: should be unique
+ std::string objName;
+
+ bool serialized;
+ static Serializer *serializer;
+
+ void mark();
+ void nameOut();
+ void nameOut(const std::string &_name);
+ void childOut(const std::string &name, Serializeable *child);
+ template <class T>
+ void paramOut(const std::string &name, const T& param);
+
+ std::ostream &out() const;
+
+ public:
+ Serializeable(const std::string &n);
+ virtual ~Serializeable();
+
+ void setName(const std::string &name);
+
+ // return name
+ const std::string &name() const { return objName; }
+
+ virtual void nameChildren() {}
+ virtual void serialize() {}
+ virtual void unserialize(IniFile &db, const std::string &category,
+ ConfigNode *node = NULL)
+ {
+ std::cout << name() << " is being unserialized" << std::endl;
+ }
+};
+
+class Serializer
+{
+ friend class Serializeable;
+
+ protected:
+ typedef std::list<Serializeable *> serlist_t;
+ serlist_t objects;
+ std::string file;
+ std::ostream *output;
+ std::ostream &out() const;
+
+ public:
+ Serializer();
+ virtual ~Serializer();
+
+ private:
+ void add_object(Serializeable *obj);
+ void add_objects();
+
+ public:
+ void serialize(const std::string &file);
+ const std::string &filename() const { return file; }
+};
+
+template <class T>
+inline void
+Serializeable::paramOut(const std::string &name, const T& param)
+{
+ out() << name << "=" << param << "\n";
+}
+
+template <> void
+Serializeable::paramOut(const std::string &name, const uint64_t& param);
+
+
+//
+// A SerializeableBuilder serves as an evaluation context for a set of
+// parameters that describe a specific instance of a Serializeable. 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
+// Serializeable references. SerializeableBuilder is an abstract superclass;
+// derived classes specialize the class for particular subclasses of
+// Serializeable (e.g., BaseCache).
+//
+// For typical usage, see the definition of
+// SerializeableClass::createObject().
+//
+class SerializeableBuilder
+{
+ public:
+
+ SerializeableBuilder() {}
+
+ virtual ~SerializeableBuilder() {}
+
+ // Create the actual Serializeable 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 Serializeable.
+ virtual Serializeable *create() = 0;
+};
+
+//
+// An instance of SerializeableClass corresponds to a class derived from
+// Serializeable. The SerializeableClass 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 SerializeableClass
+{
+ 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 SerializeableBuilder is returned.
+ typedef SerializeableBuilder *(*CreateFunc)();
+
+ static std::map<std::string,CreateFunc> *classMap;
+
+ // Constructor. For example:
+ //
+ // SerializeableClass baseCacheSerializeableClass("BaseCacheSerializeable",
+ // newBaseCacheSerializeableBuilder);
+ //
+ SerializeableClass(const std::string &className, CreateFunc createFunc);
+
+ // create Serializeable given name of class and pointer to
+ // configuration hierarchy node
+ static Serializeable *createObject(IniFile &configDB,
+ const std::string &configClassName);
+
+};
+
+//
+// Macros to encapsulate the magic of declaring & defining
+// SerializeableBuilder and SerializeableClass objects
+//
+
+#define CREATE_SERIALIZEABLE(OBJ_CLASS) \
+OBJ_CLASS *OBJ_CLASS##Builder::create()
+
+#define REGISTER_SERIALIZEABLE(CLASS_NAME, OBJ_CLASS) \
+class OBJ_CLASS##Builder : public SerializeableBuilder \
+{ \
+ public: \
+ \
+ OBJ_CLASS##Builder() {} \
+ virtual ~OBJ_CLASS##Builder() {} \
+ \
+ OBJ_CLASS *create(); \
+}; \
+ \
+ \
+SerializeableBuilder * \
+new##OBJ_CLASS##Builder() \
+{ \
+ return new OBJ_CLASS##Builder(); \
+} \
+ \
+SerializeableClass the##OBJ_CLASS##Class(CLASS_NAME, \
+ new##OBJ_CLASS##Builder);
+
+
+
+#endif // __SERIALIZE_HH__
diff --git a/sim/sim_events.cc b/sim/sim_events.cc
new file mode 100644
index 000000000..ffabc3006
--- /dev/null
+++ b/sim/sim_events.cc
@@ -0,0 +1,271 @@
+/*
+ * 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.
+ */
+
+#include <string>
+
+#include "cpu.hh"
+#include "eventq.hh"
+#include "sim_events.hh"
+#include "sim_exit.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),
+ cause(_cause),
+ downCounter(_downCounter)
+{
+ // catch stupid mistakes
+ assert(downCounter > 0);
+
+ schedule(_when, 1000);
+}
+
+
+//
+// handle termination event
+//
+void
+CountedExitEvent::process()
+{
+ if (--downCounter == 0) {
+ new SimExitEvent(cause, 1);
+ }
+}
+
+
+const char *
+CountedExitEvent::description()
+{
+ return "counted exit";
+}
+
+
+void
+DumpStatsEvent::process()
+{
+ dumpStats();
+}
+
+const char *
+DumpStatsEvent::description()
+{
+ return "stats dump";
+}
+
+
+#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 = proc_info("/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";
+}
+
+
+class DumpStatsContext : public ParamContext
+{
+ public:
+ DumpStatsContext(const string &_iniSection)
+ : ParamContext(_iniSection) {}
+ void checkParams();
+};
+
+DumpStatsContext dumpStatsParams("stats");
+
+VectorParam<Tick> dump_cycle(&dumpStatsParams, "dump_cycles",
+ "cycles on which to dump stats");
+
+void
+DumpStatsContext::checkParams()
+{
+ if (dump_cycle.isValid()) {
+ vector<Tick> &cycles = dump_cycle;
+
+ vector<Tick>::iterator i = cycles.begin();
+ vector<Tick>::iterator end = cycles.end();
+
+ for (; i < end; ++i)
+ new DumpStatsEvent(*i);
+ }
+}
+
+///////////////////////////////////////////////////
+//
+// Simulation termination parameters
+//
+///////////////////////////////////////////////////
+
+class TermParamContext : public ParamContext
+{
+ public:
+ TermParamContext(const string &_iniSection)
+ : ParamContext(_iniSection) {}
+ void checkParams();
+};
+
+TermParamContext simTerminationParams("max");
+
+Param<Tick> max_cycle(&simTerminationParams, "cycle",
+ "maximum number of cycles to execute");
+
+void
+TermParamContext::checkParams()
+{
+ // if a max cycle count was specified, put a termination event on
+ // the event queue at that point
+ if (max_cycle.isValid())
+ new SimExitEvent(max_cycle, "reached maximum cycle count");
+}
+
+//
+// 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 interval);
+
+ void process(); // process event
+ virtual const char *description();
+};
+
+//
+// constructor: schedule at specified time
+//
+ProgressEvent::ProgressEvent(EventQueue *q, Tick _interval)
+ : Event(q), interval(_interval)
+{
+ schedule(interval);
+}
+
+//
+// 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";
+}
+
+/////////
+//
+// Periodic progress message support: print out a message every n
+// cycles so we know we're making forward progress.
+//
+/////////
+
+// Parameter space for execution address tracing options. Derive
+// from ParamContext so we can override checkParams() function.
+class ProgressParamContext : public ParamContext
+{
+ public:
+ ProgressParamContext(const string &_iniSection)
+ : ParamContext(_iniSection) {}
+ void checkParams();
+};
+
+ProgressParamContext progessMessageParams("progress");
+
+Param<Tick> progress_interval(&progessMessageParams, "cycle",
+ "cycle interval for progress messages");
+
+/* check execute options */
+void
+ProgressParamContext::checkParams()
+{
+ if (progress_interval.isValid())
+ new ProgressEvent(&mainEventQueue, progress_interval);
+}
diff --git a/sim/sim_events.hh b/sim/sim_events.hh
new file mode 100644
index 000000000..e9a5f3251
--- /dev/null
+++ b/sim/sim_events.hh
@@ -0,0 +1,131 @@
+/*
+ * 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.
+ */
+
+#ifndef __SIM_EVENTS_HH__
+#define __SIM_EVENTS_HH__
+
+#include "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), cause(_cause),
+ code(c)
+ { schedule(curTick, 1000); }
+
+ SimExitEvent(Tick _when, const std::string &_cause, int c = 0)
+ : Event(&mainEventQueue), cause(_cause),
+ code(c)
+ { schedule(_when, 1000); }
+
+ SimExitEvent(EventQueue *q, const std::string &_cause, int c = 0)
+ : Event(q), cause(_cause), code(c)
+ { schedule(curTick, 1000); }
+
+ SimExitEvent(EventQueue *q, Tick _when, const std::string &_cause,
+ int c = 0)
+ : Event(q), cause(_cause), code(c)
+ { schedule(_when, 1000); }
+
+ 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 cause a statistics dump
+//
+class DumpStatsEvent : public Event
+{
+ public:
+ DumpStatsEvent()
+ : Event(&mainEventQueue)
+ { setFlags(AutoDelete); schedule(curTick, 999); }
+
+ DumpStatsEvent(EventQueue *q)
+ : Event(q)
+ { setFlags(AutoDelete); schedule(curTick, 999); }
+
+ DumpStatsEvent(Tick when)
+ : Event(&mainEventQueue)
+ { setFlags(AutoDelete); schedule(when, 999); }
+
+ DumpStatsEvent(EventQueue *q, Tick when)
+ : Event(q)
+ { setFlags(AutoDelete); schedule(when, 999); }
+
+ void process();
+
+ virtual const char *description();
+};
+
+class CheckSwapEvent : public Event
+{
+ private:
+ int interval;
+
+ public:
+ CheckSwapEvent(EventQueue *q, int ival)
+ : Event(q), interval(ival)
+ { schedule(interval); }
+
+ void process(); // process event
+
+ virtual const char *description();
+};
+
+#endif // __SIM_EVENTS_HH__
diff --git a/sim/sim_exit.hh b/sim/sim_exit.hh
new file mode 100644
index 000000000..847d9eb10
--- /dev/null
+++ b/sim/sim_exit.hh
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+#ifndef __SIM_EXIT_HH__
+#define __SIM_EXIT_HH__
+
+#include <string>
+
+class Callback;
+
+void registerExitCallback(Callback *);
+
+void exitNow(const std::string &cause, int exit_code);
+void exitNow(const char *cause, int exit_code);
+
+#endif // __SIM_EXIT_HH__
diff --git a/sim/sim_object.cc b/sim/sim_object.cc
new file mode 100644
index 000000000..e5506ee8f
--- /dev/null
+++ b/sim/sim_object.cc
@@ -0,0 +1,280 @@
+/*
+ * 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.
+ */
+
+#include <assert.h>
+
+#include "sim_object.hh"
+#include "inifile.hh"
+#include "configfile.hh"
+#include "host.hh"
+#include "misc.hh"
+#include "trace.hh"
+#include "sim_stats.hh"
+#include "stats.hh"
+
+using namespace std;
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// SimObject member definitions
+//
+////////////////////////////////////////////////////////////////////////
+
+//
+// static list of all SimObjects, used for initialization etc.
+//
+SimObject::SimObjectList SimObject::simObjectList;
+
+//
+// SimObject constructor: used to maintain static simObjectList
+//
+SimObject::SimObject(const string &_name)
+ : Serializeable(_name)
+{
+ simObjectList.push_back(this);
+}
+
+//
+// no default statistics, so nothing to do in base implementation
+//
+void
+SimObject::reg_stats(struct stat_sdb_t *sdb)
+{
+}
+
+void
+SimObject::regStats()
+{
+}
+
+void
+SimObject::regFormulas()
+{
+}
+
+//
+// no default extra output
+//
+void
+SimObject::printExtraOutput(ostream &os)
+{
+}
+
+//
+// static function: call reg_stats() on all SimObjects.
+//
+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)->reg_stats(sim_sdb);
+ (*i)->regStats();
+ }
+
+ for (i = simObjectList.begin(); i != end; ++i) {
+#ifdef STAT_DEBUG
+ cprintf("registering formulas for %s\n", (*i)->name());
+#endif
+ (*i)->regFormulas();
+ }
+}
+
+//
+// static function: call printExtraOutput() on all SimObjects.
+//
+void
+SimObject::printAllExtraOutput(ostream &os)
+{
+ SimObjectList::iterator i;
+
+ for (i = simObjectList.begin(); i != simObjectList.end(); ++i) {
+ (*i)->printExtraOutput(os);
+ }
+}
+
+///////////////////////////////////////////
+//
+// 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.findDefault(instanceName, (*i)->name, string_value)) {
+ (*i)->parse(string_value);
+ }
+ else if (iniFile.findDefault(iniSection, (*i)->name, string_value)) {
+ (*i)->parse(string_value);
+ }
+ }
+}
+
+
+void
+SimObjectBuilder::printErrorProlog(ostream &os)
+{
+ os << "Error creating object '" << getInstanceName()
+ << "' of type '" << simObjClassName
+ << "', section '" << iniSection << "':" << endl;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// 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])
+ {
+ cerr << "Error: simulation object class " << className << " redefined"
+ << endl;
+ fatal("");
+ }
+
+ // add className --> createFunc to class map
+ (*classMap)[className] = createFunc;
+}
+
+
+//
+//
+SimObject *
+SimObjectClass::createObject(IniFile &configDB,
+ const string &configClassName,
+ const string &objName,
+ ConfigNode *configNode)
+{
+ // find simulation object class name from configuration class
+ // (specified by 'type=' parameter)
+ string simObjClassName;
+
+ if (!configDB.findDefault(configClassName, "type", simObjClassName)) {
+ cerr << "Configuration class '" << configClassName << "' not found."
+ << endl;
+ abort();
+ }
+
+ // look up className to get appropriate createFunc
+ if (classMap->find(simObjClassName) == classMap->end()) {
+ cerr << "Simulator object class '" << simObjClassName << "' not found."
+ << endl;
+ abort();
+ }
+
+ CreateFunc createFunc = (*classMap)[simObjClassName];
+
+ // call createFunc with config hierarchy node to get object
+ // builder instance (context with parameters for object creation)
+ SimObjectBuilder *objectBuilder = (*createFunc)(configClassName,
+ objName, configNode,
+ simObjClassName);
+
+ 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)
+ *statStream << "[" << object->name() << "]" << endl;
+ *statStream << "type=" << simObjClassName << endl;
+ objectBuilder->showParams(*statStream);
+ *statStream << endl;
+
+ // 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/sim/sim_object.hh b/sim/sim_object.hh
new file mode 100644
index 000000000..051c7b304
--- /dev/null
+++ b/sim/sim_object.hh
@@ -0,0 +1,261 @@
+/*
+ * 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
+ * User Console Definitions
+ */
+
+#ifndef __SIM_OBJECT_HH__
+#define __SIM_OBJECT_HH__
+
+#include <map>
+#include <list>
+#include <vector>
+#include <iostream>
+
+#include "param.hh"
+#include "serialize.hh"
+
+/*
+ * 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 Serializeable
+{
+ private:
+ friend class Serializer;
+
+ typedef std::vector<SimObject *> SimObjectList;
+
+ // list of all instantiated simulation objects
+ static SimObjectList simObjectList;
+
+ public:
+ SimObject(const std::string &_name);
+
+ virtual ~SimObject() {}
+
+ // register statistics for this object
+ virtual void reg_stats(struct stat_sdb_t *sdb);
+ virtual void regStats();
+ virtual void regFormulas();
+
+ // print extra results for this object not covered by registered
+ // statistics (called at end of simulation)
+ virtual void printExtraOutput(std::ostream&);
+
+ // static: call reg_stats on all SimObjects
+ static void regAllStats();
+
+ // static: call printExtraOutput on all SimObjects
+ static void printAllExtraOutput(std::ostream&);
+};
+
+
+//
+// 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:
+ // name of the instance we are creating
+ std::string instanceName;
+
+ // The corresponding node in the configuration hierarchy.
+ // (optional: may be null if the created object is not in the
+ // hierarchy)
+ ConfigNode *configNode;
+
+ // The external SimObject class name (for error messages)
+ std::string simObjClassName;
+
+ public:
+ SimObjectBuilder(const std::string &_configClass,
+ const std::string &_instanceName,
+ ConfigNode *_configNode,
+ const std::string &_simObjClassName)
+ : ParamContext(_configClass, true),
+ instanceName(_instanceName),
+ configNode(_configNode),
+ simObjClassName(_simObjClassName)
+ {
+ }
+
+ 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 instanceName; }
+
+ // 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)(const std::string &configClassName,
+ const std::string &objName,
+ ConfigNode *configNode,
+ const std::string &simObjClassName);
+
+ 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,
+ const std::string &configClassName,
+ const std::string &objName,
+ 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(const std::string &configClass, \
+ const std::string &instanceName, \
+ ConfigNode *configNode, \
+ const std::string &simObjClassName); \
+ virtual ~OBJ_CLASS##Builder() {} \
+ \
+ OBJ_CLASS *create(); \
+};
+
+#define BEGIN_INIT_SIM_OBJECT_PARAMS(OBJ_CLASS) \
+OBJ_CLASS##Builder::OBJ_CLASS##Builder(const std::string &configClass, \
+ const std::string &instanceName, \
+ ConfigNode *configNode, \
+ const std::string &simObjClassName) \
+ : SimObjectBuilder(configClass, instanceName, \
+ configNode, simObjClassName),
+
+
+#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(const std::string &configClass, \
+ const std::string &instanceName, \
+ ConfigNode *configNode, \
+ const std::string &simObjClassName) \
+{ \
+ return new OBJ_CLASS##Builder(configClass, instanceName, \
+ configNode, simObjClassName); \
+} \
+ \
+SimObjectClass the##OBJ_CLASS##Class(CLASS_NAME, \
+ new##OBJ_CLASS##Builder); \
+ \
+/* see param.hh */ \
+DEFINE_SIM_OBJECT_CLASS_NAME(CLASS_NAME, OBJ_CLASS)
+
+
+#endif // __SIM_OBJECT_HH__
diff --git a/sim/sim_time.cc b/sim/sim_time.cc
new file mode 100644
index 000000000..c235be5db
--- /dev/null
+++ b/sim/sim_time.cc
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+#include <iostream>
+
+#include "sim_time.hh"
+
+using namespace std;
+
+namespace Time
+{
+ struct _timeval
+ {
+ timeval tv;
+ };
+
+ double
+ convert(const timeval &tv)
+ {
+ return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
+ }
+
+ Start::Start()
+ {
+ start = new _timeval;
+ ::gettimeofday(&start->tv, NULL);
+ }
+
+ Start::~Start()
+ {
+ delete start;
+ }
+
+ const timeval &
+ Start::get() const
+ {
+ return start->tv;
+ }
+
+ double
+ Start::operator()() const
+ {
+ return convert(get());
+ }
+
+ Now::Now()
+ : now(0)
+ {
+ }
+
+ Now::~Now()
+ {
+ if (now)
+ delete now;
+ }
+
+ const timeval &
+ Now::get() const
+ {
+ if (!now)
+ now = new _timeval;
+
+ ::gettimeofday(&now->tv, NULL);
+ return now->tv;
+ }
+
+ double
+ Now::operator()() const
+ {
+ return convert(get());
+ }
+
+
+ Elapsed::Elapsed()
+ : elapsed(0)
+ {}
+
+ Elapsed::~Elapsed()
+ {
+ if (elapsed)
+ delete elapsed;
+ }
+
+ const timeval &
+ Elapsed::get() const
+ {
+ if (!elapsed)
+ elapsed = new _timeval;
+
+ timersub(&now.get(), &start.get(), &elapsed->tv);
+ return elapsed->tv;
+ }
+
+ double
+ Elapsed::operator()() const
+ {
+ return convert(get());
+ }
+
+ Start start;
+ Now now;
+ Elapsed elapsed;
+
+ ostream &
+ operator<<(ostream &out, const Start &start)
+ {
+ out << ::ctime(&start.get().tv_sec);
+ return out;
+ }
+
+ ostream &
+ operator<<(ostream &out, const Now &now)
+ {
+ out << ::ctime(&now.get().tv_sec);
+ return out;
+ }
+
+ ostream &
+ operator<<(ostream &out, const Elapsed &elapsed)
+ {
+ out << ::ctime(&elapsed.get().tv_sec);
+ return out;
+ }
+}
diff --git a/sim/sim_time.hh b/sim/sim_time.hh
new file mode 100644
index 000000000..dbba42aa7
--- /dev/null
+++ b/sim/sim_time.hh
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+#ifndef __SIM_TIME_HH__
+#define __SIM_TIME_HH__
+
+#include <iosfwd>
+
+namespace Time {
+ struct _timeval;
+ class Start
+ {
+ private:
+ mutable _timeval *start;
+
+ public:
+ Start();
+ ~Start();
+
+ const timeval &get() const;
+ double operator()() const;
+ };
+
+ class Now
+ {
+ private:
+ mutable _timeval *now;
+
+ public:
+ Now();
+ ~Now();
+
+ const timeval &get() const;
+ double operator()() const;
+ };
+
+ class Elapsed
+ {
+ private:
+ mutable _timeval *elapsed;
+
+ public:
+ Elapsed();
+ ~Elapsed();
+
+ const timeval &get() const;
+ double operator()() const;
+ };
+
+ extern Start start;
+ extern Now now;
+ extern Elapsed elapsed;
+
+ std::ostream &operator<<(std::ostream &out, const Start &start);
+ std::ostream &operator<<(std::ostream &out, const Now &now);
+ std::ostream &operator<<(std::ostream &out, const Elapsed &elapsed);
+}
+
+#endif // __SIM_TIME_HH__
diff --git a/sim/simple_cpu.cc b/sim/simple_cpu.cc
new file mode 100644
index 000000000..96743d0fa
--- /dev/null
+++ b/sim/simple_cpu.cc
@@ -0,0 +1,747 @@
+/*
+ * 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.
+ */
+
+#include <iostream>
+#include <iomanip>
+#include <list>
+#include <sstream>
+#include <string>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "host.hh"
+#include "cprintf.hh"
+#include "misc.hh"
+#include "stats.hh"
+#include "smt.hh"
+
+#include "annotation.hh"
+#include "exec_context.hh"
+#include "base_cpu.hh"
+#include "debug.hh"
+#include "simple_cpu.hh"
+#include "inifile.hh"
+#include "mem_interface.hh"
+#include "base_mem.hh"
+#include "static_inst.hh"
+
+#ifdef FULL_SYSTEM
+#include "memory_control.hh"
+#include "physical_memory.hh"
+#include "alpha_memory.hh"
+#include "system.hh"
+#else // !FULL_SYSTEM
+#include "functional_memory.hh"
+#include "prog.hh"
+#include "eio.hh"
+#endif // FULL_SYSTEM
+
+#include "exetrace.hh"
+#include "trace.hh"
+#include "sim_events.hh"
+#include "pollevent.hh"
+#include "sim_object.hh"
+#include "sim_stats.hh"
+
+#include "range.hh"
+#include "symtab.hh"
+
+#ifdef FULL_SYSTEM
+#include "vtophys.hh"
+#include "pciareg.h"
+#include "remote_gdb.hh"
+#include "alpha_access.h"
+#endif
+
+
+using namespace std;
+
+SimpleCPU::CacheCompletionEvent::CacheCompletionEvent(SimpleCPU *_cpu)
+ : Event(&mainEventQueue),
+ cpu(_cpu)
+{
+}
+
+void SimpleCPU::CacheCompletionEvent::process()
+{
+ cpu->processCacheCompletion();
+}
+
+const char *
+SimpleCPU::CacheCompletionEvent::description()
+{
+ return "cache completion event";
+}
+
+#ifdef FULL_SYSTEM
+SimpleCPU::SimpleCPU(const string &_name,
+ System *_system,
+ Counter max_insts_any_thread,
+ Counter max_insts_all_threads,
+ AlphaItb *itb, AlphaDtb *dtb,
+ FunctionalMemory *mem,
+ MemInterface *icache_interface,
+ MemInterface *dcache_interface,
+ int cpu_id, Tick freq)
+ : BaseCPU(_name, /* number_of_threads */ 1,
+ max_insts_any_thread, max_insts_all_threads,
+ _system, cpu_id, freq),
+#else
+SimpleCPU::SimpleCPU(const string &_name, Process *_process,
+ Counter max_insts_any_thread,
+ Counter max_insts_all_threads,
+ MemInterface *icache_interface,
+ MemInterface *dcache_interface)
+ : BaseCPU(_name, /* number_of_threads */ 1,
+ max_insts_any_thread, max_insts_all_threads),
+#endif
+ tickEvent(this), xc(NULL), cacheCompletionEvent(this)
+{
+#ifdef FULL_SYSTEM
+ xc = new ExecContext(this, 0, system, itb, dtb, mem, cpu_id);
+
+ _status = Running;
+ if (cpu_id != 0) {
+
+ xc->setStatus(ExecContext::Unallocated);
+
+ //Open a GDB debug session on port (7000 + the cpu_id)
+ (new GDBListener(new RemoteGDB(system, xc), 7000 + cpu_id))->listen();
+
+ AlphaISA::init(system->physmem, &xc->regs);
+
+ fault = Reset_Fault;
+
+ IntReg *ipr = xc->regs.ipr;
+ ipr[TheISA::IPR_MCSR] = 0x6;
+
+ AlphaISA::swap_palshadow(&xc->regs, true);
+
+ xc->regs.pc =
+ ipr[TheISA::IPR_PAL_BASE] + AlphaISA::fault_addr[fault];
+ xc->regs.npc = xc->regs.pc + sizeof(MachInst);
+
+ _status = Idle;
+ }
+ else {
+ system->initBootContext(xc);
+
+ // Reset the system
+ //
+ AlphaISA::init(system->physmem, &xc->regs);
+
+ fault = Reset_Fault;
+
+ IntReg *ipr = xc->regs.ipr;
+ ipr[TheISA::IPR_MCSR] = 0x6;
+
+ AlphaISA::swap_palshadow(&xc->regs, true);
+
+ xc->regs.pc = ipr[TheISA::IPR_PAL_BASE] + AlphaISA::fault_addr[fault];
+ xc->regs.npc = xc->regs.pc + sizeof(MachInst);
+
+ _status = Running;
+ tickEvent.schedule(0);
+ }
+
+#else
+ xc = new ExecContext(this, /* thread_num */ 0, _process, /* asid */ 0);
+ fault = No_Fault;
+ if (xc->status() == ExecContext::Active) {
+ _status = Running;
+ tickEvent.schedule(0);
+ } else
+ _status = Idle;
+#endif // !FULL_SYSTEM
+
+ icacheInterface = icache_interface;
+ dcacheInterface = dcache_interface;
+
+ memReq = new MemReq();
+ memReq->xc = xc;
+ memReq->asid = 0;
+
+ numInst = 0;
+ last_idle = 0;
+ lastIcacheStall = 0;
+ lastDcacheStall = 0;
+
+ contexts.push_back(xc);
+}
+
+SimpleCPU::~SimpleCPU()
+{
+}
+
+void
+SimpleCPU::regStats()
+{
+ BaseCPU::regStats();
+
+ numInsts
+ .name(name() + ".num_insts")
+ .desc("Number of instructions executed")
+ ;
+
+ numMemRefs
+ .name(name() + ".num_refs")
+ .desc("Number of memory references")
+ ;
+
+ idleCycles
+ .name(name() + ".idle_cycles")
+ .desc("Number of 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)
+ ;
+
+ idleFraction = idleCycles / simTicks;
+
+ numInsts = Statistics::scalar(numInst);
+ simInsts += numInsts;
+}
+
+void
+SimpleCPU::serialize()
+{
+ nameOut();
+
+#ifdef FULL_SYSTEM
+#if 0
+ // do we need this anymore?? egh
+ childOut("itb", xc->itb);
+ childOut("dtb", xc->dtb);
+ childOut("physmem", physmem);
+#endif
+#endif
+
+ for (int i = 0; i < NumIntRegs; i++) {
+ stringstream buf;
+ ccprintf(buf, "R%02d", i);
+ paramOut(buf.str(), xc->regs.intRegFile[i]);
+ }
+ for (int i = 0; i < NumFloatRegs; i++) {
+ stringstream buf;
+ ccprintf(buf, "F%02d", i);
+ paramOut(buf.str(), xc->regs.floatRegFile.d[i]);
+ }
+ // CPUTraitsType::serializeSpecialRegs(getProxy(), xc->regs);
+}
+
+void
+SimpleCPU::unserialize(IniFile &db, const string &category, ConfigNode *node)
+{
+ string data;
+
+ for (int i = 0; i < NumIntRegs; i++) {
+ stringstream buf;
+ ccprintf(buf, "R%02d", i);
+ db.findDefault(category, buf.str(), data);
+ to_number(data,xc->regs.intRegFile[i]);
+ }
+ for (int i = 0; i < NumFloatRegs; i++) {
+ stringstream buf;
+ ccprintf(buf, "F%02d", i);
+ db.findDefault(category, buf.str(), data);
+ xc->regs.floatRegFile.d[i] = strtod(data.c_str(),NULL);
+ }
+
+ // Read in Special registers
+
+ // CPUTraitsType::unserializeSpecialRegs(db,category,node,xc->regs);
+}
+
+void
+change_thread_state(int thread_number, int activate, int priority)
+{
+}
+
+// precise architected memory state accessor macros
+template <class T>
+Fault
+SimpleCPU::read(Addr addr, T& data, unsigned flags)
+{
+ memReq->reset(addr, sizeof(T), flags);
+
+ // translate to physical address
+ Fault fault = xc->translateDataReadReq(memReq);
+
+ // do functional access
+ if (fault == No_Fault)
+ fault = xc->read(memReq, data);
+
+ if (traceData) {
+ traceData->setAddr(addr);
+ if (fault == No_Fault)
+ traceData->setData(data);
+ }
+
+ // if we have a cache, do cache access too
+ if (fault == No_Fault && dcacheInterface) {
+ memReq->cmd = Read;
+ memReq->completionEvent = NULL;
+ memReq->time = curTick;
+ memReq->flags &= ~UNCACHEABLE;
+ MemAccessResult result = dcacheInterface->access(memReq);
+
+ // Ugly hack to get an event scheduled *only* if the access is
+ // a miss. We really should add first-class support for this
+ // at some point.
+ if (result != MA_HIT && dcacheInterface->doEvents) {
+ memReq->completionEvent = &cacheCompletionEvent;
+ setStatus(DcacheMissStall);
+ }
+ }
+
+ return fault;
+}
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+template
+Fault
+SimpleCPU::read(Addr addr, uint64_t& data, unsigned flags);
+
+template
+Fault
+SimpleCPU::read(Addr addr, uint32_t& data, unsigned flags);
+
+template
+Fault
+SimpleCPU::read(Addr addr, uint16_t& data, unsigned flags);
+
+template
+Fault
+SimpleCPU::read(Addr addr, uint8_t& data, unsigned flags);
+
+#endif //DOXYGEN_SHOULD_SKIP_THIS
+
+template<>
+Fault
+SimpleCPU::read(Addr addr, double& data, unsigned flags)
+{
+ return read(addr, *(uint64_t*)&data, flags);
+}
+
+template<>
+Fault
+SimpleCPU::read(Addr addr, float& data, unsigned flags)
+{
+ return read(addr, *(uint32_t*)&data, flags);
+}
+
+
+template<>
+Fault
+SimpleCPU::read(Addr addr, int32_t& data, unsigned flags)
+{
+ return read(addr, (uint32_t&)data, flags);
+}
+
+
+template <class T>
+Fault
+SimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
+{
+ if (traceData) {
+ traceData->setAddr(addr);
+ traceData->setData(data);
+ }
+
+ memReq->reset(addr, sizeof(T), flags);
+
+ // translate to physical address
+ Fault fault = xc->translateDataWriteReq(memReq);
+
+ // do functional access
+ if (fault == No_Fault)
+ fault = xc->write(memReq, data);
+
+ if (fault == No_Fault && dcacheInterface) {
+ memReq->cmd = Write;
+ memReq->data = (uint8_t *)&data;
+ memReq->completionEvent = NULL;
+ memReq->time = curTick;
+ memReq->flags &= ~UNCACHEABLE;
+ MemAccessResult result = dcacheInterface->access(memReq);
+
+ // Ugly hack to get an event scheduled *only* if the access is
+ // a miss. We really should add first-class support for this
+ // at some point.
+ if (result != MA_HIT && dcacheInterface->doEvents) {
+ memReq->completionEvent = &cacheCompletionEvent;
+ setStatus(DcacheMissStall);
+ }
+ }
+
+ if (res && (fault == No_Fault))
+ *res = memReq->result;
+
+ return fault;
+}
+
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+template
+Fault
+SimpleCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res);
+
+template
+Fault
+SimpleCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res);
+
+template
+Fault
+SimpleCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res);
+
+template
+Fault
+SimpleCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res);
+
+#endif //DOXYGEN_SHOULD_SKIP_THIS
+
+template<>
+Fault
+SimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
+{
+ return write(*(uint64_t*)&data, addr, flags, res);
+}
+
+template<>
+Fault
+SimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
+{
+ return write(*(uint32_t*)&data, addr, flags, res);
+}
+
+
+template<>
+Fault
+SimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
+{
+ return write((uint32_t)data, addr, flags, res);
+}
+
+
+#ifdef FULL_SYSTEM
+Addr
+SimpleCPU::dbg_vtophys(Addr addr)
+{
+ return vtophys(xc, addr);
+}
+#endif // FULL_SYSTEM
+
+Tick save_cycle = 0;
+
+
+void
+SimpleCPU::processCacheCompletion()
+{
+ switch (status()) {
+ case IcacheMissStall:
+ icacheStallCycles += curTick - lastIcacheStall;
+ setStatus(IcacheMissComplete);
+ break;
+ case DcacheMissStall:
+ dcacheStallCycles += curTick - lastDcacheStall;
+ setStatus(Running);
+ break;
+ default:
+ panic("SimpleCPU::processCacheCompletion: bad state");
+ break;
+ }
+}
+
+#ifdef FULL_SYSTEM
+void
+SimpleCPU::post_interrupt(int int_num, int index)
+{
+ BaseCPU::post_interrupt(int_num, index);
+
+ if (xc->status() == ExecContext::Suspended) {
+ DPRINTF(IPI,"Suspended Processor awoke\n");
+ xc->setStatus(ExecContext::Active);
+ Annotate::Resume(xc);
+ }
+}
+#endif // FULL_SYSTEM
+
+/* start simulation, program loaded, processor precise state initialized */
+void
+SimpleCPU::tick()
+{
+ traceData = NULL;
+
+#ifdef FULL_SYSTEM
+ if (fault == No_Fault && AlphaISA::check_interrupts &&
+ xc->cpu->check_interrupts() &&
+ !PC_PAL(xc->regs.pc) &&
+ status() != IcacheMissComplete) {
+ int ipl = 0;
+ int summary = 0;
+ AlphaISA::check_interrupts = 0;
+ IntReg *ipr = xc->regs.ipr;
+
+ if (xc->regs.ipr[TheISA::IPR_SIRR]) {
+ for (int i = TheISA::INTLEVEL_SOFTWARE_MIN;
+ i < TheISA::INTLEVEL_SOFTWARE_MAX; i++) {
+ if (ipr[TheISA::IPR_SIRR] & (ULL(1) << i)) {
+ // See table 4-19 of 21164 hardware reference
+ ipl = (i - TheISA::INTLEVEL_SOFTWARE_MIN) + 1;
+ summary |= (ULL(1) << i);
+ }
+ }
+ }
+
+ uint64_t interrupts = xc->cpu->intr_status();
+ for(int i = TheISA::INTLEVEL_EXTERNAL_MIN;
+ i < TheISA::INTLEVEL_EXTERNAL_MAX; i++) {
+ if (interrupts & (ULL(1) << i)) {
+ // See table 4-19 of 21164 hardware reference
+ ipl = i;
+ summary |= (ULL(1) << i);
+ }
+ }
+
+ if (ipr[TheISA::IPR_ASTRR])
+ panic("asynchronous traps not implemented\n");
+
+ if (ipl && ipl > xc->regs.ipr[TheISA::IPR_IPLR]) {
+ ipr[TheISA::IPR_ISR] = summary;
+ ipr[TheISA::IPR_INTID] = ipl;
+ xc->ev5_trap(Interrupt_Fault);
+
+ DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n",
+ ipr[TheISA::IPR_IPLR], ipl, summary);
+ }
+ }
+#endif
+
+ // maintain $r0 semantics
+ xc->regs.intRegFile[ZeroReg] = 0;
+#ifdef TARGET_ALPHA
+ xc->regs.floatRegFile.d[ZeroReg] = 0.0;
+#endif // TARGET_ALPHA
+
+ if (status() == IcacheMissComplete) {
+ // We've already fetched an instruction and were stalled on an
+ // I-cache miss. No need to fetch it again.
+
+ setStatus(Running);
+ }
+ else {
+ // Try to fetch an instruction
+
+ // set up memory request for instruction fetch
+#ifdef FULL_SYSTEM
+#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0
+#else
+#define IFETCH_FLAGS(pc) 0
+#endif
+
+ memReq->cmd = Read;
+ memReq->reset(xc->regs.pc & ~3, sizeof(uint32_t),
+ IFETCH_FLAGS(xc->regs.pc));
+
+ fault = xc->translateInstReq(memReq);
+
+ if (fault == No_Fault)
+ fault = xc->mem->read(memReq, inst);
+
+ if (icacheInterface && fault == No_Fault) {
+ memReq->completionEvent = NULL;
+
+ memReq->time = curTick;
+ memReq->flags &= ~UNCACHEABLE;
+ MemAccessResult result = icacheInterface->access(memReq);
+
+ // Ugly hack to get an event scheduled *only* if the access is
+ // a miss. We really should add first-class support for this
+ // at some point.
+ if (result != MA_HIT && icacheInterface->doEvents) {
+ memReq->completionEvent = &cacheCompletionEvent;
+ setStatus(IcacheMissStall);
+ return;
+ }
+ }
+ }
+
+ // If we've got a valid instruction (i.e., no fault on instruction
+ // fetch), then execute it.
+ if (fault == No_Fault) {
+
+ // keep an instruction count
+ numInst++;
+
+ // check for instruction-count-based events
+ comInsnEventQueue[0]->serviceEvents(numInst);
+
+ // decode the instruction
+ StaticInstPtr<TheISA> si(inst);
+
+ traceData = Trace::getInstRecord(curTick, xc, this, si,
+ xc->regs.pc);
+
+#ifdef FULL_SYSTEM
+ xc->regs.opcode = (inst >> 26) & 0x3f;
+ xc->regs.ra = (inst >> 21) & 0x1f;
+#endif // FULL_SYSTEM
+
+ xc->func_exe_insn++;
+
+ fault = si->execute(this, xc, traceData);
+
+ if (si->isMemRef()) {
+ numMemRefs++;
+ }
+
+ if (traceData)
+ traceData->finalize();
+
+ } // if (fault == No_Fault)
+
+ if (fault != No_Fault) {
+#ifdef FULL_SYSTEM
+ xc->ev5_trap(fault);
+#else // !FULL_SYSTEM
+ fatal("fault (%d) detected @ PC 0x%08p", fault, xc->regs.pc);
+#endif // FULL_SYSTEM
+ }
+ else {
+ // go to the next instruction
+ xc->regs.pc = xc->regs.npc;
+ xc->regs.npc += sizeof(MachInst);
+ }
+
+#ifdef FULL_SYSTEM
+ Addr oldpc;
+ do {
+ oldpc = xc->regs.pc;
+ system->pcEventQueue.service(xc);
+ } while (oldpc != xc->regs.pc);
+#endif
+
+ assert(status() == Running ||
+ status() == Idle ||
+ status() == DcacheMissStall);
+
+ if (status() == Running && !tickEvent.scheduled())
+ tickEvent.schedule(curTick + 1);
+}
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// SimpleCPU Simulation Object
+//
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
+
+ Param<Counter> max_insts_any_thread;
+ Param<Counter> max_insts_all_threads;
+
+#ifdef FULL_SYSTEM
+ SimObjectParam<AlphaItb *> itb;
+ SimObjectParam<AlphaDtb *> dtb;
+ SimObjectParam<FunctionalMemory *> mem;
+ SimObjectParam<System *> system;
+ Param<int> cpu_id;
+ Param<int> mult;
+#else
+ SimObjectParam<Process *> workload;
+#endif // FULL_SYSTEM
+
+ SimObjectParam<BaseMem *> icache;
+ SimObjectParam<BaseMem *> dcache;
+
+END_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
+
+ INIT_PARAM_DFLT(max_insts_any_thread,
+ "terminate when any thread reaches this insn count",
+ 0),
+ INIT_PARAM_DFLT(max_insts_all_threads,
+ "terminate when all threads have reached this insn count",
+ 0),
+
+#ifdef FULL_SYSTEM
+ INIT_PARAM(itb, "Instruction TLB"),
+ INIT_PARAM(dtb, "Data TLB"),
+ INIT_PARAM(mem, "memory"),
+ INIT_PARAM(system, "system object"),
+ INIT_PARAM_DFLT(cpu_id, "CPU identification number", 0),
+ INIT_PARAM_DFLT(mult, "system clock multiplier", 1),
+#else
+ INIT_PARAM(workload, "processes to run"),
+#endif // FULL_SYSTEM
+
+ INIT_PARAM_DFLT(icache, "L1 instruction cache object", NULL),
+ INIT_PARAM_DFLT(dcache, "L1 data cache object", NULL)
+
+END_INIT_SIM_OBJECT_PARAMS(SimpleCPU)
+
+
+CREATE_SIM_OBJECT(SimpleCPU)
+{
+#ifdef FULL_SYSTEM
+ if (mult != 1)
+ panic("processor clock multiplier must be 1\n");
+
+ return new SimpleCPU(getInstanceName(), system,
+ max_insts_any_thread, max_insts_all_threads,
+ itb, dtb, mem,
+ (icache) ? icache->getInterface() : NULL,
+ (dcache) ? dcache->getInterface() : NULL,
+ cpu_id, ticksPerSecond * mult);
+#else
+
+ return new SimpleCPU(getInstanceName(), workload,
+ max_insts_any_thread, max_insts_all_threads,
+ icache->getInterface(), dcache->getInterface());
+
+#endif // FULL_SYSTEM
+}
+
+REGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU)
diff --git a/sim/simple_cpu.hh b/sim/simple_cpu.hh
new file mode 100644
index 000000000..c5671eb6f
--- /dev/null
+++ b/sim/simple_cpu.hh
@@ -0,0 +1,280 @@
+/*
+ * 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.
+ */
+
+#ifndef __SIMPLE_CPU_HH__
+#define __SIMPLE_CPU_HH__
+
+#include "base_cpu.hh"
+#include "eventq.hh"
+#include "symtab.hh"
+#include "pc_event.hh"
+#include "statistics.hh"
+
+
+// forward declarations
+#ifdef FULL_SYSTEM
+class Processor;
+class Kernel;
+class AlphaItb;
+class AlphaDtb;
+class PhysicalMemory;
+
+class RemoteGDB;
+class GDBListener;
+#endif // FULL_SYSTEM
+
+class MemInterface;
+class IniFile;
+
+namespace Trace {
+ class InstRecord;
+}
+
+class SimpleCPU : public BaseCPU
+{
+ public:
+ // main simulation loop (one cycle)
+ void tick();
+
+ private:
+ class TickEvent : public Event
+ {
+ private:
+ SimpleCPU *cpu;
+
+ public:
+ TickEvent(SimpleCPU *c)
+ : Event(&mainEventQueue, 100), cpu(c) { }
+ void process() { cpu->tick(); }
+ virtual const char *description() { return "tick event"; }
+ };
+
+ TickEvent tickEvent;
+
+ private:
+ Trace::InstRecord *traceData;
+ template<typename T>
+ void trace_data(T data) {
+ if (traceData) {
+ traceData->setData(data);
+ }
+ };
+
+ public:
+ //
+ enum Status {
+ Running,
+ Idle,
+ IcacheMissStall,
+ IcacheMissComplete,
+ DcacheMissStall
+ };
+
+ 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;
+ }
+ };
+
+#ifdef FULL_SYSTEM
+
+ SimpleCPU(const std::string &_name,
+ System *_system,
+ Counter max_insts_any_thread, Counter max_insts_all_threads,
+ AlphaItb *itb, AlphaDtb *dtb, FunctionalMemory *mem,
+ MemInterface *icache_interface, MemInterface *dcache_interface,
+ int cpu_id, Tick freq);
+
+#else
+
+ SimpleCPU(const std::string &_name, Process *_process,
+ Counter max_insts_any_thread,
+ Counter max_insts_all_threads,
+ MemInterface *icache_interface, MemInterface *dcache_interface);
+
+#endif
+
+ virtual ~SimpleCPU();
+
+ // execution context
+ ExecContext *xc;
+
+#ifdef FULL_SYSTEM
+ Addr dbg_vtophys(Addr addr);
+
+ bool interval_stats;
+#endif
+
+ // L1 instruction cache
+ MemInterface *icacheInterface;
+
+ // L1 data cache
+ MemInterface *dcacheInterface;
+
+ // current instruction
+ MachInst inst;
+
+ // current fault status
+ Fault fault;
+
+ // Refcounted pointer to the one memory request.
+ MemReqPtr memReq;
+
+ class CacheCompletionEvent : public Event
+ {
+ private:
+ SimpleCPU *cpu;
+
+ public:
+ CacheCompletionEvent(SimpleCPU *_cpu);
+
+ virtual void process();
+ virtual const char *description();
+ };
+
+ CacheCompletionEvent cacheCompletionEvent;
+
+ Status status() const { return _status; }
+ virtual void execCtxStatusChg() {
+ if (xc) {
+ if (xc->status() == ExecContext::Active)
+ setStatus(Running);
+ else
+ setStatus(Idle);
+ }
+ }
+
+ void setStatus(Status new_status) {
+ Status old_status = status();
+ _status = new_status;
+
+ switch (status()) {
+ case IcacheMissStall:
+ assert(old_status == Running);
+ lastIcacheStall = curTick;
+ if (tickEvent.scheduled())
+ tickEvent.squash();
+ break;
+
+ case IcacheMissComplete:
+ assert(old_status == IcacheMissStall);
+ if (tickEvent.squashed())
+ tickEvent.reschedule(curTick + 1);
+ else if (!tickEvent.scheduled())
+ tickEvent.schedule(curTick + 1);
+ break;
+
+ case DcacheMissStall:
+ assert(old_status == Running);
+ lastDcacheStall = curTick;
+ if (tickEvent.scheduled())
+ tickEvent.squash();
+ break;
+
+ case Idle:
+ assert(old_status == Running);
+ last_idle = curTick;
+ if (tickEvent.scheduled())
+ tickEvent.squash();
+ break;
+
+ case Running:
+ assert(old_status == Idle ||
+ old_status == DcacheMissStall ||
+ old_status == IcacheMissComplete);
+ if (old_status == Idle)
+ idleCycles += curTick - last_idle;
+
+ if (tickEvent.squashed())
+ tickEvent.reschedule(curTick + 1);
+ else if (!tickEvent.scheduled())
+ tickEvent.schedule(curTick + 1);
+ break;
+
+ default:
+ panic("can't get here");
+ }
+ }
+
+ // statistics
+ void regStats();
+
+ // number of simulated instructions
+ Counter numInst;
+ Statistics::Formula numInsts;
+
+ // number of simulated memory references
+ Statistics::Scalar<> numMemRefs;
+
+ // number of idle cycles
+ Statistics::Scalar<> idleCycles;
+ Statistics::Formula idleFraction;
+ Counter last_idle;
+
+ // number of cycles stalled for I-cache misses
+ Statistics::Scalar<> icacheStallCycles;
+ Counter lastIcacheStall;
+
+ // number of cycles stalled for D-cache misses
+ Statistics::Scalar<> dcacheStallCycles;
+ Counter lastDcacheStall;
+
+ void processCacheCompletion();
+
+ virtual void serialize();
+ virtual void unserialize(IniFile &db, const std::string &category,
+ ConfigNode *node);
+
+ 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);
+
+ Fault prefetch(Addr addr, unsigned flags)
+ {
+ // need to do this...
+ return No_Fault;
+ }
+
+ void writeHint(Addr addr, int size)
+ {
+ // need to do this...
+ }
+};
+
+#endif // __SIMPLE_CPU_HH__
diff --git a/sim/smt.hh b/sim/smt.hh
new file mode 100644
index 000000000..f9c1e4614
--- /dev/null
+++ b/sim/smt.hh
@@ -0,0 +1,64 @@
+/*
+ * 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
+ * Defines SMT_MAX_CPUS and SMT_MAX_THREADS.
+ */
+
+#ifndef __SMT_HH__
+#define __SMT_HH__
+
+#ifndef SMT_MAX_CPUS
+/** The maximum number of cpus in any one system. */
+#define SMT_MAX_CPUS 4
+#endif
+
+#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/sim/static_inst.cc b/sim/static_inst.cc
new file mode 100644
index 000000000..cf25d5f05
--- /dev/null
+++ b/sim/static_inst.cc
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+#include <iostream>
+#include "static_inst.hh"
+#include "universe.hh"
+
+template <class ISA>
+StaticInstPtr<ISA> StaticInst<ISA>::nullStaticInstPtr;
+
+template <class ISA>
+typename StaticInst<ISA>::DecodeCache StaticInst<ISA>::decodeCache;
+
+// Define the decode cache hash map.
+template StaticInst<AlphaISA>::DecodeCache
+StaticInst<AlphaISA>::decodeCache;
+
+template <class ISA>
+void
+StaticInst<ISA>::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;
+ }
+}
+
+
+template StaticInstPtr<AlphaISA>
+StaticInst<AlphaISA>::nullStaticInstPtr;
+
+template <class ISA>
+bool
+StaticInst<ISA>::hasBranchTarget(Addr pc, ExecContext *xc, Addr &tgt)
+{
+ if (isDirectCtrl()) {
+ tgt = branchTarget(pc);
+ return true;
+ }
+
+ if (isIndirectCtrl()) {
+ tgt = branchTarget(xc);
+ return true;
+ }
+
+ return false;
+}
+
+
+// force instantiation of template function(s) above
+template StaticInst<AlphaISA>;
diff --git a/sim/static_inst.hh b/sim/static_inst.hh
new file mode 100644
index 000000000..b8f9cc00a
--- /dev/null
+++ b/sim/static_inst.hh
@@ -0,0 +1,433 @@
+/*
+ * 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.
+ */
+
+#ifndef __STATIC_INST_HH__
+#define __STATIC_INST_HH__
+
+#include <bitset>
+#include <string>
+
+#include "host.hh"
+#include "hashmap.hh"
+#include "refcnt.hh"
+
+#include "op_class.hh"
+#include "isa_traits.hh"
+
+// forward declarations
+class ExecContext;
+class SpecExecContext;
+class SimpleCPU;
+class CPU;
+class DynInst;
+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. Prefetches are marked as IsLoad, even if they
+ /// prefetch exclusive copies.
+ /// - 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.
+ ///
+ 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.
+
+ 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.
+
+ IsThreadSync, ///< Thread synchronization operation.
+
+ 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 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]; }
+ //@}
+
+ /// Operation class. Used to select appropriate function unit in issue.
+ OpClass opClass() const { return _opClass; }
+};
+
+
+// forward declaration
+template <class ISA>
+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.
+ */
+template <class ISA>
+class StaticInst : public StaticInstBase
+{
+ public:
+
+ /// Binary machine instruction type.
+ typedef typename ISA::MachInst MachInst;
+ /// Memory address type.
+ typedef typename ISA::Addr Addr;
+ /// Logical register index type.
+ typedef typename ISA::RegIndex RegIndex;
+
+ enum {
+ MaxInstSrcRegs = ISA::MaxInstSrcRegs, //< Max source regs
+ MaxInstDestRegs = ISA::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) { 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) { 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<ISA> 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 StaticInstPtr<ISA> eaCompInst() { 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 StaticInstPtr<ISA> memAccInst() { return nullStaticInstPtr; }
+
+ /// The binary machine instruction.
+ const MachInst 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()).
+ */
+ std::string *cachedDisassembly;
+
+ /**
+ * Internal function to generate disassembly string.
+ */
+ virtual std::string generateDisassembly(Addr pc,
+ const SymbolTable *symtab) = 0;
+
+ /// Constructor.
+ StaticInst(const char *_mnemonic, MachInst _machInst, OpClass __opClass)
+ : StaticInstBase(__opClass),
+ machInst(_machInst), mnemonic(_mnemonic), cachedDisassembly(0)
+ {
+ }
+
+ public:
+
+ virtual ~StaticInst()
+ {
+ if (cachedDisassembly)
+ delete cachedDisassembly;
+ }
+
+ /**
+ * Execute this instruction under SimpleCPU model.
+ */
+ virtual Fault execute(SimpleCPU *cpu, ExecContext *xc,
+ Trace::InstRecord *traceData) = 0;
+
+ /**
+ * Execute this instruction under detailed CPU model.
+ */
+ virtual Fault execute(CPU *cpu, SpecExecContext *xc, DynInst *dynInst,
+ Trace::InstRecord *traceData) = 0;
+
+ /**
+ * 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)
+ {
+ 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.
+ * Invalid if not an indirect branch (i.e. isIndirectCtrl()
+ * should be true).
+ */
+ virtual Addr branchTarget(ExecContext *xc)
+ {
+ 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);
+
+ /**
+ * 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)
+ {
+ 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<MachInst, StaticInstPtr<ISA> > 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.
+ static
+ StaticInstPtr<ISA> decode(MachInst 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
+
+ typename DecodeCache::iterator iter = decodeCache.find(mach_inst);
+ if (iter != decodeCache.end()) {
+ return iter->second;
+ }
+
+ StaticInstPtr<ISA> si = ISA::decodeInst(mach_inst);
+ decodeCache[mach_inst] = si;
+ return si;
+ }
+};
+
+typedef RefCountingPtr<StaticInstBase> StaticInstBasePtr;
+
+/// Reference-counted pointer to a StaticInst object.
+/// This type should be used instead of "StaticInst<ISA> *" so that
+/// StaticInst objects can be properly reference-counted.
+template <class ISA>
+class StaticInstPtr : public RefCountingPtr<StaticInst<ISA> >
+{
+ public:
+ /// Constructor.
+ StaticInstPtr()
+ : RefCountingPtr<StaticInst<ISA> >()
+ {
+ }
+
+ /// Conversion from "StaticInst<ISA> *".
+ StaticInstPtr(StaticInst<ISA> *p)
+ : RefCountingPtr<StaticInst<ISA> >(p)
+ {
+ }
+
+ /// Copy constructor.
+ StaticInstPtr(const StaticInstPtr &r)
+ : RefCountingPtr<StaticInst<ISA> >(r)
+ {
+ }
+
+ /// Construct directly from machine instruction.
+ /// Calls StaticInst<ISA>::decode().
+ StaticInstPtr(typename ISA::MachInst mach_inst)
+ : RefCountingPtr<StaticInst<ISA> >(StaticInst<ISA>::decode(mach_inst))
+ {
+ }
+
+ /// Convert to pointer to StaticInstBase class.
+ operator const StaticInstBasePtr()
+ {
+ return get();
+ }
+};
+
+#endif // __STATIC_INST_HH__
diff --git a/sim/std_types.hh b/sim/std_types.hh
new file mode 100644
index 000000000..9c3898ff7
--- /dev/null
+++ b/sim/std_types.hh
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#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 unsigned long long InstSeqNum;
+
+// inst tag type, used to tag an operation instance in the IQ
+typedef unsigned int InstTag;
+
+#endif // __STD_TYPES_HH__
diff --git a/sim/system.cc b/sim/system.cc
new file mode 100644
index 000000000..04db8b134
--- /dev/null
+++ b/sim/system.cc
@@ -0,0 +1,250 @@
+/*
+ * 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.
+ */
+
+#include "kernel_loader.hh"
+#include "exec_context.hh"
+#include "object_file.hh"
+#include "memory_control.hh"
+#include "physical_memory.hh"
+#include "symtab.hh"
+#include "remote_gdb.hh"
+#include "vtophys.hh"
+#include "system.hh"
+#include "trace.hh"
+
+using namespace std;
+
+vector<System *> System::systemList;
+
+int System::numSystemsRunning = 0;
+
+System::System(const std::string _name,
+ MemoryController *_memCtrl,
+ PhysicalMemory *_physmem,
+ const std::string &kernel_path,
+ const std::string &console_path,
+ const std::string &palcode,
+ const std::string &boot_osflags)
+ : SimObject(_name),
+ kernel_panic_event(&pcEventQueue, "kernel panic"),
+ console_panic_event(&pcEventQueue, "console panic"),
+ badaddr_event(&pcEventQueue, "badaddr"),
+ skip_power_state(&pcEventQueue, "tl_v48_capture_power_state"),
+ skip_scavenge_boot(&pcEventQueue, "pmap_scavenge_boot"),
+ printf_event(&pcEventQueue, "printf"),
+ debug_printf_event(&pcEventQueue, "debug_printf", false),
+ debug_printfr_event(&pcEventQueue, "debug_printfr", true),
+ dump_mbuf_event(&pcEventQueue, "dump_mbuf"),
+ memCtrl(_memCtrl),
+ physmem(_physmem),
+ remoteGDB(NULL),
+ gdbListen(NULL)
+{
+ kernelSymtab = new SymbolTable;
+ consoleSymtab = new SymbolTable;
+
+ EcoffObject kernel(kernel_path);
+ EcoffObject console(console_path);
+
+ if (!kernel.loadGlobals(kernelSymtab))
+ panic("could not load kernel symbols\n");
+
+ if (!console.loadGlobals(consoleSymtab))
+ panic("could not load console symbols\n");
+
+ // Load pal file
+ loadPal(palcode, physmem, PAL_BASE);
+
+ // copy of initial reg file contents
+ initRegs = new RegFile;
+ memset(initRegs, 0, sizeof(RegFile));
+
+ // Load console file
+ loadKernel(console_path, physmem);
+
+ // Load kernel file
+ loadKernel(kernel_path, physmem, initRegs,
+ &kernelStart, &kernelEnd, &kernelEntry);
+
+ DPRINTF(Loader, "Kernel loaded...\n");
+
+#ifdef FULL_SYSTEM
+ Addr addr = 0;
+
+ for(int i = 0; i < 12/*MAX_CPUS*/; i++)
+ xc_array[i] = (ExecContext *) 0;
+
+ num_cpus = 0;
+
+ if (kernelSymtab->findAddress("enable_async_printf", addr)) {
+ Addr paddr = vtophys(physmem, addr);
+ uint8_t *enable_async_printf =
+ physmem->dma_addr(paddr, sizeof(uint32_t));
+
+ if (enable_async_printf)
+ *(uint32_t *)enable_async_printf = 0;
+ }
+
+ if (consoleSymtab->findAddress("env_booted_osflags", addr)) {
+ Addr paddr = vtophys(physmem, addr);
+ char *osflags = (char *)physmem->dma_addr(paddr, sizeof(uint32_t));
+
+ if (osflags)
+ strcpy(osflags, boot_osflags.c_str());
+ }
+
+ if (kernelSymtab->findAddress("panic", addr))
+ kernel_panic_event.schedule(addr);
+ else
+ panic("could not find kernel symbol \'panic\'");
+
+ if (consoleSymtab->findAddress("panic", addr))
+ console_panic_event.schedule(addr);
+
+ if (kernelSymtab->findAddress("badaddr", addr))
+ badaddr_event.schedule(addr);
+ else
+ panic("could not find kernel symbol \'badaddr\'");
+
+ if (kernelSymtab->findAddress("tl_v48_capture_power_state", addr))
+ skip_power_state.schedule(addr);
+
+ if (kernelSymtab->findAddress("pmap_scavenge_boot", addr))
+ skip_scavenge_boot.schedule(addr);
+
+#if TRACING_ON
+ if (kernelSymtab->findAddress("printf", addr))
+ printf_event.schedule(addr);
+
+ if (kernelSymtab->findAddress("m5printf", addr))
+ debug_printf_event.schedule(addr);
+
+ if (kernelSymtab->findAddress("m5printfr", addr))
+ debug_printfr_event.schedule(addr);
+
+ if (kernelSymtab->findAddress("m5_dump_mbuf", addr))
+ dump_mbuf_event.schedule(addr);
+#endif
+
+#endif
+
+ // add self to global system list
+ systemList.push_back(this);
+
+ numSystemsRunning++;
+}
+
+
+System::~System()
+{
+ delete kernelSymtab;
+ delete consoleSymtab;
+ delete initRegs;
+}
+
+
+void
+System::initBootContext(ExecContext *xc)
+{
+ xc->regs = *initRegs;
+
+ remoteGDB = new RemoteGDB(this, xc);
+ gdbListen = new GDBListener(remoteGDB, 7000);
+ gdbListen->listen();
+
+ // Reset the system
+ //
+ TheISA::init(physmem, &xc->regs);
+}
+
+
+void
+System::registerExecContext(ExecContext *xc)
+{
+ if (num_cpus == 12/*MAX_CPUS*/)
+ panic("Too many CPU's\n");
+ xc_array[xc->cpu_id] = xc;
+ num_cpus++;
+}
+
+
+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();
+}
+
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(System)
+
+ SimObjectParam<MemoryController *> mem_ctl;
+ SimObjectParam<PhysicalMemory *> physmem;
+
+ Param<string> kernel_code;
+ Param<string> console_code;
+ Param<string> pal_code;
+ Param<string> boot_osflags;
+
+END_DECLARE_SIM_OBJECT_PARAMS(System)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(System)
+
+ INIT_PARAM(mem_ctl, "memory controller"),
+ INIT_PARAM(physmem, "phsyical memory"),
+ INIT_PARAM(kernel_code, "file that contains the kernel code"),
+ INIT_PARAM(console_code, "file that contains the console code"),
+ INIT_PARAM(pal_code, "file that contains palcode"),
+ INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot",
+ "a")
+
+END_INIT_SIM_OBJECT_PARAMS(System)
+
+
+CREATE_SIM_OBJECT(System)
+{
+ System *sys = new System(getInstanceName(), mem_ctl, physmem,
+ kernel_code, console_code, pal_code,
+ boot_osflags);
+
+ return sys;
+}
+
+REGISTER_SIM_OBJECT("System", System)
diff --git a/sim/system.hh b/sim/system.hh
new file mode 100644
index 000000000..bd2fd89b1
--- /dev/null
+++ b/sim/system.hh
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+#ifndef __SYSTEM_HH__
+#define __SYSTEM_HH__
+
+#include <string>
+
+#include "sim_object.hh"
+#include "pc_event.hh"
+#include "symtab.hh"
+
+class MemoryController;
+class PhysicalMemory;
+class RemoteGDB;
+class GDBListener;
+
+class ExecContext;
+
+class System : public SimObject
+{
+ private:
+
+ SymbolTable *kernelSymtab;
+ SymbolTable *consoleSymtab;
+
+ BreakPCEvent kernel_panic_event;
+ BreakPCEvent console_panic_event;
+ BadAddrEvent badaddr_event;
+ SkipFuncEvent skip_power_state;
+ SkipFuncEvent skip_scavenge_boot;
+ PrintfEvent printf_event;
+ DebugPrintfEvent debug_printf_event;
+ DebugPrintfEvent debug_printfr_event;
+ DumpMbufEvent dump_mbuf_event;
+
+ RegFile *initRegs;
+
+ Addr kernelStart;
+ Addr kernelEnd;
+ Addr kernelEntry;
+
+ public:
+
+ MemoryController *memCtrl;
+ PhysicalMemory *physmem;
+
+ PCEventQueue pcEventQueue;
+
+ ExecContext *xc_array[12/*MAX_CPUS*/];
+ int num_cpus;
+
+ RemoteGDB *remoteGDB;
+ GDBListener *gdbListen;
+
+ System(const std::string name,
+ MemoryController *, PhysicalMemory *,
+ const std::string &kernel_path, const std::string &console_path,
+ const std::string &palcode, const std::string &boot_osflags);
+
+ ~System();
+
+ const SymbolTable *getKernelSymtab() const { return kernelSymtab; }
+ const SymbolTable *getConsoleSymtab() const { return consoleSymtab; }
+
+ Addr getKernelStart() const { return kernelStart; }
+ Addr getKernelEnd() const { return kernelEnd; }
+ Addr getKernelEntry() const { return kernelEntry; }
+
+ void initBootContext(ExecContext *xc);
+ void registerExecContext(ExecContext *xc);
+
+ ////////////////////////////////////////////
+ //
+ // STATIC GLOBAL SYSTEM LIST
+ //
+ ////////////////////////////////////////////
+
+ public:
+
+ static std::vector<System *> systemList;
+
+ static int numSystemsRunning;
+
+ static void printSystems();
+};
+
+#endif // __SYSTEM_HH__
diff --git a/sim/universe.cc b/sim/universe.cc
new file mode 100644
index 000000000..83f268b14
--- /dev/null
+++ b/sim/universe.cc
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#include <list>
+#include <string>
+#include <vector>
+
+#include "universe.hh"
+#include "host.hh"
+#include "param.hh"
+
+using namespace std;
+
+Tick curTick = 0;
+Tick ticksPerSecond;
+
+class UniverseParamContext : public ParamContext
+{
+ public:
+ UniverseParamContext(const string &is) : ParamContext(is) {}
+ void checkParams();
+};
+
+UniverseParamContext universe("Universe");
+
+Param<Tick> universe_freq(&universe, "frequency", "tick frequency",
+ 200000000);
+
+void
+UniverseParamContext::checkParams()
+{
+ ticksPerSecond = universe_freq;
+}
diff --git a/test/Makefile b/test/Makefile
new file mode 100644
index 000000000..8c36f9806
--- /dev/null
+++ b/test/Makefile
@@ -0,0 +1,83 @@
+# $Id$
+
+CC= gcc
+CXX= g++
+
+CURDIR?= $(shell /bin/pwd)
+SRCDIR?= .
+TARGET?= alpha
+
+TEST_SRCDIR?= $(SRCDIR)
+ARCH_SRCDIR?= $(SRCDIR)/../arch/$(TARGET)
+BASE_SRCDIR?= $(SRCDIR)/../base
+SIM_SRCDIR?= $(SRCDIR)/../sim
+CACHE_SRCDIR?= $(SRCDIR)/../sim/cache
+OLD_SRCDIR= $(SRCDIR)/../old
+
+vpath % $(TEST_SRCDIR)
+vpath % $(BASE_SRCDIR)
+vpath % $(SIM_SRCDIR)
+vpath % $(CACHE_SRCDIR)
+vpath % $(OLD_SRCDIR)
+
+INCLDIRS= -I$(ARCH_SRCDIR) -I$(BASE_SRCDIR) -I$(SIM_SRCDIR) \
+ -I$(CACHE_SRCDIR) -I$(OLD_SRCDIR)
+CCFLAGS= -g -O0 -MMD -I. $(INCLDIRS) -I- -DTRACING_ON=0
+
+default:
+ @echo "You must specify a target"
+
+bitvectest: bitvectest.o
+ $(CXX) $(LFLAGS) -o $@ $^
+
+circletest: circletest.o circlebuf.o
+ $(CXX) $(LFLAGS) -o $@ $^
+
+cprintftest: cprintftest.o cprintf.o
+ $(CXX) $(LFLAGS) -o $@ $^
+
+initest: initest.o str.o inifile.o
+ $(CXX) $(LFLAGS) -o $@ $^
+
+lrutest: lru_test.o
+ $(CXX) $(LFLAGS) -o $@ $^
+
+nmtest: nmtest.o object_file.o symtab.o misc.o str.o
+ $(CXX) $(LFLAGS) -o $@ $^
+
+offtest: offtest.o
+ $(CXX) $(LFLAGS) -o $@ $^
+
+rangetest: rangetest.o str.o
+ $(CXX) $(LFLAGS) -o $@ $^
+
+stattest: statistics.o stattest.o cprintf.o misc.o omisc.o str.o
+ $(CXX) $(LFLAGS) -o $@ $^
+
+strnumtest: strnumtest.o str.o
+ $(CXX) $(LFLAGS) -o $@ $^
+
+symtest: misc.o symtest.o symtab.o str.o
+ $(CXX) $(LFLAGS) -o $@ $^
+
+tokentest: tokentest.o str.o
+ $(CXX) $(LFLAGS) -o $@ $^
+
+tracetest: tracetest.o trace.o trace_flags.o cprintf.o str.o misc.o omisc.o
+ $(CXX) $(LFLAGS) -o $@ $^
+
+clean:
+ @rm -f *.o *.d *test *~ .#* *.core core
+.PHONY: clean
+
+# C++ Compilation
+%.o: %.cc
+ @echo '$(CXX) $(CCFLAGS) -c $(notdir $<) -o $@'
+ @$(CXX) $(CCFLAGS) -c $< -o $@
+
+# C Compilation
+%.o: %.c
+ @echo '$(CC) $(CCFLAGS) -c $(notdir $<) -o $@'
+ @$(CC) $(CCFLAGS) -c $< -o $@
+
+-include *.d
diff --git a/test/bitvectest.cc b/test/bitvectest.cc
new file mode 100644
index 000000000..5c2a79a4e
--- /dev/null
+++ b/test/bitvectest.cc
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+#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/test/circletest.cc b/test/circletest.cc
new file mode 100644
index 000000000..5123cfc9a
--- /dev/null
+++ b/test/circletest.cc
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#include <fcntl.h>
+#include <iostream.h>
+#include <unistd.h>
+
+#include "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/test/cprintftest.cc b/test/cprintftest.cc
new file mode 100644
index 000000000..87518c3c3
--- /dev/null
+++ b/test/cprintftest.cc
@@ -0,0 +1,164 @@
+/*
+ * 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.
+ */
+
+#include <cstdio>
+#include <iostream>
+#include <list>
+#include <string>
+#include <sstream>
+
+#include "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/test/foo.ini b/test/foo.ini
new file mode 100644
index 000000000..aa4305f12
--- /dev/null
+++ b/test/foo.ini
@@ -0,0 +1,7 @@
+#define JUNK
+[Foo]
+Foo1=89
+Foo2=384
+
+[General]
+Test3=89
diff --git a/test/initest.cc b/test/initest.cc
new file mode 100644
index 000000000..d45e9eaa7
--- /dev/null
+++ b/test/initest.cc
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+
+#include <iostream.h>
+#include <fstream.h>
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+#include "inifile.hh"
+
+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 config;
+
+ progname = argv[0];
+
+ int cpp_options_count = 0;
+ char **cpp_options = new char*[argc * 2];
+ char **cur_opt = cpp_options;
+
+ int ch;
+ while ((ch = getopt(argc, argv, "D:")) != -1) {
+ switch (ch) {
+ case 'D':
+ *cur_opt++ = "-D";
+ *cur_opt++ = optarg;
+ cpp_options_count += 2;
+ break;
+
+ default:
+ usage();
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 1)
+ usage();
+
+ string file = argv[0];
+
+ if (!config.loadCPP(file, cpp_options, cpp_options_count)) {
+ cout << "File not found!\n";
+ exit(1);
+ }
+
+ string value;
+#define FIND(C, E) \
+ if (config.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";
+
+ config.dump();
+
+ return 0;
+}
diff --git a/test/initest.ini b/test/initest.ini
new file mode 100644
index 000000000..ebf2719d8
--- /dev/null
+++ b/test/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/test/lru_test.cc b/test/lru_test.cc
new file mode 100644
index 000000000..b2b1350d0
--- /dev/null
+++ b/test/lru_test.cc
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+#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/test/nmtest.cc b/test/nmtest.cc
new file mode 100644
index 000000000..701f83188
--- /dev/null
+++ b/test/nmtest.cc
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include "ecoff.hh"
+#include "object_file.hh"
+#include "str.hh"
+#include "symtab.hh"
+
+Tick curTick;
+
+int
+main(int argc, char *argv[])
+{
+ EcoffObject obj;
+ if (argc != 3) {
+ cout << "usage: " << argv[0] << " <filename> <symbol>\n";
+ return 1;
+ }
+
+ if (!obj.open(argv[1])) {
+ cout << "file not found\n";
+ return 1;
+ }
+
+ SymbolTable symtab;
+ obj.loadGlobals(&symtab);
+
+ string symbol = argv[2];
+ Addr address;
+
+ if (symbol[0] == '0' && symbol[1] == 'x') {
+ if (to_number(symbol, address) && symtab.findSymbol(address, symbol))
+ cout << "address = 0x" << hex << address
+ << ", symbol = " << symbol << "\n";
+ else
+ cout << "address = 0x" << hex << address << " was not found\n";
+ } else {
+ if (symtab.findAddress(symbol, address))
+ cout << "symbol = " << symbol << ", address = 0x" << hex
+ << address << "\n";
+ else
+ cout << "symbol = " << symbol << " was not found\n";
+ }
+
+ return 0;
+}
diff --git a/test/offtest.cc b/test/offtest.cc
new file mode 100644
index 000000000..6970ecf72
--- /dev/null
+++ b/test/offtest.cc
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+#include <sys/types.h>
+#include <stddef.h>
+#include <stdio.h>
+#include "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/test/paramtest.cc b/test/paramtest.cc
new file mode 100644
index 000000000..343d75b91
--- /dev/null
+++ b/test/paramtest.cc
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+//
+// 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_object.hh"
+#include "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<mem_hierarchy_obj *> memobj;
+ SimObjectVectorParam<mem_hierarchy_obj *> 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 },
+ { "fourty", 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/test/rangetest.cc b/test/rangetest.cc
new file mode 100644
index 000000000..01c69bb26
--- /dev/null
+++ b/test/rangetest.cc
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+#include <iostream>
+#include <string>
+
+#include "range.hh"
+
+
+int
+main()
+{
+ Range<int> r1(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"
+
+ int i1 = 10;
+ int i2 = 0x1001;
+ RANGETEST(i1, < , r1);
+ RANGETEST(i1, <=, r1);
+ RANGETEST(i1, > , r1);
+ RANGETEST(i1, >=, r1);
+ RANGETEST(i1, ==, r1);
+ RANGETEST(i1, !=, r1);
+ RANGETEST(r1, < , i1);
+ RANGETEST(r1, <=, i1);
+ RANGETEST(r1, > , i1);
+ RANGETEST(r1, >=, i1);
+ RANGETEST(r1, ==, i1);
+ RANGETEST(r1, !=, i1);
+
+ RANGETEST(i2, < , r1);
+ RANGETEST(i2, <=, r1);
+ RANGETEST(i2, > , r1);
+ RANGETEST(i2, >=, r1);
+ RANGETEST(i2, ==, r1);
+ RANGETEST(i2, !=, r1);
+ RANGETEST(r1, < , i2);
+ RANGETEST(r1, <=, i2);
+ RANGETEST(r1, > , i2);
+ RANGETEST(r1, >=, i2);
+ RANGETEST(r1, ==, i2);
+ RANGETEST(r1, !=, i2);
+
+ unsigned u1 = 10;
+ unsigned u2 = 0x1001;
+ RANGETEST(u1, < , r2);
+ RANGETEST(u1, <=, r2);
+ RANGETEST(u1, > , r2);
+ RANGETEST(u1, >=, r2);
+ RANGETEST(u1, ==, r2);
+ RANGETEST(u1, !=, r2);
+ RANGETEST(r2, < , u1);
+ RANGETEST(r2, <=, u1);
+ RANGETEST(r2, > , u1);
+ RANGETEST(r2, >=, u1);
+ RANGETEST(r2, ==, u1);
+ RANGETEST(r2, !=, u1);
+
+ RANGETEST(u2, < , r2);
+ RANGETEST(u2, <=, r2);
+ RANGETEST(u2, > , r2);
+ RANGETEST(u2, >=, r2);
+ RANGETEST(u2, ==, r2);
+ RANGETEST(u2, !=, r2);
+ RANGETEST(r2, < , u2);
+ RANGETEST(r2, <=, u2);
+ RANGETEST(r2, > , u2);
+ RANGETEST(r2, >=, u2);
+ RANGETEST(r2, ==, u2);
+ RANGETEST(r2, !=, u2);
+
+ return 0;
+}
diff --git a/test/sized_test.cc b/test/sized_test.cc
new file mode 100644
index 000000000..fe52b7a41
--- /dev/null
+++ b/test/sized_test.cc
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+#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/test/stattest.cc b/test/stattest.cc
new file mode 100644
index 000000000..02f65169a
--- /dev/null
+++ b/test/stattest.cc
@@ -0,0 +1,504 @@
+/*
+ * 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.
+ */
+
+#include <iomanip>
+#include <iostream>
+#include <string>
+#include <unistd.h>
+
+#include "cprintf.hh"
+#include "host.hh"
+#include "misc.hh"
+#include "statistics.hh"
+
+using namespace std;
+using namespace Statistics;
+
+Tick curTick = 0;
+//Tick ticksPerSecond = ULL(2000000000);
+
+Scalar<> s1;
+Scalar<> s2;
+Average<> s3;
+Scalar<Counter, MainBin> s4;
+Vector<Counter, MainBin> s5;
+Distribution<Counter, MainBin> s6;
+Vector<> s7;
+AverageVector<> s8;
+StandardDeviation<> s9;
+AverageDeviation<> s10;
+Scalar<Counter> s11;
+Distribution<> s12;
+VectorDistribution<> s13;
+VectorStandardDeviation<> s14;
+VectorAverageDeviation<> s15;
+Vector2d<> s16;
+
+Formula f1;
+Formula f2;
+Formula f3;
+Formula f4;
+Formula f5;
+Formula f6;
+
+MainBin bin1;
+MainBin bin2;
+
+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 [-v]\n", progname);
+}
+
+int
+main(int argc, char *argv[])
+{
+ char c;
+ progname = argv[0];
+ PrintDescriptions = false;
+ while ((c = getopt(argc, argv, "v")) != -1) {
+ cprintf("c == %c\n", c);
+ switch (c) {
+ case 'v':
+ PrintDescriptions = true;
+ break;
+ default:
+ 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, 2);
+
+ 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(s11)
+ ;
+
+ 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")
+ ;
+
+ 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
+ .name("Formula4")
+ .desc("this is formula 4")
+ ;
+
+ f5
+ .name("Formula5")
+ .desc("this is formula 5")
+ ;
+
+ f6
+ .name("Formula6")
+ .desc("this is formula 6")
+ ;
+
+ check();
+
+ MainBin::activate(bin1);
+
+ f1 = s1 + s2;
+ f2 = (-s1) / (-s2) * -s3 + ULL(100) + s4;
+ f3 = sum(s5) * s7;
+ f4 = functor(testfunc);
+ TestClass testclass;
+ f5 = functor(testclass);
+ f6 += constant(10.0);
+ f6 += s5[3];
+
+ s16[1][0] = 1;
+ s16[0][1] = 3;
+ s16[0][0] = 2;
+ s16[1][1] = 9;
+ s16[1][1] += 9;
+
+ 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);
+
+ MainBin::activate(bin2);
+ 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);
+
+ 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);
+
+ MainBin::activate(bin1);
+ dump(cout);
+ cout << endl << endl;
+
+ MainBin::activate(bin2);
+ dump(cout);
+ cout << endl << endl;
+
+ return 0;
+}
diff --git a/test/strnumtest.cc b/test/strnumtest.cc
new file mode 100644
index 000000000..1e0a6676f
--- /dev/null
+++ b/test/strnumtest.cc
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+#include <iostream.h>
+
+#include <string>
+#include <vector>
+
+#include "str.hh"
+
+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/test/symtest.cc b/test/symtest.cc
new file mode 100644
index 000000000..bc03fc1df
--- /dev/null
+++ b/test/symtest.cc
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+#include <iostream.h>
+
+#include "str.hh"
+#include "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/test/tokentest.cc b/test/tokentest.cc
new file mode 100644
index 000000000..4a4551883
--- /dev/null
+++ b/test/tokentest.cc
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+#include <iostream.h>
+#include <string>
+#include <vector>
+
+#include "str.hh"
+
+int
+main(int argc, char *argv[])
+{
+ 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()) {
+ for (i = 0; i < tokens1.size() - 1; i++)
+ cout << tokens1[i] << "(" << tokens1[i].size() << "), ";
+ cout << tokens1[i] << "(" << tokens1[i].size() << ")\n";
+ }
+
+ cout << "testing with ignore\n";
+ tokenize(tokens2, test, token, true);
+
+ if (tokens2.size()) {
+ for (i = 0; i < tokens2.size() - 1; i++)
+ cout << tokens2[i] << "(" << tokens2[i].size() << "), ";
+ cout << tokens2[i] << "(" << tokens2[i].size() << ")\n";
+ }
+
+ return 0;
+}
diff --git a/test/tracetest.cc b/test/tracetest.cc
new file mode 100644
index 000000000..51236123c
--- /dev/null
+++ b/test/tracetest.cc
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+#include "host.hh"
+#include "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;
+}
diff --git a/util/rundiff b/util/rundiff
new file mode 100644
index 000000000..064e7e136
--- /dev/null
+++ b/util/rundiff
@@ -0,0 +1,511 @@
+#!/usr/bin/perl
+
+# Copyright (c) 2001 Nathan L. Binkert
+# All rights reserved.
+#
+# Permission to redistribute, use, copy, and modify this software
+# without fee is hereby granted, provided that the following
+# conditions are met:
+#
+# 1. This entire notice is included in all source code copies of any
+# software which is or includes a copy or modification of this
+# software.
+# 2. 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.
+#
+
+use Algorithm::Diff qw(diff);
+use vars qw ($opt_C $opt_c $opt_u $opt_U);
+
+$opt_u = "";
+$opt_c = undef;
+
+$diffsize = 2000;
+# After we've read up to a certain point in each file, the number of items
+# we've read from each file will differ by $FLD (could be 0)
+my $File_Length_Difference = 0;
+my $Context_Lines = 9;
+
+$progname = $0;
+if (scalar(@ARGV) != 2) {
+ usage();
+}
+
+my ($filename1, $filename2);
+($filename1, $start1) = parse_filearg($ARGV[0]);
+($filename2, $start2) = parse_filearg($ARGV[1]);
+
+if ($filename1 eq "-" && $filename2 eq "-") {
+ die "Only one of the inputs may be standard in\n";
+}
+
+my ($file1, $file2);
+if ($filename1 eq "-") {
+ $file1 = STDIN;
+} else {
+ open(FILE1, $filename1) || die "can't open $file1: $!\n";
+ $file1 = FILE1;
+}
+
+if ($filename2 eq "-") {
+ $file2 = STDIN;
+} else {
+ open(FILE2, $filename2) || die "can't open $file2: $!\n";
+ $file2 = FILE2;
+}
+
+my $file_offset1 = ffw($file1, $start1);
+my $file_offset2 = ffw($file2, $start2);
+
+$skip_first = 0;
+my (@buf1, @buf2, @printbuf1, @printbuf2);
+
+$Compare_Ahead = 0;
+
+while (!eof($file1) && !eof($file2)) {
+ my $line1 = <$file1>; chomp $line1;
+ my $line2 = <$file2>; chomp $line2;
+ my $printline1 = $line1;
+ my $printline2 = $line2;
+
+ push @buf1, $line1;
+ push @buf2, $line2;
+ push @printbuf1, $printline1;
+ push @printbuf2, $printline2;
+
+# while ($Compare_Ahead < $Context_Lines) {
+# $line1 = @buf1[$Compare_Ahead];
+# $line2 = @buf2[$Compare_Ahead];
+# $line2 =~ s/ *--.*$//;
+# if ($line1 ne $line2) { last; }
+# ++$Compare_Ahead;
+# }
+
+ $line1 = @buf1[$Compare_Ahead];
+ $line2 = @buf2[$Compare_Ahead];
+ $line2 =~ s/ *--.*$//;
+
+ if ($line1 ne $line2) {
+ while (!eof($file1) && scalar(@buf1) < $diffsize) {
+ $line = <$file1>; chomp $line;
+ my $printline = $line;
+
+ push @printbuf1, $printline;
+ push @buf1, $line;
+ }
+
+ while (!eof($file2) && scalar(@buf2) < $diffsize) {
+ $line = <$file2>; chomp $line;
+ my $printline = $line;
+# $line =~ s/ *--.*$//;
+
+ push @printbuf2, $printline;
+ push @buf2, $line;
+ }
+
+ my $diffs = diff(\@buf1, \@buf2);
+
+ next unless @$diffs;
+
+ my @hunklist;
+ my ($hunk,$oldhunk);
+ # Loop over hunks. If a hunk overlaps with the last hunk, join them.
+ # Otherwise, print out the old one.
+ foreach my $piece (@$diffs) {
+ $hunk = new Hunk ($piece, $Context_Lines, scalar(@buf1));
+ next unless $oldhunk;
+
+ if ($hunk->does_overlap($oldhunk)) {
+ $hunk->prepend_hunk($oldhunk);
+ } else {
+ push @hunklist, $oldhunk;
+ }
+ } continue {
+ $oldhunk = $hunk;
+ }
+
+ my $change = 0;
+ while (scalar(@hunklist) && !$change) {
+ $hunk = pop @hunklist;
+ $change = $hunk->{"change"};
+ }
+ push @hunklist, $hunk;
+ $last_start1 = $hunk->{"start1"};
+ $last_start2 = $hunk->{"start2"};
+ $last_end1 = $hunk->{"end1"};
+ $last_end2 = $hunk->{"end2"};
+
+ while (scalar(@hunklist)) {
+ $hunk = shift @hunklist;
+# $hunk->output_diff(\@buf1, \@buf2);
+ $hunk->output_diff(\@printbuf1, \@printbuf2);
+ }
+
+ $last_end1 -= $Context_Lines - 1;
+ $last_end2 -= $Context_Lines - 1;
+ $file_offset1 += $last_end1;
+ $file_offset2 += $last_end2;
+ @printbuf1 = @printbuf1[$last_end1..$#printbuf1];
+ @printbuf2 = @printbuf2[$last_end2..$#printbuf2];
+ @buf1 = @buf1[$last_end1..$#buf1];
+ @buf2 = @buf2[$last_end2..$#buf2];
+ while (scalar(@buf1) > $Context_Lines &&
+ scalar(@buf2) > $Context_Lines) {
+ $foo1 = @buf1[$Context_Lines];
+ $foo2 = @buf2[$Context_Lines];
+ if (scalar($foo1) != scalar($foo2) || $foo1 ne $foo2) { last; }
+ $foo1 = shift @printbuf1;
+ $foo2 = shift @printbuf2;
+ $foo1 = shift @buf1;
+ $foo2 = shift @buf2;
+ ++$file_offset1;
+ ++$file_offset2;
+ }
+ } else {
+ ++$file_offset1;
+ ++$file_offset2;
+ $foo1 = shift @printbuf1;
+ $foo2 = shift @printbuf2;
+ $foo1 = shift @buf1;
+ $foo2 = shift @buf2;
+ }
+}
+
+close $file1;
+close $file2;
+
+sub ffw() {
+ if (scalar(@_) != 2) { die "improper usage of ffw\n"; }
+
+ my $FILE = $_[0];
+ my $start = $_[1];
+ my $count = 0;
+
+ while ($start-- > 0 && !eof($FILE)) {
+ <$FILE>;
+ $count++;
+ }
+
+ if ($start > 0) {die "File too short for ffw amount\n"; }
+ return $count;
+}
+
+sub parse_filearg() {
+ $start = 0;
+ split /:/, @_[0];
+ if (scalar(@_) > 2) { usage(); }
+
+ $file = $_[0];
+ if (scalar(@_) > 1) { $start = $_[1]; }
+
+ return ($file, $start);
+}
+
+sub usage() {
+ printf "usage: $progname <file1>[:start] <file2>[:start]\n";
+ exit 1;
+}
+
+
+# Package Hunk. A Hunk is a group of Blocks which overlap because of the
+# context surrounding each block. (So if we're not using context, every
+# hunk will contain one block.)
+{
+package Hunk;
+
+sub new {
+# Arg1 is output from &LCS::diff (which corresponds to one Block)
+# Arg2 is the number of items (lines, e.g.,) of context around each block
+#
+# This subroutine changes $File_Length_Difference
+#
+# Fields in a Hunk:
+# blocks - a list of Block objects
+# start - index in file 1 where first block of the hunk starts
+# end - index in file 1 where last block of the hunk ends
+#
+# Variables:
+# before_diff - how much longer file 2 is than file 1 due to all hunks
+# until but NOT including this one
+# after_diff - difference due to all hunks including this one
+ my ($class, $piece, $context_items, $maxlen) = @_;
+
+ my $block = new Block ($piece); # this modifies $FLD!
+
+ my $before_diff = $File_Length_Difference; # BEFORE this hunk
+ my $after_diff = $before_diff + $block->{"length_diff"};
+ $File_Length_Difference += $block->{"length_diff"};
+
+ # @remove_array and @insert_array hold the items to insert and remove
+ # Save the start & beginning of each array. If the array doesn't exist
+ # though (e.g., we're only adding items in this block), then figure
+ # out the line number based on the line number of the other file and
+ # the current difference in file lenghts
+ my @remove_array = $block->remove;
+ my @insert_array = $block->insert;
+ my ($a1, $a2, $b1, $b2, $start1, $start2, $end1, $end2, $change);
+ $a1 = @remove_array ? $remove_array[0 ]->{"item_no"} : -1;
+ $a2 = @remove_array ? $remove_array[-1]->{"item_no"} : -1;
+ $b1 = @insert_array ? $insert_array[0 ]->{"item_no"} : -1;
+ $b2 = @insert_array ? $insert_array[-1]->{"item_no"} : -1;
+
+ $start1 = $a1 == -1 ? $b1 - $before_diff : $a1;
+ $end1 = $a2 == -1 ? $b2 - $after_diff : $a2;
+ $start2 = $b1 == -1 ? $a1 + $before_diff : $b1;
+ $end2 = $b2 == -1 ? $a2 + $after_diff : $b2;
+ $change = scalar(@remove_array) && scalar(@insert_array);
+
+ # At first, a hunk will have just one Block in it
+ my $hunk = {
+ "start1" => $start1,
+ "start2" => $start2,
+ "end1" => $end1,
+ "end2" => $end2,
+ "maxlen" => $maxlen,
+ "change" => $change,
+ "blocks" => [$block],
+ };
+ bless $hunk, $class;
+
+ $hunk->flag_context($context_items);
+
+ return $hunk;
+}
+
+# Change the "start" and "end" fields to note that context should be added
+# to this hunk
+sub flag_context {
+ my ($hunk, $context_items) = @_;
+ return unless $context_items; # no context
+
+ # add context before
+ my $start1 = $hunk->{"start1"};
+ my $num_added = $context_items > $start1 ? $start1 : $context_items;
+ $hunk->{"start1"} -= $num_added;
+ $hunk->{"start2"} -= $num_added;
+
+ # context after
+ my $end1 = $hunk->{"end1"};
+ $num_added = ($end1+$context_items > $hunk->{"maxlen"}) ?
+ $hunk->{"maxlen"} - $end1 :
+ $context_items;
+ $hunk->{"end1"} += $num_added;
+ $hunk->{"end2"} += $num_added;
+}
+
+# Is there an overlap between hunk arg0 and old hunk arg1?
+# Note: if end of old hunk is one less than beginning of second, they overlap
+sub does_overlap {
+ my ($hunk, $oldhunk) = @_;
+ return "" unless $oldhunk; # first time through, $oldhunk is empty
+
+ # Do I actually need to test both?
+ return ($hunk->{"start1"} - $oldhunk->{"end1"} <= 1 ||
+ $hunk->{"start2"} - $oldhunk->{"end2"} <= 1);
+}
+
+# Prepend hunk arg1 to hunk arg0
+# Note that arg1 isn't updated! Only arg0 is.
+sub prepend_hunk {
+ my ($hunk, $oldhunk) = @_;
+
+ $hunk->{"start1"} = $oldhunk->{"start1"};
+ $hunk->{"start2"} = $oldhunk->{"start2"};
+
+ unshift (@{$hunk->{"blocks"}}, @{$oldhunk->{"blocks"}});
+}
+
+
+# DIFF OUTPUT ROUTINES. THESE ROUTINES CONTAIN DIFF FORMATTING INFO...
+sub output_diff {
+ if (defined $main::opt_u) {&output_unified_diff(@_)}
+ elsif (defined $main::opt_c) {&output_context_diff(@_)}
+ else {die "unknown diff"}
+}
+
+sub output_unified_diff {
+ my ($hunk, $fileref1, $fileref2) = @_;
+ my @blocklist;
+
+ # Calculate item number range.
+ my $range1 = $hunk->unified_range(1, $file_offset1);
+ my $range2 = $hunk->unified_range(2, $file_offset2);
+ print "@@ -$range1 +$range2 @@\n";
+
+ # Outlist starts containing the hunk of file 1.
+ # Removing an item just means putting a '-' in front of it.
+ # Inserting an item requires getting it from file2 and splicing it in.
+ # We splice in $num_added items. Remove blocks use $num_added because
+ # splicing changed the length of outlist.
+ # We remove $num_removed items. Insert blocks use $num_removed because
+ # their item numbers---corresponding to positions in file *2*--- don't take
+ # removed items into account.
+ my $low = $hunk->{"start1"};
+ my $hi = $hunk->{"end1"};
+ my ($num_added, $num_removed) = (0,0);
+ my @outlist = @$fileref1[$low..$hi];
+ map {s/^/ /} @outlist; # assume it's just context
+
+ foreach my $block (@{$hunk->{"blocks"}}) {
+ foreach my $item ($block->remove) {
+ my $op = $item->{"sign"}; # -
+ my $offset = $item->{"item_no"} - $low + $num_added;
+ $outlist[$offset] =~ s/^ /$op/;
+ $num_removed++;
+ }
+ foreach my $item ($block->insert) {
+ my $op = $item->{"sign"}; # +
+ my $i = $item->{"item_no"};
+ my $offset = $i - $hunk->{"start2"} + $num_removed;
+ splice(@outlist,$offset,0,"$op$$fileref2[$i]");
+ $num_added++;
+ }
+ }
+
+ map {s/$/\n/} @outlist; # add \n's
+ print @outlist;
+
+}
+
+sub output_context_diff {
+ my ($hunk, $fileref1, $fileref2) = @_;
+ my @blocklist;
+
+ print "***************\n";
+ # Calculate item number range.
+ my $range1 = $hunk->context_range(1, $file_offset1);
+ my $range2 = $hunk->context_range(2, $file_offset2);
+
+ # Print out file 1 part for each block in context diff format if there are
+ # any blocks that remove items
+ print "*** $range1 ****\n";
+ my $low = $hunk->{"start1"};
+ my $hi = $hunk->{"end1"};
+ if (@blocklist = grep {$_->remove} @{$hunk->{"blocks"}}) {
+ my @outlist = @$fileref1[$low..$hi];
+ map {s/^/ /} @outlist; # assume it's just context
+ foreach my $block (@blocklist) {
+ my $op = $block->op; # - or !
+ foreach my $item ($block->remove) {
+ $outlist[$item->{"item_no"} - $low] =~ s/^ /$op/;
+ }
+ }
+ map {s/$/\n/} @outlist; # add \n's
+ print @outlist;
+ }
+
+ print "--- $range2 ----\n";
+ $low = $hunk->{"start2"};
+ $hi = $hunk->{"end2"};
+ if (@blocklist = grep {$_->insert} @{$hunk->{"blocks"}}) {
+ my @outlist = @$fileref2[$low..$hi];
+ map {s/^/ /} @outlist; # assume it's just context
+ foreach my $block (@blocklist) {
+ my $op = $block->op; # + or !
+ foreach my $item ($block->insert) {
+ $outlist[$item->{"item_no"} - $low] =~ s/^ /$op/;
+ }
+ }
+ map {s/$/\n/} @outlist; # add \n's
+ print @outlist;
+ }
+}
+
+sub context_range {
+# Generate a range of item numbers to print. Only print 1 number if the range
+# has only one item in it. Otherwise, it's 'start,end'
+ my ($hunk, $flag, $offset) = @_;
+ my ($start, $end) = ($hunk->{"start$flag"},$hunk->{"end$flag"});
+
+ # index from 1, not zero
+ $start += $offset + 1;
+ $end += $offset + 1;
+ my $range = ($start < $end) ? "$start,$end" : $end;
+ return $range;
+}
+
+sub unified_range {
+# Generate a range of item numbers to print for unified diff
+# Print number where block starts, followed by number of lines in the block
+# (don't print number of lines if it's 1)
+ my ($hunk, $flag, $offset) = @_;
+ my ($start, $end) = ($hunk->{"start$flag"},$hunk->{"end$flag"});
+
+ # index from 1, not zero
+ $start += $offset + 1;
+ $end += $offset + 1;
+ my $length = $end - $start + 1;
+ my $first = $length < 2 ? $end : $start; # strange, but correct...
+ my $range = $length== 1 ? $first : "$first,$length";
+ return $range;
+}
+} # end Package Hunk
+
+# Package Block. A block is an operation removing, adding, or changing
+# a group of items. Basically, this is just a list of changes, where each
+# change adds or deletes a single item.
+# (Change could be a separate class, but it didn't seem worth it)
+{
+package Block;
+sub new {
+# Input is a chunk from &Algorithm::LCS::diff
+# Fields in a block:
+# length_diff - how much longer file 2 is than file 1 due to this block
+# Each change has:
+# sign - '+' for insert, '-' for remove
+# item_no - number of the item in the file (e.g., line number)
+# We don't bother storing the text of the item
+#
+ my ($class,$chunk) = @_;
+ my @changes = ();
+
+# This just turns each change into a hash.
+ foreach my $item (@$chunk) {
+ my ($sign, $item_no, $text) = @$item;
+ my $hashref = {"sign" => $sign, "item_no" => $item_no};
+ push @changes, $hashref;
+ }
+
+ my $block = { "changes" => \@changes };
+ bless $block, $class;
+
+ $block->{"length_diff"} = $block->insert - $block->remove;
+ return $block;
+}
+
+
+# LOW LEVEL FUNCTIONS
+sub op {
+# what kind of block is this?
+ my $block = shift;
+ my $insert = $block->insert;
+ my $remove = $block->remove;
+
+ $remove && $insert and return '!';
+ $remove and return '-';
+ $insert and return '+';
+ warn "unknown block type";
+ return '^'; # context block
+}
+
+# Returns a list of the changes in this block that remove items
+# (or the number of removals if called in scalar context)
+sub remove { return grep {$_->{"sign"} eq '-'} @{shift->{"changes"}}; }
+
+# Returns a list of the changes in this block that insert items
+sub insert { return grep {$_->{"sign"} eq '+'} @{shift->{"changes"}}; }
+
+} # end of package Block
diff --git a/util/tap/Makefile b/util/tap/Makefile
new file mode 100644
index 000000000..c7078158b
--- /dev/null
+++ b/util/tap/Makefile
@@ -0,0 +1,67 @@
+# 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.
+#
+# Authors: Nathan Binkert
+
+# $Id$
+
+CC= gcc
+CXX= g++
+
+CURDIR?= $(shell /bin/pwd)
+SRCDIR?= .
+
+BASE_SRCDIR?= $(SRCDIR)/../../base
+SIM_SRCDIR?= $(SRCDIR)/../../sim
+
+vpath % $(BASE_SRCDIR)
+vpath % $(SIM_SRCDIR)
+
+INCLDIRS= -I. -I$(BASE_SRCDIR) -I$(SIM_SRCDIR) -I- -I/usr/local/include
+CCFLAGS= -g -O0 -MMD $(INCLDIRS)
+
+default: m5tap
+
+m5tap: tap.o cprintf.o
+ $(CXX) $(LFLAGS) -o $@ $^ -lpcap -L/usr/local/lib -ldnet
+
+
+clean:
+ @rm -f m5tap *.o *.d *~ .#*
+
+.PHONY: clean
+
+# C++ Compilation
+%.o: %.cc
+ @echo '$(CXX) $(CCFLAGS) -c $(notdir $<) -o $@'
+ @$(CXX) $(CCFLAGS) -c $< -o $@
+
+# C Compilation
+%.o: %.c
+ @echo '$(CC) $(CCFLAGS) -c $(notdir $<) -o $@'
+ @$(CC) $(CCFLAGS) -c $< -o $@
+
+-include *.d
diff --git a/util/tap/tap.cc b/util/tap/tap.cc
new file mode 100644
index 000000000..0ef49dfd7
--- /dev/null
+++ b/util/tap/tap.cc
@@ -0,0 +1,415 @@
+/*
+ * 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.
+ */
+
+extern "C" {
+#include <pcap.h>
+}
+
+#include <dnet.h>
+
+#include <arpa/inet.h>
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <netdb.h>
+#include <poll.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <list>
+#include <string>
+
+#include "cprintf.hh"
+
+#define panic(arg...) \
+ do { cprintf("Panic: " arg); exit(1); } while (0)
+
+char *program = "ethertap";
+void
+usage()
+{
+ cprintf(
+ "usage: \n"
+ "\t%s [-b bufsize] [-d] [-f filter] [-p port] [-v] <device> <host>\n"
+ "\t%s [-b bufsize] [-d] [-f filter] [-l] [-p port] [-v] <device>\n",
+ program, program);
+ exit(2);
+}
+
+int verbose = 0;
+#define DPRINTF(args...) do { \
+ if (verbose > 1) \
+ cprintf(args); \
+} while (0)
+
+#define DDUMP(args...) do { \
+ if (verbose > 2) \
+ dump((const u_char *)args); \
+} while (0)
+
+void
+dump(const u_char *data, int len)
+{
+ int c, i, j;
+
+ for (i = 0; i < len; i += 16) {
+ cprintf("%08x ", i);
+ c = len - i;
+ if (c > 16) c = 16;
+
+ for (j = 0; j < c; j++) {
+ cprintf("%02x ", data[i + j] & 0xff);
+ if ((j & 0xf) == 7 && j > 0)
+ cprintf(" ");
+ }
+
+ for (; j < 16; j++)
+ cprintf(" ");
+ cprintf(" ");
+
+ for (j = 0; j < c; j++) {
+ int ch = data[i + j] & 0x7f;
+ cprintf("%c", (char)(isprint(ch) ? ch : ' '));
+ }
+
+ cprintf("\n");
+
+ if (c < 16)
+ break;
+ }
+}
+
+bool quit = false;
+void
+quit_now(int sigtype)
+{
+ DPRINTF("User requested exit\n");
+ quit = true;
+}
+
+
+int
+Socket(int reuse)
+{
+ int fd = ::socket(PF_INET, SOCK_STREAM, 0);
+ if (fd < 0)
+ panic("Can't create socket!");
+
+ if (reuse) {
+ int i = 1;
+ if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&i,
+ sizeof(i)) < 0)
+ panic("setsockopt() SO_REUSEADDR failed!");
+ }
+
+ return fd;
+}
+
+void
+Listen(int fd, int port)
+{
+ 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 == -1)
+ panic("bind() failed!");
+
+ if (::listen(fd, 1) == -1)
+ panic("listen() failed!");
+}
+
+// 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
+Accept(int fd, bool nodelay)
+{
+ struct sockaddr_in sockaddr;
+ socklen_t slen = sizeof (sockaddr);
+ int sfd = ::accept(fd, (struct sockaddr *)&sockaddr, &slen);
+ if (sfd == -1)
+ panic("accept() failed!");
+
+ if (nodelay) {
+ int i = 1;
+ ::setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (char *)&i, sizeof(i));
+ }
+ return sfd;
+}
+
+void
+Connect(int fd, const string &host, int port)
+{
+ struct sockaddr_in sockaddr;
+ if (::inet_aton(host.c_str(), &sockaddr.sin_addr) == 0) {
+ struct hostent *hp;
+ hp = ::gethostbyname(host.c_str());
+ if (!hp)
+ panic("Host %s not found\n", host);
+
+ sockaddr.sin_family = hp->h_addrtype;
+ memcpy(&sockaddr.sin_addr, hp->h_addr, hp->h_length);
+ }
+
+ sockaddr.sin_port = htons(port);
+ if (::connect(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) != 0)
+ panic("could not connect to %s on port %d", host, port);
+
+ DPRINTF("connected to %s on port %d\n", host, port);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int port = 3500;
+ int bufsize = 2000;
+ bool listening = false;
+ char *device = NULL;
+ char *filter = "";
+ char c;
+ int daemon = false;
+ string host;
+
+ program = basename(argv[0]);
+
+ while((c = getopt(argc, argv, "b:df:lp:v")) != -1) {
+ switch (c) {
+ case 'b':
+ bufsize = atoi(optarg);
+ break;
+ case 'd':
+ daemon = true;
+ break;
+ case 'f':
+ filter = optarg;
+ break;
+ case 'l':
+ listening = true;
+ break;
+ case 'p':
+ port = atoi(optarg);
+ break;
+ case 'v':
+ verbose++;
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+
+ signal(SIGINT, quit_now);
+ signal(SIGTERM, quit_now);
+ signal(SIGHUP, quit_now);
+
+ if (daemon) {
+ verbose = 0;
+ switch(fork()) {
+ case -1:
+ panic("Fork failed\n");
+ case 0:
+ break;
+ default:
+ exit(0);
+ }
+ }
+
+ char *buffer = new char[bufsize];
+ argc -= optind;
+ argv += optind;
+
+ if (argc-- == 0)
+ usage();
+
+ device = *argv++;
+
+ if (listening) {
+ if (argc)
+ usage();
+ } else {
+ if (argc != 1)
+ usage();
+
+ host = *argv;
+ }
+
+ char errbuf[PCAP_ERRBUF_SIZE];
+ pcap_t *pcap = pcap_open_live(device, 1500, 1, -1, errbuf);
+ if (pcap == NULL)
+ panic("pcap_open_live failed: %s\n", errbuf);
+
+ bpf_program program;
+ bpf_u_int32 localnet, netmask;
+ if (!pcap_lookupnet(device, &localnet, &netmask, errbuf))
+ panic("pcap_lookupnet failed: %s\n", errbuf);
+
+ if (pcap_compile(pcap, &program, filter, 1, netmask) == -1)
+ panic("pcap_compile failed, invalid filter:\n%s\n", filter);
+
+ if (pcap_setfilter(pcap, &program) == -1)
+ panic("pcap_setfilter failed\n");
+
+ eth_t *ethernet = eth_open(device);
+
+ pollfd pfds[3];
+ pfds[0].fd = Socket(true);
+ pfds[0].events = POLLIN;
+ pfds[0].revents = 0;
+
+ if (listening)
+ Listen(pfds[0].fd, port);
+ else
+ Connect(pfds[0].fd, host, port);
+
+ pfds[1].fd = pcap_fileno(pcap);
+ pfds[1].events = POLLIN;
+ pfds[1].revents = 0;
+
+ pfds[2].fd = 0;
+ pfds[2].events = POLLIN|POLLERR;
+ pfds[2].revents = 0;
+
+ pollfd *listen_pfd = listening ? &pfds[0] : NULL;
+ pollfd *tap_pfd = &pfds[1];
+ pollfd *client_pfd = listening ? NULL : &pfds[0];
+ int npfds = 2;
+
+ int32_t buffer_offset = 0;
+ int32_t data_len = 0;
+
+ while (!quit) {
+ int ret = ::poll(pfds, npfds, INFTIM);
+ if (ret < 0)
+ continue;
+
+ if (listen_pfd && listen_pfd->revents) {
+ if (listen_pfd->revents & POLLIN) {
+ int fd = Accept(listen_pfd->fd, false);
+ if (client_pfd) {
+ DPRINTF("Connection rejected\n");
+ close(fd);
+ } else {
+ DPRINTF("Connection accepted\n");
+ client_pfd = &pfds[2];
+ client_pfd->fd = fd;
+ npfds++;
+ }
+ }
+ listen_pfd->revents = 0;
+ }
+
+ if (tap_pfd && tap_pfd->revents) {
+ if (tap_pfd->revents & POLLIN) {
+ pcap_pkthdr hdr;
+ const u_char *data = pcap_next(pcap, &hdr);
+ if (data && client_pfd) {
+ DPRINTF("Received packet from ethernet len=%d\n", hdr.len);
+ DDUMP(data, hdr.len);
+ u_int32_t len = htonl(hdr.len);
+ write(client_pfd->fd, &len, sizeof(len));
+ write(client_pfd->fd, data, hdr.len);
+ }
+ }
+
+ tap_pfd->revents = 0;
+ }
+
+ if (client_pfd && client_pfd->revents) {
+ if (client_pfd->revents & POLLIN) {
+ if (buffer_offset < data_len + sizeof(u_int32_t)) {
+ int len = read(client_pfd->fd, buffer + buffer_offset,
+ bufsize - buffer_offset);
+
+ if (len <= 0) {
+ perror("read");
+ goto error;
+ }
+
+ buffer_offset += len;
+ if (data_len == 0)
+ data_len = ntohl(*(u_int32_t *)buffer);
+
+ DPRINTF("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)) {
+ char *data = buffer + sizeof(u_int32_t);
+ eth_send(ethernet, data, data_len);
+ DPRINTF("Sent packet to ethernet len = %d\n", data_len);
+ DDUMP(data, data_len);
+
+ buffer_offset -= data_len + sizeof(u_int32_t);
+ if (buffer_offset > 0 && data_len > 0) {
+ memmove(buffer, data + data_len, buffer_offset);
+ data_len = ntohl(*(u_int32_t *)buffer);
+ } else
+ data_len = 0;
+ }
+ }
+
+ if (client_pfd->revents & POLLERR) {
+ error:
+ DPRINTF("Error on client socket\n");
+ close(client_pfd->fd);
+ client_pfd = NULL;
+
+ if (listening)
+ npfds--;
+ else
+ quit = true;
+ }
+
+ if (client_pfd)
+ client_pfd->revents = 0;
+ }
+
+ }
+
+ delete [] buffer;
+ pcap_close(pcap);
+ eth_close(ethernet);
+ if(listen_pfd)
+ close(listen_pfd->fd);
+
+ if (client_pfd)
+ close(client_pfd->fd);
+
+ return 0;
+}
diff --git a/util/term/Makefile b/util/term/Makefile
new file mode 100644
index 000000000..39e396687
--- /dev/null
+++ b/util/term/Makefile
@@ -0,0 +1,45 @@
+# 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.
+#
+# Authors: Nathan Binkert
+
+# $Id$
+
+CC= gcc
+CCFLAGS= -g -O0
+
+default: m5term
+
+m5term: term.c
+ $(CC) $(LFLAGS) -o $@ $^
+
+install: m5term
+ $(SUDO) install -o root -m 555 m5term /usr/local/bin
+
+clean:
+ @rm -f m5term *~ .#*
+
+.PHONY: clean
diff --git a/util/term/term.c b/util/term/term.c
new file mode 100644
index 000000000..d445b4d37
--- /dev/null
+++ b/util/term/term.c
@@ -0,0 +1,312 @@
+/* $Id$ */
+/* $OpenBSD: netcat.c,v 1.57 2002/12/30 18:00:18 stevesk Exp $ */
+/*
+ * Copyright (c) 2001 Eric Jackson <ericj@monkey.org>
+ *
+ * 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. 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.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/termios.h>
+#include <sys/time.h>
+#include <sys/un.h>
+
+#include <netinet/in.h>
+#include <arpa/telnet.h>
+
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <poll.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+ssize_t atomicio(ssize_t (*)(), int, void *, size_t);
+void readwrite(int);
+int remote_connect(char *, char *, struct addrinfo);
+
+struct termios saved_ios;
+void raw_term();
+void restore_term();
+
+char progname[256];
+void usage(int);
+
+int
+main(int argc, char *argv[])
+{
+ int ch, s, ret;
+ char *host, *port, *endp;
+ struct addrinfo hints;
+ socklen_t len;
+
+ ret = 1;
+ s = 0;
+ host = NULL;
+ port = NULL;
+ endp = NULL;
+
+ strncpy(progname, argv[0], sizeof progname);
+
+ /* Cruft to make sure options are clean, and used properly. */
+ if (argc != 3 || !argv[1] || !argv[2])
+ usage(1);
+
+ host = argv[1];
+ port = argv[2];
+
+
+ if (!isatty(STDIN_FILENO))
+ errx(1, "not attached to a terminal");
+
+ raw_term();
+
+ /* Initialize addrinfo structure */
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+
+ s = remote_connect(host, port, hints);
+ ret = 0;
+ readwrite(s);
+
+ if (s)
+ close(s);
+
+ exit(ret);
+}
+
+/*
+ * remote_connect()
+ * Return's a socket connected to a remote host. Properly bind's to a local
+ * port or source address if needed. Return's -1 on failure.
+ */
+int
+remote_connect(char *host, char *port, struct addrinfo hints)
+{
+ struct addrinfo *res, *res0;
+ int s, error;
+
+ if ((error = getaddrinfo(host, port, &hints, &res)))
+ errx(1, "getaddrinfo: %s", gai_strerror(error));
+
+ res0 = res;
+ do {
+ if ((s = socket(res0->ai_family, res0->ai_socktype,
+ res0->ai_protocol)) < 0)
+ continue;
+
+ if (connect(s, res0->ai_addr, res0->ai_addrlen) == 0)
+ break;
+
+ close(s);
+ s = -1;
+ } while ((res0 = res0->ai_next) != NULL);
+
+ freeaddrinfo(res);
+
+ return (s);
+}
+
+/*
+ * readwrite()
+ * Loop that polls on the network file descriptor and stdin.
+ */
+void
+readwrite(int nfd)
+{
+ struct pollfd pfd[2];
+ char buf[BUFSIZ];
+ int wfd = fileno(stdin), n, ret;
+ int lfd = fileno(stdout);
+ int escape = 0;
+
+ /* Setup Network FD */
+ pfd[0].fd = nfd;
+ pfd[0].events = POLLIN;
+
+ /* Setup STDIN FD */
+ pfd[1].fd = wfd;
+ pfd[1].events = POLLIN;
+
+ while (pfd[0].fd != -1) {
+ if ((n = poll(pfd, 2, -1)) < 0) {
+ close(nfd);
+ err(1, "Polling Error");
+ }
+
+ if (n == 0)
+ return;
+
+ if (pfd[0].revents & POLLIN) {
+ if ((n = read(nfd, buf, sizeof(buf))) < 0)
+ return;
+ else if (n == 0) {
+ shutdown(nfd, SHUT_RD);
+ pfd[0].fd = -1;
+ pfd[0].events = 0;
+ } else {
+ if ((ret = atomicio(write, lfd, buf, n)) != n)
+ return;
+ }
+ }
+
+ if (pfd[1].revents & POLLIN) {
+ if ((n = read(wfd, buf, sizeof(buf))) < 0)
+ return;
+ else if (n == 0) {
+ shutdown(nfd, SHUT_WR);
+ pfd[1].fd = -1;
+ pfd[1].events = 0;
+ } else {
+ if (escape) {
+ char buf2[] = "~";
+ if (*buf == '.') {
+ printf("quit!\n");
+ return;
+ }
+ escape = 0;
+ if (*buf != '~' &&
+ (ret = atomicio(write, nfd, buf2, 1)) != n)
+ return;
+ } else {
+ escape = (*buf == '~');
+ if (escape)
+ continue;
+ }
+
+ if((ret = atomicio(write, nfd, buf, n)) != n)
+ return;
+ }
+ }
+ }
+}
+
+void
+usage(int ret)
+{
+ fprintf(stderr, "usage: %s hostname port\n", progname);
+ if (ret)
+ exit(1);
+}
+
+/*
+ * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved.
+ * 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.
+ *
+ * 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.
+ */
+
+/*
+ * ensure all of data on socket comes through. f==read || f==write
+ */
+ssize_t
+atomicio(ssize_t (*f) (), int fd, void *_s, size_t n)
+{
+ char *s = _s;
+ ssize_t res, pos = 0;
+
+ while (n > pos) {
+ res = (f) (fd, s + pos, n - pos);
+ switch (res) {
+ case -1:
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ case 0:
+ return (res);
+ default:
+ pos += res;
+ }
+ }
+ return (pos);
+}
+
+/*
+ * Copyright (c) 2003 Nathan L. Binkert <binkertn@umich.edu>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+void
+raw_term()
+{
+ struct termios ios;
+
+ if (tcgetattr(STDIN_FILENO, &ios) < 0)
+ errx(1, "tcgetagttr\n");
+
+ memcpy(&saved_ios, &ios, sizeof(struct termios));
+
+ ios.c_iflag &= ~(ISTRIP|ICRNL|IGNCR|ICRNL|IXOFF|IXON);
+ ios.c_oflag &= ~(OPOST);
+ ios.c_oflag &= (ONLCR);
+ ios.c_lflag &= ~(ISIG|ICANON|ECHO);
+ ios.c_cc[VMIN] = 1;
+ ios.c_cc[VTIME] = 0;
+
+ if (tcsetattr(STDIN_FILENO, TCSANOW, &ios) < 0)
+ errx(1, "tcsetattr\n");
+
+ atexit(restore_term);
+}
+
+void
+restore_term()
+{
+ tcsetattr(STDIN_FILENO, TCSANOW, &saved_ios);
+}