diff options
author | Stan Shebs <shebs@codesourcery.com> | 1999-04-16 01:35:26 +0000 |
---|---|---|
committer | Stan Shebs <shebs@codesourcery.com> | 1999-04-16 01:35:26 +0000 |
commit | c906108c21474dfb4ed285bcc0ac6fe02cd400cc (patch) | |
tree | a0015aa5cedc19ccbab307251353a41722a3ae13 /sim/common | |
parent | cd946cff9ede3f30935803403f06f6ed30cad136 (diff) | |
download | gdb-c906108c21474dfb4ed285bcc0ac6fe02cd400cc.zip gdb-c906108c21474dfb4ed285bcc0ac6fe02cd400cc.tar.gz gdb-c906108c21474dfb4ed285bcc0ac6fe02cd400cc.tar.bz2 |
Initial creation of sourceware repositorygdb-4_18-branchpoint
Diffstat (limited to 'sim/common')
119 files changed, 46267 insertions, 0 deletions
diff --git a/sim/common/ChangeLog b/sim/common/ChangeLog new file mode 100644 index 0000000..bde0710 --- /dev/null +++ b/sim/common/ChangeLog @@ -0,0 +1,4005 @@ +1999-02-09 Doug Evans <devans@casey.cygnus.com> + + * Make-common.in (CGEN_READ_SCM): Renamed from CGEN_MAIN_SCM. + (CGEN_DESC_SCM): New variable. + (cgen-desc): New rule. + * cgen-cpu.h (CGEN_DISASSEMBLER): New type. + (CGEN_CPU): Member opcode renamed to cpu_desc. + New members get_idata,disassembler. + * cgen-defs.h (CGEN_INSN_VIRTUAL_P): CGEN_INSN_ATTR renamed to + CGEN_INSN_ATTR_VALUE. + (CGEN_STATE): Delete member opcode_table. + (sim_disassemble_insn): Delete decl. + * cgen-engine.h (struct insn_sem): Moved to here from <cpu>-decode.c. + (struct idesc): Moved to here from <cpu>-decode.h. + * cgen-run.c (prime_cpu): Call prepare_run callback. + * cgen-trace.h (SFILE): New type. + (sim_disasm_sprintf): Declare. + (sim_disasm_read_memory,sim_disasm_perror_memory): Declare. + (sim_cgen_disassemble_insn): Declare. + * cgen-trace.c: Include errno.h,dis-asm.h. Don't include cpu-opc.h. + (insn_fields): Delete. + (trace_insn_fini): STATE_OPCODE_TABLE (sd) replaced with + CPU_CPU_DESC (cpu). + (trace_insn): Call CPU_DISASSEMBLER hook. + (sim_disasm_sprintf): New function. + (sim_disasm_read_memory): New function. + (sim_disasm_perror_memory): New function. + (sim_cgen_disassemble_insn): New function. + * cgen-utils.c: Don't include cpu-opc.h. + (virtual_insn_entries): New static local. + (cgen_virtual_insn_table): Renamed from cgen_virtual_opcode_table. + (cgen_insn_name): Rewrite. + (disasm_sprintf,sim_disassemble_insn): Moved to cgen-trace.c. + * cgen.sh (desc): New file generator handler. + * genmloop.sh: -parallel changed to -parallel-read/-parallel-write. + Define WITH_PARALLEL_READ/WITH_PARALLEL_WRITE appropriately. + Don't include cpu-opc.h,cpu-sim.h. + * sim-model.c (model_set): Delete SIM_DESC arg. + (sim_model_set): Update. + * sim-model.h (MACH): New member prepare_run. + +1999-01-28 Frank Ch. Eigler <fche@cygnus.com> + + * sim-memopt.c (memory_option_handler): Avoid memset() calls + if redundant with allocator functions. + +Wed Jan 27 17:19:09 1999 Doug Evans <devans@canuck.cygnus.com> + + * cgen-engine.h (EXTRACT_LSB0_{INT,UINT}): Fix. + + * sim-profile.h: Make like sim-trace.h. + (PROFILE_USEFUL_MASK): New macro. + * sim-profile.c (profile_options): Make like trace_options, allow + optional on|off arg where applicable. + (set_profile_option_mask): New function. + (sim_profile_set_option): New function. + (profile_option_handler): Simplify. + Have -p only enable selected things, not everything. + Add missing break to OPTION_PROFILE_PC_RANGE. + * cgen-scache.c (scache_options): Allow optional on|off arg to + --profile-scache. + (scache_option_handler): Use sim_profile_set_option. + +1999-01-26 Frank Ch. Eigler <fche@cygnus.com> + + * sim-memopt.c (memory_options): Add MEMORY_FILL option. + (memory_option_handler): Implement MEMORY_FILL option. Make + MEMORY_CLEAR an alias for MEMORY_FILL=0. + (parse_ulong_value): New function. + (do_memopt_add): Allocate all buffers. Optionally fill them. + +1999-01-15 Richard Henderson <rth@cygnus.com> + + * hw-events.c (hw_event_queue_schedule): _vtracef takes a + va_list, not an integer. + * sim-events.c (sim_events_schedule): Likewise. + + * sim-types.h (UNSIGNED32, UNSIGNED64): Properly cast to + the appropriate type. + +1999-01-14 Doug Evans <devans@casey.cygnus.com> + + * cgen-defs.h (PCADDR,CIA): Define in terms of IADDR. + (sim_disassemble_insn): Update prototype. + (sim_engine_invalid_insn): Ditto. + * cgen-engine.h (SEMANTIC_FN): Add !WITH_SCACHE version. + (SEM_BRANCH_INIT): PCADDR->IADDR. + (SEM_NBRANCH_FINI): New macro for !WITH_SCACHE case. + * cgen-scache.c (scache_lookup,scache_lookup_or_alloc): PCADDR->IADDR. + * cgen-scache.h (*): Ditto. + * cgen-trace.c (*): Ditto. + * cgen-trace.h (*): Ditto. + * cgen-utils.c (*): Ditto. + * cgen-types.h (integer modes): Use signedNN/unsignedNN types. + (insn_t): Delete. + * genmloop.sh (@cpu@_fill_argbuf): Add !WITH_SCACHE support. + (simple engine framework): Rewrite. + * sim-module.c (modules): Install model module sooner (and in + particular before the profile module). + +1999-01-12 Doug Evans <devans@casey.cygnus.com> + + * sim-model.h (sim_mach_lookup_bfd_name): Add prototype. + * sim-model.c (sim_mach_lookup_bfd_name): New function. + (sim_model_init): Call it. + + * cgen-trace.c (trace_insn): Pass pc to trace_prefix for virtual insns. + +1999-01-05 Doug Evans <devans@casey.cygnus.com> + + * Make-common.in (CGEN_INCLUDE_DEPS): Add cgen-defs.h, cgen-engine.h. + (CGEN_MAIN_SCM): Add rtx-funcs.scm. + (cgen-arch): Pass $(mach) to cgen.sh. + * cgen-engine.h (SEM_BRANCH_FINI): New arg pcvar, all uses updated. + (SEM_BRANCH_INIT_EXTRACT): New macro. + (SEM_BRANCH_INIT): Add taken_p. + (TARGET_SEM_BRANCH_FINI): Provide default definition. + (SEM_BRANCH_FINI): Use it. + (SEM_INSN): Update. + * cgen-run.c (sim_resume): Handle tracing of last insn. + * cgen-scache.h (WITH_SCACHE): Define as 0 if not defined. + * cgen-trace.c (current_abuf): New static global. + (trace_insn_init): Initialize it. + (trace_insn_fini): Use it. + (trace_insn): Set it. + * cgen.sh (arch case): Pass -m ${mach} to cgen. + * genmloop.sh (@cpu@_emit_before): Only define if WITH_SCACHE_PBB. + (@cpu@_emit_after): Ditto. + (simple @cpu@_engine_run_full): New local `pc'. Initialize semantic + labels if WITH_SEM_SWITCH_FULL. + * sim-model.c: Include bfd.h. + (sim_model_init): New function. + (sim_model_install): Record init fn. + * sim-model.h (MACH): New member bfd_name. + * sim-module.c (modules): Initialize model before scache. + +1998-12-24 Frank Ch. Eigler <fche@cygnus.com> + + * dv-sockser.c (DEFAULT_TIMEOUT): Increase to 1 ms. + + * nrun.c (main): Remain in simulation loop for traps and + exceptions when in operating environment mode. + (ui_loop_hook): New stub hook for standalone use. + * sim-events.c (sim_events_process): Call ui_loop_hook + periodically on CYGWIN host. + + * sim-reason.c (sim_stop_reason): Return host signal numbers + to gdb on sim_stopped and sim_signalled cases. + * sim-engine.c (sim_engine_halt): Call SIM_CPU_EXCEPTION_SUSPEND + hook just before longjmp. + * sim-resume.c (sim_resume): Call SIM_CPU_EXCEPTION_RESUME + hook just before sim_engine_run. + + * sim-n-core.h (sim_core_trace_M): Allay const warning. + * sim-trace.h (trace_generic): Ditto. + * sim-trace.c (trace_generic): Ditto. + +1998-12-14 Doug Evans <devans@casey.cygnus.com> + + * Make-common.in (SIM_MAIN_DEPS): New var. + (CGEN_MAIN_CPU_DEPS): New var. + * aclocal.m4: Add --enable-cgen-maint option. + * cgen-mem.h (GETMEM*): New arg `pc'. Pass to sim_core routine. + (SETMEM*): Ditto. + (GETIMEM*): Pass pc value to sim_core routine. + +Fri Dec 11 16:58:36 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * hw-handles.c (hw_handle_add_ihandle, hw_handle_add_phandle): + Compare with ZERO not NULL. + +Thu Dec 10 14:14:39 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * hw-properties.c, hw-instances.c, hw-tree.c: Include + "sim-assert.h". + +1998-12-09 Doug Evans <devans@casey.cygnus.com> + + * sim-arange.c: Include libiberty.h, and stdlib.h if present. + * sim-trace.c: Include stdlib.h if present. + * dv-sockser.c: Include unistd.h if present. + (dv_sockser_init): Add missing arg to call to sim_io_eprintf. + * cgen-scache.c (scache_flush): Delete unused locals i,sc. + +1998-12-08 James E Wilson <wilson@wilson-pc.cygnus.com> + + * gennltvals.sh: Add i960. + * nltvals.def: Rebuild. + +1998-12-04 Doug Evans <devans@casey.cygnus.com> + + * cgen-defs.h: New file, old cgen-sim.h. + * cgen-sim.h: Simple header that includes others. + * sim-arange.c: New file. + * sim-arange.h: New file. + * sim-basics.h: Include it. + * Make-common.in (SIM_NEW_COMMON_OBJS): Add sim-arange.o. + (sim-arange.o): Add rule for. + * sim-cpu.h (sim_cpu_msg_prefix): Add prototype. + (sim_io_eprintf_cpu): Add prototype. + * sim-inline.h (HAVE_INLINE): Define if GNUC. + (INLINE2): New macro. + (EXTERN_INLINE): New macro. + * sim-module.c (sim_post_argv_init): Initialize cpu backlink + before calling module init fns. + * sim-profile.c (OPTION_PROFILE_*): Move into enum. + (profile_init): New function. + (profile_options): New option --profile-range. + (profile_option_handler): Handle --profile-range. + (profile_print_insn): Qualify address range specific section titles. + (profile_print_addr_ranges): New function. + (profile_info): Print address ranges if specified. + (profile_install): Set profile_init init fn. + * sim-profile.h (PROFILE_DATA): New member `range'. + * sim-trace.c (trace_init): New function. + (trace_options): New option --trace-range. + (trace_option_handler): Handle --trace-range. + (trace_install): Set trace_init init fn. + * sim-trace.h (TRACE_DATA): New member `range'. + * sim-utils.c (sim_cpu_msg_prefix): New function. + (sim_io_eprintf_cpu): New function. + * cgen-engine.h (PC_IN_TRACE_RANGE_P): New macro. + (PC_IN_PROFILE_RANGE_P): New macro. + * cgen-trace.c (trace_insn_init): Set current_insn to NULL. + (trace_insn_fini): New arg abuf. All callers updated. + Exit early if trace_insn not called. Check ARGBUF_PROFILE_P before + printing cycle counts. + * cgen-trace.h (trace_insn_fini): Update prototype. + (TRACE_RESULT_P): New macro. + (TRACE_INSN_INIT,TRACE_INSN_FINI): New arg abuf. All callers updated. + (TRACE_INSN): Check ARGBUF_TRACE_P. + (TRACE_EXTRACT,TRACE_RESULT): New arg abuf. All callers updated. + * cgen-types.h (SIM_INLINE): Delete. + (SIM_HAVE_MODEL,SIM_HAVE_ADDR_RANGE): Define. + * cgen-utils.c: Don't include cgen-engine.h + * genmloop.sh (@cpu@_fill_argbuf): New function. + (@cpu@_fill_argbuf_tp): New function. + (@cpu@_emit_before,@cpu@_emit_after): New functions. + (@cpu@_pbb_begin): Prefix cti_sc,insn_count with '_'. + (SET_CTI_VPC,SET_INSN_COUNT): Update. + (@cpu@_pbb_before): Check ARGBUF_PROFILE_P before calling + doing profiling. Update call to TRACE_INSN_INIT,TRACE_INSN_FINI. + (@cpu@_pbb_after): Check ARGBUF_PROFILE_P before calling + doing profiling. Update call to TRACE_INSN_FINI. + + * sim-memopt.c (sim_memory_uninstall): Result type is `void'. + +1998-12-03 Frank Ch. Eigler <fche@cygnus.com> + + * sim-memopt.c (sim_memory_uninstall): Deallocate all memory + regions. + +1998-12-01 Doug Evans <devans@casey.cygnus.com> + + * sim-inline.c (SIM_INLINE_P): Fix typo. + +1998-11-30 Doug Evans <devans@casey.cygnus.com> + + * cgen-utils.c (cgen_virtual_opcode_table): Update. + +Tue Nov 24 18:40:03 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * gennltvals.sh: Add v850 and d10v. Sort alphabetically. + * nltvals.def: Re-generate. + +Mon Nov 23 13:28:38 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-core.c (reverse_n, sim_core_uninstall, sim_core_init, + sim_core_map_attach, sim_core_map_detach, next_event_queue, + new_sim_core_mapping): Only define when EXTERN_SIM_CORE_P, pacify + GCC. + * sim-events.c (sim_events_uninstall, sim_events_suspend, + sim_events_resume, sim_events_zalloc, insert_sim_event): Ditto. + +1998-11-22 Doug Evans <devans@tobor.to.cygnus.com> + + * genmloop.sh (${cpu}_pbb_chain): Watch for Ctrl-C's. + (${cpu}_pbb_cti_chain): Ditto. + +1998-11-18 Doug Evans <devans@casey.cygnus.com> + + * Make-common.in (cgen-utils.o): Depend on cgen-engine.h. + (CGEN_ARCH_SCM): New variable. + * cgen-engine.h (EXTRACT_[ML]SB0_{INT,UINT}): New macros. + (EXTRACT_INT,EXTRACT_UINT): New macros. + (SEM_SEM_ARG): New macro. + (SEM_NEXT_VPC): New arg `pc'. + * cgen-sim.h (EXTRACT_SIGNED,EXTRACT_UNSIGNED): Delete. + (sim_disassemble_insn): Update prototype. + * cgen-trace.c (current_insn,insn_fields): New static locals. + (trace_insn): Set them. + * cgen-utils.scm: #include cgen-engine.h. + (sim_disassemble_insn): New arg insn_fields. + Handle variable length insns. + * genmloop.sh: Only emit pbb decls if -pbb. + (${cpu}_scache_lookup): New arg `vpc'. + (scache support): Fetch pc before entering loop. + + * gennltvals.sh: Add fr30 support. + * nltvals.def: Rebuild. + +Wed Nov 18 10:22:22 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-types.h: Re-do type system so that GCC's attribute and mode + are used to specify types. Handle case of ALPHA. + +1998-11-13 Frank Ch. Eigler <fche@elastic.org> + + * aclocal.m4: Add tests for dlopen family. + * config.in: Regenerated. + +Wed Nov 11 14:02:25 1998 Doug Evans <devans@canuck.cygnus.com> + + * sim-hload.c (sim_load): Pass `prog_name' to sim_load_file, not NULL. + +Wed Nov 4 23:51:19 1998 Doug Evans <devans@seba.cygnus.com> + + * genmloop.sh (eng.hin): Rename HAVE_PARALLEL_EXEC to + HAVE_PARALLEL_INSNS, define as 0 or 1. Emit decls of fns in mloop.cin. + * cgen-engine.h: Typedefs of IADDR,CIA,SEM_ARG,SEM_PC moved ... + * cgen-sim.h: ... to here. + +Wed Oct 28 12:00:57 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * aclocal.m4 (enable-build-warnings): Replace + enable-sim-warnings. Extend =LIST syntax so that prepend and + append of options is possible. Drop -Werror, add + -Wstrict-prototypes for GDB compatibility. + * Make-common.in (SIM_WARNINGS): Update. + +Mon Oct 19 13:56:32 1998 Doug Evans <devans@seba.cygnus.com> + + * Make-common.in (CGEN_INCLUDE_DEPS): Define. + (sim-core.o): Delete duplicate dependence on $(SIM_EXTRA_DEPS). + (sim-cpu.o,sim-endian.o,sim-hw.o): Ditto. + (cgen-run.o,cgen-scache.o,cgen-trace.o,cgen-utils.o): Delete + explicit cgen header dependencies, require SIM_EXTRA_DEPS to include + CGEN_INCLUDE_DEPS. + * cgen-cpu.h: New file. + * cgen-engine.h: New file. + * cgen-scache.h: New file. + * cgen-sim.h: Delete portions moved to new files. + * genmloop.sh: Generate two files eng.hin,mloop.cin explicitly, + rather than sending result to stdout. + +Fri Oct 9 14:20:22 1998 Doug Evans <devans@seba.cygnus.com> + + * Make-common.in (sim-reg.o): New rule. + (cgen-run.o): New rule. + * cgen-ops.h: Delete many BI macros. Change all UBI -> BI. + * cgen-run.c (prime_cpu): New function. + * cgen-scache.c: Add pseudo-basic-block (pbb) scaching support. + (scache_option_handler, case OPTION_PROFILE_SCACHE): Handle explicitly + mentioned cpu. + (scache_flush_cpu,scache_lookup,scache_lookup_or_alloc): New fns. + * cgen-sim.h (CGEN_INSN_VIRTUAL_TYPE): New enum. + (CGEN_INSN_VIRTUAL_P): New macro. + (SEM_PC): New typedef. + (SEMANTIC_FN): Change type of result to SEM_PC. + (SEM_SET_FULL_CODE,SEM_SET_FAST_CODE,SEM_SET_CODE): New macros. + (IDESC_CTI_P,IDESC_SKIP_P): New macros. + (SCACHE_MAP): New typedef. + (CPU_SCACHE): Add pbb support. + (scace_lookup,scache_lookup_or_alloc,scache_flush_cpu): Declare. + (SEM_BRANCH_INIT_EXTRACT,SEM_BRANCH_INIT,SEM_BRANCH_FINI): New macros. + (CGEN_CPU): New members running_p,insn_count,{fast,full}_engine_fn, + max_slice_insns. + (INSN_NAME): Delete. + (cgen_insn_name): Declare. + (sim_engine_invalid_insn): Renamed from sim_engine_illegal_insn. + * cgen-trace.c (trace_buf): Shrink from 1024 to 256 bytes. + (first_insn_p): Make static. + (trace_insn): Handle virtual insns specially. + (cgen_trace_printf): Ensure we haven't overflowed the buffer. + * cgen-types.h (UBI): Delete. + (MODE_TYPE): New enum. + (HOSTINT,HOSTUINT,HOSTPTR): Delete. + * cgen-utils.c (mode_names): Delete UBI. Add INT,UINT,PTR. + (cgen_virtual_opcode_table): New global. + (cgen_insn_name): New function. + (sim_disassemble_insn): Ignore virtual insns. + * genmloop.sh: Delete top level loop generation. Add pbb support. + * sim-cpu.h (CPU_INSN_NAME_FN): New typedef. + (sim_cpu_base): New members max_insns,insn_name,model_data. + (CPU_PC_GET,CPU_PC_SET): New macros. + (sim_pc_get,sim_pc_set): Declare. + * sim-model.c (model_set): Call model init fn. + * sim-model.h (MODEL_FN): New typedef. + (INSN_TIMING): New member model_fn. + (MODEL): New members num,init. + * sim-profile.c (sim_profile_print_bar): Renamed from print_bar. + All callers updated. + (profile_insn_init): New fn. + (profile_print_insn): Update, INSN_NAME -> CPU_INSN_NAME. + Exit early if insn profiling not supported. + (profile_print_memory): Update, MAX_MODES -> MODE_TARGET_MAX. + (profile_install): Record profile_insn_init as init fn. + (profile_uninstall): Free PROFILE_INSN_COUNT if non-null. + * sim-profile.h: Update, MAX_MODES -> MODE_TARGET_MAX. + (PROFILE_DATA): Delete member exec_time. + Change insn_count to pointer to array, rather than the array. + (sim_profile_print_bar): Declare. + +Wed Oct 7 16:56:42 1998 Doug Evans <devans@seba.cygnus.com> + + * cgen-run.c: New file. + * sim-reg.c: New file. + +Mon Sep 14 10:58:19 1998 Frank Ch. Eigler <fche@cygnus.com> + + * aclocal.m4: Add checks for -lsocket and -lnsl. + + * dv-sockser.c (dv_sockser_init): Use SO_REUSEADDR to + allow local port reuse on listening socket. + +Tue Sep 1 15:36:52 1998 Frank Ch. Eigler <fche@cygnus.com> + + * sim-config.h: Remove reference to linux kernel header. + +Tue Aug 25 12:45:27 1998 Frank Ch. Eigler <fche@cygnus.com> + + * dv-sockser.c (sockser_addr): Make variable non-static. + +Mon Aug 24 11:47:37 1998 Joyce Janczyn <janczyn@cygnus.com> + + * sim-hw.{c,h} (sim_hw_parse): Return struct hw pointer. + +Tue Aug 11 18:12:19 1998 Doug Evans <devans@canuck.cygnus.com> + + * sim-events.c (sim_events_elapsed_time): Fix calculation. + +Tue Aug 4 20:36:46 1998 Jeff Holcomb <jeffh@cygnus.com> + + * Make-common.in (install-common): Add $(EXEEXT) when installing + run. + +Mon Aug 3 11:46:01 1998 Doug Evans <devans@seba.cygnus.com> + + * cgen-sim.h (cgen_state): New member opcode_table. + * cgen-utils.c (sim_disassemble_insn): Use it. + +Fri Jul 24 10:14:18 1998 Doug Evans <devans@canuck.cygnus.com> + + * cgen-mem.h (DECLARE_SETT): Fix return type. + * cgen-sim.h (sim_engine_illegal_insn): Declare. + * cgen-scache.c: Include stdlib.h. + * cgen-trace.c (trace_extract): Use %lx for PCADDR. + * sim-model.c (model_option_handler): Remove unused variable `n'. + +Tue Jul 21 16:27:43 1998 Doug Evans <devans@seba.cygnus.com> + + * cgen-utils.c: Include bfd.h. + (sim_disassemble_insn): Update call to CGEN_EXTRACT_FN. + +Wed Jul 8 18:24:10 1998 Jeffrey A Law (law@cygnus.com) + + * sim-bits.h (EXTEND24): Fix typo. + +Wed Jul 8 17:41:47 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-events.c (ETRACE_P): New macro. + (struct _sim_event): Add member trace. + (sim_events_free): Reclaim trace message. + + * sim-events.c, sim-events.h (sim_events_schedule_vtracef, + sim_events_schedule_tracef): New functions, include printf trace + information in argument list. If tracing, store asprintf'd trace + message in sim_event. + + * hw-events.c, hw-events.h (hw_event_queue_schedule_tracef, + hw_event_queue_schedule_vtracef): New functions, mimic + sim_event_tracef. + +Mon Jul 6 15:51:14 1998 Jeffrey A Law (law@cygnus.com) + + * sim-bits.h (EXTEND24): Define. + +Thu Jul 2 17:13:25 1998 Doug Evans <devans@seba.cygnus.com> + + * cgen-sim.h (CPU_SCACHE): Make size unsigned. + (CPU_SCACHE_HASH_MASK): New macro. + (SCACHE_HASH_PC): Rewrite. + * genmloop.sh (engine_resume_{full,fast}): Move some of hash + computation out of main loop. + +Wed Jul 1 16:44:12 1998 Doug Evans <devans@seba.cygnus.com> + + * Make-common.in (SCHEME,SCHEMEFLAGS): Delete. + (CGENDIR,CGEN): New variables. + (CGEN_VERBOSE): Renamed to CGENFLAGS. + (cgen-arch,cgen-cpu,cgen-decode): Update. + (CGEN_CPU_WRITE): New variable. + (CGEN_CPU_SEMSW): -W -> -X. + (CGEN_FLAGS_TO_PASS): Delete SCHEME. Add CGEN,CGENFLAGS. + * cgen.sh: Delete args scheme,schemeflags. New arg cgen. + + * cgen-sim.h (RECORD_IADDR): Delete. + * cgen-types.h (HOSTINT,HOSTUINT,HOSTPTR): New types. + * genmloop.sh (engine_resume_{full,fast}): Delete icount. + +Wed Jun 17 12:25:08 1998 Mark Alexander <marka@cygnus.com> + + * gennltvals.def (mn10200): Add entry. + * nltvals.def: Regenerate with MN10200 additions. + +Wed Jun 17 13:18:28 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-inline.h (EXTERN_*): Replace with EXTERN_*_P. Correct + documentation on how it works. + + * sim-core.h, sim-core.c (sim_core_install, sim_core_attach, + sim_core_detach, sim_core_read_buffer, sim_core_write_buffer, + sim_core_set_xor, sim_core_xor_read_buffer, + sim_core_xor_write_buffer): Update. + + * sim-events.h, sim-events.c (sim_events_install, + sim_events_watch_clock, sim_events_schedule_after_signal, + sim_events_schedule, sim_events_watch_sim, sim_events_watch_core, + sim_events_deschedule): Update. + + * sim-fpu.h, sim-fpu.c (sim_fpu_zero, sim_fpu_one, sim_fpu_two, + sim_fpu_max32, sim_fpu_max64): Update. + +Sat Jun 13 07:45:38 1998 Doug Evans <devans@fallis.cygnus.com> + + * cgen-trace.c (trace_insn_fini): Redo cycle handling. + * sim-profile.h (PROFILE_DATA): Rename cycle handling members. + * sim-profile.c (profile_print_model): Update. + +Fri Jun 12 18:35:07 1998 Doug Evans <devans@seba.cygnus.com> + + * gennltvals.def (m32r): Use common syscall.h now. + (mn10300): Add entry. + * nltvals.def: Regenerate. + + * sim-engine.c (sim_engine_get_run_state): New function. + * sim-engine.h (sim_engine_get_run_state): Declare it. + +Thu Jun 11 00:50:03 1998 Doug Evans <devans@seba.cygnus.com> + + * sim-core.h (SIM_CORE_SIGNAL_FN): New typedef. + * sim-core.c (sim_core_signal): Make extern, always define. + +Wed Jun 10 16:02:29 1998 Doug Evans <devans@seba.cygnus.com> + + * Make-common.in (CGEN_FLAGS_TO_PASS): New variable. + * cgen-ops.h (ANDIF): New macro. + (ANDIF[BQHSD]I): Delete. + +Thu Jun 4 13:53:54 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * hw-events.c (create_hw_event, delete_hw_event): Delete. + (hw_event_queue_schedule, hw_event_queue_deschedule, + bounce_hw_event): Fix hw-event memory corruptions found by Joyce + Janczyn. + + * hw-alloc.h (HW_NZALLOC): Define. + + * Make-common.in (test-hw-events): Add target for testing the + hw-event code. + +Mon May 25 21:11:26 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * Make-common.in (SIM_COMMON_HW_OBJS): Add hw-handles.o and + hw-instances.o. + hw-handles.c, hw-instances.c, hw-handles.h, hw-instances.h: New + files. + * hw-main.h: Include hw-handles.h, hw-instances.h. + * hw-base.h ({create,delete}_hw_{handles,instances}_data): Declare + * hw-base.c (hw_create, hw_delete): Call same. + +Mon May 25 18:55:35 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * dv-core.c: Include hw-main.h and sim-main.h. + * dv-pal.c: Include hw-main.h and sim-io.h. + * dv-glue.c: Include hw-main.h. + + * hw-main.h: New file. Move list of includes to here. + * hw-base.h: From here. + * Make-common.in (hw_base_headers): Rename to hw_main_headers. + (hw-*.o, dv-*.o): Update. + * hw-tree.c, hw-base.c, hw-properties.c, hw-ports.c, hw-device.c, + hw-events.c, hw-alloc.c, sim-hw.c: Include hw-main.h instead of + sim-main.h. + + * hw-base.h (do_hw_attach_regs, do_hw_poll_read_method, + do_hw_poll_read): Move declarations from here. + * hw-main.h: To here. + + * hw-base.h (struct hw_device_descriptor, hw_finish_callback): + Move from here. + * hw-main.h (struct hw_descriptor, hw_finish_method): To here, + rename. + * Make-common.in (hw-config.h): Update + * hw-base.c, dv-pal.c, dv-glue.c: Update + + * dv-glue.c, hw-device.h, hw-base.h, hw-ports.c: Rename + `*_callback' to `*_method. + +Mon May 25 18:41:18 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * hw-base.h (set_*): Move set method macros from here. + * hw-device.h: To here. + +Mon May 25 18:21:38 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * hw-base.h (create_hw_property_data, delete_hw_property_data): + Declare. + + * hw-base.c (hw_create, hw_delete): Call + * hw-properties.c (create_hw_property_data, + delete_hw_property_data): Define. + +Mon May 25 17:40:46 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * hw-device.c, hw-properties.c: Include hw-base.h + + * hw-alloc.h, hw-alloc.c: New files. Move alloc code to here. + * hw-device.c: From here. + * hw-base.h: Include "hw-events.h". + + * hw-base.h (create_hw_alloc_data, delete_hw_alloc_data): Declare. + * hw-base.c (hw_create, hw_delete): Call. + * hw-alloc.c (create_hw_alloc_data, delete_hw_alloc_data): Define. + + * Make-common.in (SIM_NEW_COMMON_OBJS): Add hw-alloc.o. + (hw-alloc.o): New target. + +Mon May 25 17:14:27 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * hw-events.h, hw-events.c: New files. Move event code to here. + * sim-hw.c: From here. + * hw-base.h: Include "hw-events.h". + * Make-common.in (SIM_NEW_COMMON_OBJS): Add hw-events.o. + (hw-events.o): New target. + + * hw-device.h (struct hw): Add struct hw_event_data events_of_hw. + * hw-events.h (struct hw_event): Replace typedef hw_event. + + * hw-base.h (create_hw_event_data, delete_hw_event_data): Declare. + * hw-base.c (hw_create, hw_delete): Call. + * hw-events.c (create_hw_event_data, delete_hw_event_data): Define. + + * dv-pal.c: Update. + +Mon May 25 16:55:16 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * hw-base.c (panic_hw_port_event, empty_hw_ports): Move from here. + * hw-ports.c: To here. + + * hw-base.h, hw-ports.c (create_hw_port_data, + delete_hw_port_data): New functions. + * hw-base.c (hw_delete, hw_create): Call same. + + * hw-base.h (set_hw_ports, set_hw_port_event): Move set functions + from here. + * hw-ports.h: To here. + +Mon May 25 16:42:48 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * hw-device.c (hw_ioctl), hw-device.h (hw_ioctl_callback): Drop + PROCESSOR and CIA arguments. + +Fri May 22 12:16:27 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * aclocal.m4 (SIM_AC_OPTION_HW): Add enable / disable argument. + Move common object files from here. + * Make-common.in (SIM_COMMON_HW_OBJS): To here. + +Thu May 21 17:57:16 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-hw.c: Include ctype.h. + (do_hw_poll_read): Do not assume EAGAIN. + +Wed May 20 04:37:57 1998 Doug Evans <devans@seba.cygnus.com> + + * cgen-trace.c (first_insn_p): New static local. + (trace_insn_init): Set it. + (trace_insn_fini): Use TRACE_PREFIX. + (trace_insn): Rewrite to use trace_prefix. + * sim-trace.c (trace_prefix): Don't print filename arg if NULL. + Adjust width accordingly. + + * sim-profile.h (PROFILE_DATA): New member profile_any_p. + (PROFILE_ANY_P,PROFILE_INSN_P,PROFILE_MEMORY): New macros. + (PROFILE_SCACHE_P,PROFILE_PC_P,PROFILE_CORE_P): New macros. + (PROFILE_COUNT_INSN,PROFILE_COUNT_READ,PROFILE_COUNT_WRITE): Simplify. + (PROFILE_COUNT_CORE): Simplify. + * sim-profile.c (profile_option_handler): Compute profile_any_p. + +Tue May 19 23:55:30 1998 Doug Evans <devans@seba.cygnus.com> + + * cgen-ops.h (ADDCFSI): Fix typo. + +Sat May 16 12:44:52 1998 Doug Evans <devans@seba.cygnus.com> + + * cgen-sim.h (CGEN_CPU): New members idesc_{read,sem}_init_p. + * genmloop.sh: Use them rather than static locals. + + * sim-engine.c (sim_engine_set_run_state): New function. + * sim-engine.h (sim_engine_set_run_state): Declare. + * genmloop.sh (pending_reason,pending_sigrc): New static locals. + (@cpu@_engine_stop): New args reason,sigrc. All callers updated. + (engine_resume): Reorganize. Allow synchronous exit from main loop. + +Fri May 15 16:06:05 1998 Doug Evans <devans@seba.cygnus.com> + + * cgen-trace.c (trace_insn_init): New arg first_p. + All callers updated. + (trace_insn_fini): New arg last_p. All callers updated. + * cgen-trace.h (trace_insn_init,trace_insn_fini): Update. + (TRACE_INSN_INIT,TRACE_INSN_FINI): Update. + * genmloop.sh (engine_resume): Update. + +Fri May 15 15:59:00 1998 Joyce Janczyn <janczyn@cygnus.com> + + * Make-common.in (install-common): Run ranlib on installed copy of + libsim.a. + +Fri May 15 15:03:00 1998 Joyce Janczyn <janczyn@cygnus.com> + + * Make-common.in (install-common): Rename and install libsim.a. + +Tue May 12 15:23:57 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-io.c (unistd.h): Include. + +Wed May 6 16:04:18 1998 Doug Evans <devans@seba.cygnus.com> + + * Make-common (sim_main_headers): Sort. + (cgen-*.o): Add cgen-sim.h dependency. + + * cgen-scache.c (scache_init): Only allocate space if scache element + size is non-zero. + (scache_flush,scache_print_profile): Check if scache in use first. + + * cgen-sim.h (IDESC): Provide forward declaration. + (DECODE): Delete. + (CGEN_CPU): Always define scache member. New members idesc,opcode. + (cgen_cpu_max_extra_bytes): Declare. + * cgen-utils.c (cgen_cpu_max_extra_bytes): New function. + + * cgen.sh: s/@arch@/${arch}/ for cpu files. + + * sim-cpu.h: New file. sim_cpu_base moved here. + Move sim_cpu_lookup decl here. + * sim-base.h: #include "sim-cpu.h". + * sim-cpu.c: New file. + * Make-common (sim_main_headers): Add sim-cpu.h. + (sim-cpu.o): Add rule for. + + * sim-model.c (set_model): Delete. + (sim_model_set,model_set): New functions. + (sim_model_install): Renamed from model_install. + Don't set default model here. + (model_option_handler): Rewrite --model processing. + (sim_model_lookup,sim_mach_lookup): New functions. + * sim-model.h (MAX_MODELS,MAX_INSNS): Delete. + (insn_timing): Delete. + (INSN_TIMING): New member `num'. + (IMP_PROPERTIES): Always define scache_elm_size member. + (MACH): New member init_cpu. + (sim_machs): Renamed from machs. + (sim_model_install): Renamed from model_install. + (sim_model_set,sim_model_lookup,sim_mach_lookup): Declare. + * sim-module.c (modules): Update. + + * sim-profile.c (profile_print_insn): Add cpu arg to INSN_NAME macro. + + * sim-io.c: #include <errno.h>. + +Wed May 6 12:39:15 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * dv-pal.c (struct hw_pal_device): Add reader. + (hw_pal_finish): Initialize reader. + (scan_hw_pal): Use reader. + + * hw-base.h, sim-hw.c (do_hw_poll_read): New function. + (HW_IO_EOF, HW_IO_NOT_READY): Define. + * dv-pal.c: Use. + + * sim-io.h, sim-io.c (sim_io_poll_read): New function. Copy from + ../ppc/main.c sim_io_read_stdin. + +Fri May 1 12:11:02 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * hw-tree.h (hw_tree_print): Paramaterize with print and file + arguments. + * hw-tree.c: Update. + + * hw-base.h (hw_port_event_callback): Delete CPU/CIA args. + * hw-device.h (hw_io_read_buffer, hw_io_write_buffer): Delete + CPU/CIA args. + * hw-ports.h (hw_port_event): Ditto. + * hw-ports.c (hw_port_event): Update. + * hw-base.c (panic_hw_io_read_buffer, panic_hw_io_write_buffer): + Update. + * dv-pal.c (hw_pal_io_read_buffer, hw_pal_io_write_buffer): + Update. + (hw_pal_io_write_buffer): Call hw_halt not sim_engine_halt. + (do_counter_event): Update. + * dv-glue.c (hw_glue_io_read_buffer): Update. + (hw_glue_port_event): Update. + + * hw-device.h (SIM_DESC): Replace with struct sim_state. + * hw-base.h (hw_create): Ditto. + * hw-base.c (hw_create): Ditto. + + * hw-device.c (hw_abort, hw_trace, hw_hw_event_queue_schedule, + hw_event_queue_deschedule, hw_event_queue_time): Delete, moved + from here to. + * sim-hw.c: Here. + * hw-device.h (hw_system_cpu): Declare. + * sim-hw.c (hw_system_cpu): New function. + + * sim-core.c (sim_core_map_attach, sim_core_attach): Call + sim_hw_abort not hw_abort. + (sim-hw.h): Include. + (sim_core_read_buffer, sim_core_write_buffer): Call + sim_hw_io_read_buffer and sim_hw_io_write_buffer. Do not pass CPU + argument. + (sim_core_set_xor): Do not pass CPU when aborting. + + * sim-n-core.h (sim_core_read_aligned_N, + sim_core_write_aligned_N): Call sim_hw_abort not hw_abort. + (sim_core_read_aligned_N, sim_core_write_aligned_N): Call + sim_cpu_hw_io_read_buffer and sim_cpu_hw_io_write_buffer. Does not + return length. + + * sim-hw.h: Declare sim_hw_io_{read,write}_buffer. Declare + sim_hw_print. + * sim-hw.c (sim_hw_io_read_buffer, sim_hw_io_write_buffer, + sim_cpu_hw_io_read_buffer, sim_cpu_hw_io_write_buffer): New + functions. + (sim_hw_print): New function. + + * sim-engine.h (sim_engine_vabort): Declare. + * sim-engine.c (sim_engine_vabort): New function. + +Wed Apr 29 23:58:52 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-trace.c (print_data): For floating-point numbers trace raw + hex value. + (trace_result_fp2): New function. + * sim-trace.h (trace_result_fp2): New declaration. + (TRACE_FP_RESULT2): New macro. + +Tue Apr 28 18:28:58 1998 Geoffrey Noer <noer@cygnus.com> + + * common/aclocal.m4: call AM_EXEEXT in SIM_AC_COMMON, define + AM_CYGWIN32 and AM_EXEEXT. + * common/Make-common.in: set EXEEXT, add missing EXEEXTs + to run and install-common rules. + * common/configure: regenerate + +Sat Apr 25 17:45:01 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-types.h (cell_word): New type. + (natural_cell): Delete type. + +Sun Apr 26 15:31:55 1998 Tom Tromey <tromey@creche> + + * configure: Regenerated to track ../common/aclocal.m4 changes. + * config.in: Ditto. + +Sun Apr 26 15:25:07 1998 Tom Tromey <tromey@cygnus.com> + + * acconfig.h (NEED_DECLARATION_PRINTF): Removed. + +Fri Apr 24 14:16:40 1998 Tom Tromey <tromey@creche> + + * configure: Regenerated to track ../common/aclocal.m4 changes. + * config.in: Ditto. + +Fri Apr 24 11:38:08 1998 Tom Tromey <tromey@cygnus.com> + + * acconfig.h: New file. + * Make-common.in (top_builddir): New macro. + (INTL_LIB): Removed. + (INTLLIBS): New macro. + (INTLDEPS): Likewise. + (LIBDEPS): Use INTLDEPS. + (EXTRA_LIBS): Use INTLLIBS. + * aclocal.m4 (SIM_AC_COMMON): Call CY_GNU_GETTEXT. + (CY_WITH_NLS, CY_GNU_GETTEXT, AM_PATH_PROG_WITH_TEST, + AM_LC_MESSAGES): New macros from GNU gettext. + +Fri Apr 24 19:57:59 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-config.h: Discard leading _ from macros. + * sim-types.h: Ditto. + +Wed Apr 22 14:14:19 1998 Michael Meissner <meissner@cygnus.com> + + * Make-common.in (CSEARCH): Add -I to intl directories. + (INTL_LIB): Point to libintl.a. + (LIBDEPS): Add $(INTL_LIB). + (EXTRA_LIBS): Ditto. + +Tue Apr 21 12:44:27 1998 Doug Evans <devans@canuck.cygnus.com> + + * cgen-types.h (GETHIDI,MAKEDI): Tweak. + + * cgen-ops.h (ADDCFSI): Fix. + (SUBCFSI): Tweak. + +Tue Apr 21 13:18:41 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-types.h (signed_address, unsigned_address): Define. + +Mon Apr 20 21:47:54 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-fpu.c (sim_fpu_2d): Don't return an SNaN, convert it into a + QNaN. + +Thu Apr 16 10:30:14 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-fpu.c, sim-fpu.h (sim_fpu_fractionto, sim_fpu_tofraction): + New functions, pack / unpack sim_fpu struct using raw values. + (sim_fpu_is): Differentiate between negative and positive + infinity. + +Tue Apr 14 18:49:31 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-bits.h (EXTEND4): Define. + (EXTEND4, EXTEND15, EXTEND11): Ditto. + +Tue Apr 14 16:31:35 1998 John Metzler <jmetzler@cygnus.com> + + * sim-memopt.c (parse_addr): Sunos 4.5 does not have strtol + declared so we need this cast to prevent long long addresses + from being misconfigures. Results in access to unmapped memory. + +Tue Apr 14 13:19:14 1998 Doug Evans <devans@canuck.cygnus.com> + + * Make-common.in (RUNTESTFLAGS): Define. + (check): Pass RUNTESTFLAGS to recursive make. + +Tue Apr 14 15:09:19 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-info.c (sim_info): Be verbose when either VERBOSE or + STATE_VERBOSE_P. + +Sat Apr 4 23:24:17 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * aclocal.m4 (sim-inline): By default, disable sim-inline when + cross compiling. + +Sat Apr 4 20:36:25 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * aclocal.m4 (sim-cflags): Add -fomit-frame-pointer to defaults. + (sim-inline): Update to match sim-inline.[hc] + * configure: Regenerated to track ../common/aclocal.m4 changes. + + * Make-common.in (sim_main_headers): Add sim-inline.h + + * sim-bits.h (sim-bits.c): Include when H_REVEALS_MODULE_P. + selected. + * sim-endian.h (sim-endian.c): Ditto. + + * sim-events.h (_SIM_EVENTS_H_): Replace with SIM_EVENTS_H. + (sim_events_set_trace): Delete unused prototype. + + * sim-core.h (_SIM_CORE_H_): Replace with SIM_CORE_H. + * sim-core.c (_SIM_CORE_C_): Ditto for SIM_CORE_C. + + * sim-fpu.h (sim-fpu.c): Include when H_REVEALS_MODULE_P. + (sim_fpu_to232i, sim_fpu_to232u, sim_fpu_i232to, sim_fpu_u232to): + Comment out, not yet implemented in sim-fpu.c. + (sim_fpu_zero, sim_fpu_one, sim_fpu_two, sim_fpu_qnan, + sim_fpu_max32, sim_fpu_max64): Mark as EXTERN_SIM_FPU. + + * sim-inline.h: Rewrite description. + (H_REVEALS_MODULE_P, C_REVEALS_MODULE_P): Define. + (SIM_MAIN_INLINE): Add inline option. + + * sim-inline.c (semantics.c, idecode.c, engine.c, ...): Do not + include generated files. Handled by generator directly. + +Sat Apr 4 01:07:06 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-trace.c (set_trace_option_mask): Keep TRACE_ANY_P + up-to-date. + + * sim-trace.h (TRACE_ANY_P): Define. + (struct _trace_data): Add trace_any_p. + +Mon Mar 30 17:11:55 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * run.c (main): Handle all alternatives of enum sim_stop. + (main): Delete unused `asection *s'. + +Fri Mar 27 16:15:52 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * hw-tree.h, hw-tree.c (hw_tree_vparse): New function + + * configure: Regenerated to track ../common/aclocal.m4 changes. + + * sim-hw.c: New file. + * sim-hw.h (sim_hw_parse): Declare function. + (hw-tree.h): Do not include. + + * sim-base.h (STATE_HW): Define. + (struct sim_state_base): Add member struct *hw. + + * sim-module.c (sim-hw.h): Include. + (modules): Add sim_hw_install. + + * aclocal.m4 (sim_hw_obj): Add sim-hw.o + +Fri Mar 27 14:55:06 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-base.h (CPU_INDEX): Define. + + * sim-utils.c (sim_state_alloc): Initialize. + * sim-module.c (sim_post_argv_init): Ditto. + +Thu Mar 26 10:07:57 1998 Stu Grossman <grossman@bhuna.cygnus.co.uk> + + * aclocal.m4 (sim_hw_obj): Fix sed expression to generate + properly formatted lists. + +Thu Mar 26 10:37:22 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * dv-pal.c (enum hw_pal_address_mask): From Stu Grossman, was + 0x2f needs to be 0x3f. + +Thu Mar 26 09:10:56 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * hw-tree.c (hw_tree_find_property): Return NULL when device is + not found. + (hw_tree_find_*_property): Clean up error message when property is + not found. + + * dv-pal.c (hw_pal_io_read_buffer): Check the smp property is + present before looking for it. + +Wed Mar 25 16:17:38 1998 Ian Carmichael <iancarm@cygnus.com> + + * aclocal.m4 (AC_CHECK_HEADERS): Add check for fpu_control.h. + (AC_CHECK_FUNCS): Add check for __setfpucw. + * configure: Regenerated. + +Wed Mar 25 09:18:34 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * dv-pal.c (hw_pal_countdown, hw_pal_countdown_value, + hw_pal_timer, hw_pal_timer_value): Define. + (hw_pal_io_read_buffer, hw_pal_io_write_buffer): Add timer support + (do_counter_event, do_counter_read, do_counter_value, + do_counter_write): new functions. + +Tue Mar 24 12:24:24 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * hw-tree.c (hw_printf): Send tree dump to stderr, same as other + trace output. + + * hw-base.c (hw_create): Stop searching for a device when one is + found. + +Wed Mar 25 12:35:29 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * configure: Regenerated to track ../common/aclocal.m4 changes. + +Mon Mar 23 10:25:08 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * aclocal.m4 (SIM_AC_OPTION_HARDWARE): Add second argument, + appends extra devices. + (SIM_AC_OPTION_HARDWARE): Substute sim_hw, a non-duplicate list of + the device names. + + * Make-common.in (hw-config.h): New target, create hw-config.h + file. + (SIM_HW): Definition from @sim_hw@. + (hw-base.o): Depend on hw-config.h + +Tue Mar 24 17:41:35 1998 Stu Grossman <grossman@bhuna.cygnus.co.uk> + + * Make-common.in: Get SHELL from configure. + * (stamp-tvals sim-inline.c): Use $(SHELL) when invoking + move-if-change. Fixes NT native build problem. + * Makefile.in (nltvals.def): Use $(SHELL) when invoking + move-if-change. Fixes NT native build problem. + * configure: Regenerate with autoconf 2.12.1 to fix shell issues for + NT native builds. + +Sun Mar 22 16:54:40 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * hw-device.h, hw-device.c (hw_strdup): New function. + + * hw-base.c (hw_create): Use hw_strdup when saving a copy of the + strings name, family and args. + (full_name_of_hw): Use hw_strdup when returning the full path. + + * hw-properties.c: Clean up property not found / wrong type error + messages. + + * hw-tree.c (hw_tree_parse): Finish a devices initialization + before attaching any ports. + + * hw-base.c (hw-config.): Include. Replace hardwired table. + + * dv-glue.c: Copy over ../ppc/hw_glue.c. Update to new framework. + + * Make-common.in: Add rule for dv-glue.o. + +Sun Mar 22 16:45:54 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * hw-base.c (hw_finish): Move setting of trace level to here. + (hw_create): From here. + + * hw-base.h, hw-base.c (do_hw_attach_regs): Copy function from + ../ppc/device_table.c. + + * dv-pal.c (hw_pal_finish): Attach PAL device to parent bus. + + * hw-tree.c (print_properties): Supress path when printing + properties of root node. + +Sun Mar 22 16:21:15 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * hw-device.h (HW_TRACE): Define. + (hw_trace): Declare. + * hw-device.c (hw_trace): Implement function. + + * hw-base.c (hw_create): Set hw trace level from "trace?" + property. + + * dv-core.c (dv_core_attach_address_callback): Add trace. + + * dv-pal.c: Replace DTRACE with HW_TRACE. + +Sun Mar 22 15:23:35 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * hw-device.h (HW_ZALLOC, HW_MALLOC): New macros. + (hw_alloc_data): Delcare. + (struct hw): Add member alloc_of_hw. + + * hw-device.c (hw_zalloc, hw_malloc, hw_free, hw_free_all): New + functions. Assocate memory with a device. + (stdlib.h): Include. + + * hw-base.h (set_hw_delete): Define. + (hw_delete_callback): Declare. + (hw_delete): Declare. + + * hw-base.c (hw_delete): Implement function. + (struct hw_base_data): Add member to_delete. + (ignore_hw_delete): New function, does nothing. + (hw_create): Set the hw_delete method. + (hw_create): Allocate the base type using HW_ZALLOC before setting + any methods. + + * hw-tree.h, hw-tree.c (hw_tree_delete): New function. + + * hw-properties.c: Replace zalloc/zfree with hw_zalloc/hw_free. + + * hw-ports.c: Replace zalloc/zfree with hw_zalloc/hw_free. + (attach_hw_port_edge): Add struct hw argument + + * dv-pal.c (hw_pal_finish): Replace zalloc/zfree with + hw_zalloc/hw_free. + +Sun Mar 22 15:09:52 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * hw-device.h (hw_attach_address_callback, + hw_detach_address_callback): Attach to a single space not a space + mask. Clarify interpretation of SPACE:ADDR parameters. + + * hw-base.c (passthrough_hw_attach_address, + passthrough_hw_detach_address): Update. + * dv-core.c (dv_core_attach_address_callback): Ditto. + * dv-pal.c (hw_pal_attach_address): Ditto. + +Thu Mar 19 00:41:00 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-options.h: Document additional CPU arg to OPTION_HANDLER. + +Wed Mar 18 14:13:02 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * Make-common.in (SIM_HW_OBJS, SIM_HW_SRC, SIM_DV_OBJS): Define. + (hw-base_h, hw-device_h, hw-handles_h, hw-instances_h, hw_ports_h, + hw-properties_h, hw-tree_h): Define, point at corresponding + header. + (hw_base_headers): Define list of headers included by hw-base.h + (hw-base.o, hw-device.o, hw-instances.o, hw-handles.o, hw-ports.o, + hw-properties.o, hw-tree.o): Specify dependencies. + (dv-core.o, dv-pal.o): Ditto. + + * sim-hw.h: New file. + + * hw-device.h, hw-device.c, hw-properties.h, hw-properties.c, + hw-ports.h, hw-ports.c: New files. Copied from ../ppc/device.[ch]. + + * hw-tree.h, hw-tree.c: New files. Copied from ../ppc/tree.[hc]. + + * hw-base.h, hw-base.c: new files. Copied from + ../ppc/device_table.[hc]. + + * dv-core.c, dv-pal.c: New files. Copied from + ../ppc/hw_{core,pal}.c + + * sim-basics.h (struct hw): Declare. + (enum port_direction, enum object_disposition): Declare. + +Wed Mar 18 12:38:12 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * aclocal.m4 (SIM_AC_OPTION_HARDWARE): Set sim_hw_obj, sim_dv_obj, + sim_dv_src in Makefile. Take list of devices as parameter to m4 + macro.. + + * configure: Regenerated to track ../common/aclocal.m4 changes. + +Mon Mar 16 12:37:33 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-trace.h, sim-trace.c (trace_prefix): Pass in sim_cia so that + trace_prefix can abort cleanly. + +Sat Mar 14 18:36:12 1998 Doug Evans <devans@seba.cygnus.com> + + * dv-sockser.c, dv-sockser.h: New files. + * Make-common.in (dv-sockser.o): Add rule for. + * aclocal.m4: Check for fcntl.h. + * config.h: Add HAVE_FCNTL_H. + + * sim-break.c (remove_breakpoint): Fix thinko. + + * sim-hload.c (sim_load): Provide default value of SIM_HANDLES_LMA. + Use SIM_HANDLES_LMA for lma_p arg to sim_load_file. + +1998-03-13 Fred Fish <fnf@cygnus.com> + + * sim-base.h (struct sim_state_base): Add prog_syms and + define macro STATE_PROG_SYMS. + * sim-trace.c (trace_prefix): Add variables abfd, symsize, + symbol_count, and asymbols. Call bfd_get_symtab_upper_bound + and bfd_canonicalize_symtab, to get symbol table on first use + and preserve it via STATE_PROG_SYMS for future calls to + bfd_find_nearest_line. + +Wed Mar 11 14:02:47 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-core.h, sim-core.c (sim_core_map_to_str): Delete. + + * sim-core.c (sim_core_attach): Handle a generic number of maps - + up to nr_maps, not just access_* maps. + + * sim-profile.h (struct PROFILE_DATA): Track nr_maps different + maps. + + * sim-profile.c (profile_print_core): Make map unsigned. Iterate + over nr_maps not sim_core_nr_maps. + + * sim-events.h, sim-events.c (sim_events_watch_core): Change + core_map argument to unsigned. + (struct _sim_core): Ditto for struct member core_map. + + * sim-core.h (nr_sim_core_maps, sim_core_*_map): Delete + + * sim-basics.h (access_io, access_*_io): Define. + (map_read, map_write, map_exec, map_io): Define. + + * sim-core.c, sim-core.h (sim_core_attach): Replace argument + attach with more generic mapmask. + (sim_core_{read,write}_*): Change map argument to unsigned. + + * sim-core.c (sim_core_uninstall, sim_core_attach, + sim_core_detach): Iterate over nr_maps instead of + sim_core_nr_maps. + + * sim-break.c (insert_breakpoint): Write breakpoints to exec_map + instead of the write_map. + (remove_breakpoint): Ditto. + + * genmloop.sh (engine_resume_full): Replace sim_core_*_map + with read_map, write_map, exec_map resp. + + * cgen-mem.h (DECLARE_GETMEM, DECLARE_SETMEM, DECLARE_GETIMEM): + Ditto. + + * cgen-utils.c (sim_disassemble_insn): Ditto. + + * sim-hrw.c (sim_write, sim_write): Ditto. + + * sim-utils.h, sim-utils.c (access_to_str, map_to_str, + transfer_to_str): New functions. + +Mon Mar 9 12:50:59 1998 Doug Evans <devans@seba.cygnus.com> + + * sim-base.h (sim_state_base): New member environment. + (STATE_ENVIRONMENT): New macro. + * sim-config.c (current_environment): Delete. + (sim_config_default): New function. + (sim_config): Set STATE_ENVIRONMENT, not current_environment. + * sim-config.h (current_environment,CURRENT_ENVIRONMENT): Delete. + (sim_config_default): Add prototype. + * sim-module.c (sim_pre_argv_init): Call sim_config_default. + * sim-options.c (standard_option_handler, case OPTION_ENVIRONMENT): + Set STATE_ENVIRONMENT, not current_environment. + +Mon Mar 9 11:59:03 1998 Jim Wilson <wilson@cygnus.com> + + * sim-fpu.c (NR_GUARDS64): Change NR_PAD32 to NR_PAD64. + +Tue Mar 3 10:53:05 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-types.h (SIGNED32, SIGNED64): Pacify GCC. + + * sim-alu.h (ALU64_BEGIN): Make alu64_r unsigned. + +Mon Mar 2 10:20:06 1998 Doug Evans <devans@seba.cygnus.com> + + * Make-common.in (TAGS): Make smarter. + * Makefile.in (TAGS): Ditto. + +Fri Feb 27 19:09:57 1998 Doug Evans <devans@canuck.cygnus.com> + + * sim-module.c (*): Fix typos in assertion tests. + +Sat Feb 28 13:54:10 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-module.c (sim_pre_argv_init): String passed to asprintf + can't be constant. + + * sim-options.c (sim_parse_args): Ditto. + (sim_args_command): Return OK, instead of nothing, for an empty + command. + +Fri Feb 27 13:29:13 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-profile.c (profile_info): Rename from profile_print. Drop + misc and misc_cpu callback arguments. Use + PROFILE_INFO_CPU_CALLBACK and STATE_PROFILE_INFO_CALLBACK instead. + (profile_install): Install profile_info function. + + * sim-profile.h (PROFILE_INFO_CPU_CALLBACK, + STATE_PROFILE_INFO_CALLBACK): Define. + (struct PROFILE_DATA): Add field info_cpu_callback. + (profile_print): Delete function. + + * sim-base.h (STATE_MODULES): Define. Replace individual + STATE_*_LIST with single struct module_list. + + * sim-module.h (MODULE_INFO_FN, MODULE_INFO_LIST): Declare. + (struct module_list): Declare. + + * sim-module.h, sim-module.c (sim_module_add_info_fn, + sim_module_info): New functions. + (sim_module_install): Clean up module data structures. + + * sim-info.c (sim_info): New file. New function. Call + sim_module_info. + + * Make-common.in (sim-info.o): Define rule. + (SIM_NEW_COMMON_OBJS): Add sim-info.o. + + +Fri Feb 27 18:26:16 1998 Doug Evans <devans@canuck.cygnus.com> + + * sim-base.h (sim_cpu_base): New members name, options. + (sim_cpu_lookup): Add prototype. + * sim-module.c (sim_pre_argv_init): Provide default names for cpus. + * sim-options.h (DECLARE_OPTION_HANDLER): New argument `cpu'. + (sim_add_option_table): Update prototype. + * sim-options.c (sim_add_option_table): New argument `cpu'. + (standard_option_handler,standard_install): Update. + (sim_parse_args): Handle cpu specific options. + (print_help): New static function. + (sim_print_help): Call it. Print cpu specific options. + (find_match): New static function. + (sim_args_command): Call it. Handle cpu specific options. + * sim-utils.c (sim_cpu_lookup): New function. + * sim-memopt.c (memory_option_handler): Update. + (sim_memopt_install): Update. + * sim-model.c (model_option_handler): Update. + (model_install): Update. + * sim-profile.c (profile_option_handler): Update. + (profile_install): Update. + * sim-trace.c (trace_option_handler): Update. + (trace_install): Update. + * sim-watch.c (watchpoint_option_handler): Update. + (sim_watchpoint_install): Update. + * cgen-scache.c (scache_option_handler): Update. + (scache_install): Update. + +Wed Feb 25 11:00:26 1998 Doug Evans <devans@canuck.cygnus.com> + + * Make-common.in (check): Run `make check' in testsuite dir. + +Wed Feb 25 14:40:24 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-trace.c (trace_result0): New function. + + * sim-trace.h (TRACE_FP_*, TRACE_FPU_*): Rename TRACE_FPU_* + macro's to TRACE_FP_*. TRACE_FPU_* should be defined and used when + tracing sim_fpu variables. + (TRACE_ALU_RESULT0): Define. + (TRACE_FP_RESULT_WORD): Define. + (TRACE_FP_INPUT_WORD1): Define. + + * sim-fpu.c, sim-fpu.h (sim_fpu_max32, sim_fpu_max64, sim_fpu_one, + sim_fpu_two): New constants. + (sim_fpu_op1, sim_fpu_op2): New types. + (struct _sim_fpu): Delete member result. Re-order other members. + (sim_fpu_sign, sim_fpu_exp): New functions. + (sim_fpu_max, sim_fpu_min): new functions. + (EXPMAX32, EXPMAX64, NR_PAD32, NR_PAD64, NR_GUARDS32, NR_GUARDS64, + NORMAL_EXPMAX32, NORMAL_EXPMAX64): Define. + +Tue Feb 24 22:45:39 1998 Doug Evans <devans@seba.cygnus.com> + + * sim-profile.c (profile_print): Delete duplicate test of + PROFILE_INSN_IDX. + (profile_print_pc): Exit early if data collection not set up. + (profile_print_core): Simplify by calling sim_core_map_to_str. + * sim-core.h (sim_core_map_to_str): Declare. + * sim-core.c (sim_core_map_to_str): Make non-static. + + * genmloop.sh (engine_resume): Update insn_count before exiting. + (engine_resume_full): Keep accurate core profile data. + + * cgen-utils.c (sim_disassemble_insn): Don't use + sim_core_read_aligned_N, it messes up profiling results. + +Mon Feb 23 20:45:57 1998 Mark Alexander <marka@cygnus.com> + + * nltvals.def: Regenerate with MN10300 additions. + +Tue Feb 24 13:18:42 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-trace.h (TRACE_ALU_RESULT2): Define. + + * sim-trace.h, sim-trace.c (trace_result_word2, + trace_input_word4, trace_result_word4): New function. + +Mon Feb 23 13:08:35 1998 Doug Evans <devans@canuck.cygnus.com> + + * cgen-sim.h (SEM_NEXT_PC): New arg `len'. + + * sim-xcat.h: Delete. + * cgen-mem.h: Delete inclusion of sim-xcat.h. + * cgen-sim.h: Ditto. + * sim-alu.h: Replace sim-xcat.h with symcat.h. + * sim-n-bits.h: Ditto. + * sim-n-core.h: Ditto. + * sim-n-endian.h: Ditto. + +Mon Feb 23 13:19:58 1998 Michael Meissner <meissner@cygnus.com> + + * syscall.c (cb_syscall): Handle short reads, and EOF. + +Tue Feb 24 00:29:57 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-trace.c (print_data): case trace_fmt_fp missing break. Use + sim_fpu to safely print fp_word values. + (print_data): Add trace_fmt_bool and trace_fmt_addr. + (trace_result_bool1, trace_result_addr1): New functions. + (trace_input_bool1, trace_input_addr1): New functions. + + * sim-trace.h (TRACE_FPU_*): Define. + +Mon Feb 23 13:24:54 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-fpu.h (enum sim_fpu_class): Add sim_fpu_class_denorm. + (sim_fpu_fpto, sim_fpu_tofp): Define. + +Fri Feb 20 18:08:51 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-fpu.c (sim_fpu_cmp): New function. + +Wed Feb 18 16:29:21 1998 Doug Evans <devans@canuck.cygnus.com> + + * cgen-utils.h (sim_disassemble_insn): Use CGEN_INSN_BITSIZE + instead of abuf->length. + * sim-trace.c (trace_options): Have -t only trace a few useful things. + (set_trace_option_mask): Renamed from set_trace_options. + (set_trace_option): New function. + (trace_option_handler): Update calls to set_trace_option{,_mask}. + * sim-trace.h (TRACE_USEFUL_MASK): New macro. + +Wed Feb 18 12:42:15 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-basics.h: Declare struct _sim_fpu. + +Tue Feb 17 16:27:46 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-trace.h (TRACE_ALU_INPUT*, TRACE_ALU_RESULT): Define. + (trace_prefix, trace_input*, trace_result*): Declare. + (trace_one_insn): Change declaration, assume trace_prefix called. + (trace_generic): Like trace_one_insn. + (TRACE_ALU_IDX, TRACE_*_IDX): Change #define's to enum. + (TRACE_alu, TRACE_[a-z]*): Update. + + * sim-trace.c (trace_prefix, trace_input*, trace_result*, + trace_insn, save_data, trace_idx_to_str, print_data): New + functions. + (trace_one_insn): Rewrite. + (trace_generic): New function. + +Tue Feb 17 17:27:30 1998 Doug Evans <devans@seba.cygnus.com> + + * Make-common.in (CGEN_MAIN_SCM): Update. + * aclocal.m4 (USE_MAINTAINER_MODE): New variable. + + * cgen-sim.h (SEMANTIC_CACHE_FN): Delete. + (SEMANTIC_FN): Rewrite declaration. + (DECODE): Update type of semantic_fast member. + ({EX,SEM}_FN_NAME): Have only one version. + * cgen.sh: Support building cpu.c. + * sim-base.h (sim_state_base): Delete conditionals surrounding + member scache_size. + +Tue Feb 10 18:31:49 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-load.c (sim_load_file): Print LMA/VMA according to value + used. + +Tue Feb 10 14:56:23 1998 Ian Carmichael <iancarm@cygnus.com> + + * sim-core.c: Add missing prototypes for WITH_DEVICES. + Add missing parameters to device_io calls. + * sim-core.h: Add missing parameters to device_io calls. + +Mon Feb 9 14:48:37 1998 Doug Evans <devans@canuck.cygnus.com> + + * cgen-sim.h (DECODE): Always use switch for `read' for now. + (PAREXEC): Renamed from PARALLEL_EXEC. All uses updated. + (SEMANTIC{,_CACHE}_FN): Fix return type. + * cgen.sh (decode): Add s/@arch@/$arch/. + * genmloop.sh (@cpu@_engine_run): Delete `current_state'. + (engine_resume): Likewise. Make `engine' volatile. Save copy + of cpu pointer in volatile object. Initialize read switch if + -parallel. + +Thu Feb 5 13:27:04 1998 Doug Evans <devans@seba.cygnus.com> + + * cgen-sim.h (EX_FN_NAME): _exc_ -> _ex_. + (SEM_INSN): New macro. + +Tue Feb 3 16:31:56 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-run.c (sim_engine_run): Assume IMEM is 32 bit. + +Sun Feb 1 16:47:51 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * configure: Regenerated to track ../common/aclocal.m4 changes. + +Sun Feb 1 16:16:57 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-types.h (fp_word): New type, define according to + WITH_TARGET_FLOATING_POINT_BITSIZE. + + * aclocal.m4 (default_sim_floating_point_bitsize): Add + configuration of size of floating point registers. + +Sun Feb 1 14:02:31 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-profile.c (profile_print): Only print CPU <N> if other + output is going to appear. + +Sat Jan 31 18:15:41 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * configure: Regenerated to track ../common/aclocal.m4 changes. + +Sat Jan 31 18:03:55 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-types.h (address_word): Typedef according to + WITH_TARGET_ADDRESS_BITSIZE. + (signed_cell, unsigned_cell, natural_cell): Ditto using + WITH_TARGET_CELL_BITSIZE. + + * sim-config.h (WITH_TARGET_ADDRESS_BITSIZE): Define. + (WITH_TARGET_CELL_BITSIZE): Define. + (WITH_HOST_WORD_BITSIZE): Delete. + + * sim-config.c (print_sim_config): Update. + + * aclocal.m4 (SIM_AC_OPTION_BITSIZE): Add support for + configuration of address and OpenFirmware cell sizes. + +Fri Jan 30 09:36:33 1998 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-engine.h (sim_engine_run): Add argument nr_cpus. + * sim-run.c (sim_engine_run): Update. + + * sim-engine.h (SIM_ENGINE_HALT_HOOK): Use SET_CPU_CIA instead of + CPU_CIA. + * sim-run.c (sim_engine_run): Ditto. + + * sim-resume.c (sim_resume): Obtain nr_cpus from sim_engine. + (sim_resume): Pass nr_cpus to sim_engine_run. + + * sim-engine.h (struct _sim_engine): Add member nr_cpus. + + * sim-engine.c (sim_engine_init): Hardwire nr_cpus to + MAX_NR_PROCESSORS. + (sim_engine_nr_cpus) sim-engine.c, sim-engine.h: New function + +Thu Jan 29 12:13:01 1998 Doug Evans <devans@canuck.cygnus.com> + + * cgen.sh: Portably read parms past $9. + +Fri Jan 23 14:20:54 1998 Doug Evans <devans@seba.cygnus.com> + + * Make-common.in (stamp-tvals): New rule. + (targ-vals.h,targ-map.c): Depend on it. + (clean): Remove stamp-tvals. + +Tue Jan 20 21:35:13 1998 Michael Meissner <meissner@cygnus.com> + + * sim-utils.c (sim_state_alloc): #if 0 variable that is only used + in code also #if 0'ed. + +Mon Jan 19 22:26:29 1998 Doug Evans <devans@seba> + + * configure: Regenerated to track ../common/aclocal.m4 changes. + * aclocal.m4: Recognize --enable-maintainer-mode. + +Mon Jan 19 12:45:45 1998 Doug Evans <devans@seba.cygnus.com> + + * cgen-scache.h: Deleted. + * Make-common.in (cgen-run.o,cgen-scache.o): Delete cgen-scache.h dep. + (CGEN_CPU_SCM): Add sim-model.scm. + * cgen-scache.c: Only compile contents if WITH_SCACHE. + (scache_init): Use runtime computed size of SCACHE. + (scache_flush): Likewise. + * cgen-mem.h (GETIMEMU[QHSD]I): Declare. + ([GS]ETT{QI,UQI,HI,UHI,SI,USI,DI,UDI}): Declare. + * cgen-sim.h: Scache support moved here. + (PC): Redo definition. + (ARGBUF,SCACHE,PARALLEL_EXEC): Provide forward decls. + (DECODE): Add parallel execution support. + Only include semantic label members if using switch. + (SWITCH,CASE,BREAK,DEFAULT,ENDSWITCH): Portable computed goto support. + (CGEN_CPU): Delete members exec_state, halt_sigrc, halt_jmp_buf. + (IADDR,CIA,SEM_ARG,EX_FN_NAME,SEM_FN_NAME,RECORD_IADDR,SEM_ARGBUF, + SEM_NEXT_PC,SEM_BRANCH_VIA_{CACHE,ADDR},SEM_NEW_PC_ADDR): Moved here + from cgen-types.h. + (engine_{stop,run,resume,halt,signal}): Delete decls. + * cgen-types.h (CGEN_{XCAT3,CAT3}): Delete. + (argbuf,scache): Delete forward decls. + (STATE): Delete decl. + * cgen-utils.c: Don't include decode.h, mem-ops.h, sem-ops.h. + Include cgen-mem.h, cgen-ops.h. + (engine_halt,engine_signal): Delete. + ({ex,exc,sem,semc}_illegal): Delete. + (sim_disassemble_insn): Result of extract fn is in bits. + * genmloop.sh: Rewrite. + + * cgen-trace.c (trace_insn): Set printed_result_p=0 if not tracing + line numbers. + + * sim-base.h (sim_state_base): Delete member `model'. + (sim_cpu_base): Add member `model'. + * sim-model.h (IMP_PROPERTIES): New type. + (MACH): New members imp_props, models. + (models): Delete decl. + * sim-model.c (set_model): Update. + * sim-profile.c (profile_print_model): Update. + + * sim-utils.c (sim_state_alloc): Delete setting of cpu backlink here. + +Fri Jan 16 12:33:09 1998 Nick Clifton <nickc@cygnus.com> + + * cgen-trace.c (trace_insn): Call CGEN_INSN_MNEMONIC() rather than + CGEN_INSN_SYNTAX(). + +Mon Dec 15 23:17:11 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * configure: Regenerated to track ../common/aclocal.m4 changes. + * config.in: Ditto. + +Mon Dec 15 23:16:03 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * aclocal.m4 (AR): Check for sigaction. + +Thu Dec 4 09:21:05 1997 Doug Evans <devans@canuck.cygnus.com> + + * Make-common.in (sim-core.o): Depend on $(sim_main_headers). + + * sim-config.h (WITH_TREE_PROPERTIES): Define as 0. + * sim-config.c (sim_config): Replace WITH_DEVICES with + WITH_TREE_PROPERTIES. + + * configure: Regenerated to track ../common/aclocal.m4 changes. + +Wed Dec 3 17:56:02 1997 Doug Evans <devans@canuck.cygnus.com> + + * Make-common.in (SIM_ENVIRONMENT): New variable. + (CONFIG_CFLAGS): Add it. + * aclocal.m4 (SIM_AC_OPTION_ENVIRONMENT): Handle + --enable-sim-environment option. + * configure: Regenerated. + * sim-config.h (environment support): Rewrite. + * sim-config.c (current_environment): Define as enum, unconditionally. + (current_alignment): Define unconditionally. + (config_environment_to_a): Update. + (config_alignment_to_a): Fix type of argument. Define unconditionally. + (sim_config): Handle environment and alignment determination + unconditionally. Delete sanity checks of current_environment, + unnecessary. + (print_sim_config): Update. + * sim-options.c (STANDARD_OPTIONS enum): Add OPTION_ENVIRONMENT. + (standard_options): Add --environment. + (standard_option_handler): Likewise. + +Fri Nov 28 12:21:25 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-alu.h: Add notes on carry vs borrow for subtraction. + (ALU{,8,16,32,64}ADD): Redefine ADD macro as add overflowing. + (ALU{,8,16,32,64}ADDC): Define - add carrying. + (ALU{,8,16,32,64}SUB): Redefine SUB macro as subtract overflowing. + (ALU{,8,16,32,64}SUBB): Define - subtract borrowing. + (ALU{,8,16,32,64}SUBC): Define - tract carrying. + (ALU{,8,16,32,64}ADD_CA, ALU{,8,16,32,64}ADDC_C): Replace single + argument ADD_CA macro with two argument ADDC_C - add carrying with + carry in. + (ALU{,8,16,32,64}SUB_CA, ALU{,8,16,32,64}SUBC_X): Replace single + argument SUB_CA macro with two argument SUBC_X - subtract + carrying, extended. + (ALU{,8,16,32,64}SUBB_B): Define - subtract borrowing with + borrow-in. + (ALU{,8,16,32,64}NEGC, ALU{,8,16,32,64}NEGB): Define. + +Sun Nov 30 17:40:57 1997 Michael Meissner <meissner@cygnus.com> + + * sim-io.c (sim_io_{syscalls,getstring}): Delete. No longer used. + * sim-io.h (sim_io_syscalls): Delete. + +Fri Nov 28 20:10:09 1997 Michael Meissner <meissner@cygnus.com> + + * syscall.c (cb_syscall): Add missing else, so write to stdout + isn't doubled. + + * sim-alu.h (ALU{,8,16,32,64}_SET_CARRY): Provide macros to import + the carry bit from the CPU's psw. + +Fri Nov 28 11:15:05 1997 Doug Evans <devans@canuck.cygnus.com> + + * gennltvals.sh: Redo syscall support. + * nltvals.def: Regenerated. + +Wed Nov 26 16:49:38 1997 Michael Meissner <meissner@cygnus.com> + + * syscall.c (cb_syscall): If writing to stdout or stderr, flush + the stream immediately. + +Wed Nov 26 12:32:11 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-io.c (sim_io_getstring): Delete unused len2. + (sim_io_syscalls): Ditto for sys_errno. + +Wed Nov 26 11:18:40 1997 Doug Evans <devans@canuck.cygnus.com> + + * syscall.c (cb_syscall): Test CB_SYSCALL struct magic number. + + * Make-common.in (run.o): Depend on remote-sim.h. + (nrun.o,sim-hload.o,sim-hrw.o): Likewise. + (sim-io.o,sim-reason.o,sim-resume.o): Likewise. + +Tue Nov 25 20:12:46 1997 Michael Meissner <meissner@cygnus.com> + + * sim-io.c (sim_io_syscalls): Disable lseek. + +Tue Nov 25 00:12:38 1997 Doug Evans <devans@seba.cygnus.com> + + * gennltvals.sh: Generate syscall values for d30v. + + * gennltvals.sh: Use libgloss/syscall.h for sparc. + * nltvals.def: Regenerate. + + * callback.c (os_stat): Make 3rd arg a host struct stat ptr. + (os_fstat): Likewise. Validate fd argument. + (cb_host_to_target_stat): Delete big_p arg. If HS arg is NULL, + just compute target stat struct length. + * syscall.c: #include "libiberty.h", <sys/types.h>, <sys/stat.h>. + (ENOSYS,ENAMETOOLONG): Provide definitions if missing. + (get_string): Return host errno values so they can be properly + translated later. + (cb_syscall): Likewise. + (cb_syscall, cases open,unlink): Use get_path instead of get_string. + (cb_syscall, case read): Use read_stdin for file descriptor 0. + (cb_syscall, case write): Use write_stderr for file descriptor 2. + (cb_syscall): Add cases for lseek, unlink, stat, fstat, time. + (get_path): New function. + +Mon Nov 24 18:56:07 1997 Michael Meissner <meissner@cygnus.com> + + * sim-io.c (sim_io_syscalls): New function to provide system call + emulation. Provide exit, open, close, read, write, lseek, and + unlink. + (sim_io_getstring): New function to return a string from a + simulated memory location. + + * sim-io.h (sim_io_syscalls): Add declaration. + +Mon Nov 24 12:09:59 1997 Doug Evans <devans@seba.cygnus.com> + + * sim-core.c (sim_core_signal): Fix spelling error in message. + + * sim-hrw.c (sim_read): Use read map, not write map. + + * Make-common.in (all): Add .gdbinit. + * gdbinit.in: Add dump command. + + * sim-model.c (model_options): Use '\0' for `shortopt'. + + * sim-trace.c (trace_option_handler): Set state trace file + for --trace-file in addition to cpu's values. + (trace_vprintf): If cpu == NULL, try state's trace file. + (trace_options): Reorganize table, reword some descriptions. + +Sun Nov 23 10:57:00 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-fpu.c (sim_fpu_abs, sim_fpu_neg, sim_fpu_inv), sim-fpu.h: + New functions. + +Sat Nov 22 19:16:54 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-reason.c (sim_stop_reason): For sim_signalled, return the + signal untranslated, document problem with this. + + * nrun.c (main): Check for a prog name of `*step'. If present, + step the simulator instead of allowing it to run free. + + * sim-signal.c (SIGQUIT): Define on _MSC_VER hosts. + + * Make-common.in (sim_main_headers): Add sim-signal.h. + +Fri Nov 21 09:32:32 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-signal.c (sim_signal_to_host): Return 0 for SIM_SIGNONE. + +Thu Nov 20 20:35:20 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-signal.h: Start simulator signals at 64 so that host signal + numbers can be detected and reported. + + * sim-signal.h (SIM_SIGFPE), sim-signal.h: Add signal. + +Wed Nov 19 12:02:41 1997 Doug Evans <devans@seba.cygnus.com> + + * callback.c (cb_host_to_target_stat): Fix return values. + + * cgen-sim.h (enum_signal_type): Delete. + (engine_signal): Update prototype. + * cgen-utils.c: Don't include <signal.h>. + (sim_signal_to_host): Delete, lives in sim-signal.c now. + (engine_signal): Update. + + * sim-utils.c (sim_state_alloc): Call SIM_STATE_ALLOC if defined. + (sim_state_free): Call SIM_STATE_FREE if defined. + + * sim-module.c (sim_module_install): Don't leave any modules + installed if one fails to install. + +Wed Nov 19 13:25:48 1997 Michael Meissner <meissner@cygnus.com> + + * sim-options.c: Don't include ../libiberty/alloca-conf.h any + more, since alloca is not used in this file. + + * sim-alu.h (ALU{32,64}_*): Rewrite 32 and 64 bit ALU support to + correctly set the carry and overflow bits for those types. + (ALU{8,16,32,64}_{ADD,SUB}_CA): Take VAL argument to add along + with carry, so carry is correct after doing both adds. + (ALU*): Space out '\' to make it easier to read. + +Tue Nov 18 15:53:45 1997 Doug Evans <devans@canuck.cygnus.com> + + * sim-core.c (sim_core_signal): Use sim_stopped instead of + sim_signalled. + + * sim-signal.c, sim-signal.h: New files. + * Make-common.in (sim-signal.o): Add rule for. + (SIM_NEW_COMMON_OBJS): Add sim-signal.o. + * sim-abort.c: Don't include <signal.h>. + * sim-basics.h: #include "sim-signal.h". + * sim-break.c: Don't include <signal.h>. + (sim_handle_breakpoint): Replace SIGTRAP with SIM_SIGTRAP. + * sim-core.c: Don't include <signal.h>. + (SIGBUS): Delete definition. + (sim_core_signal): Replace SIGSEGV,SIGBUS with SIM_SIGSEGV,SIM_SIGBUS. + * sim-engine.c: Don't include <signal.h>. + (sim_engine_abort): Replace SIGABRT with SIM_SIGABRT. + * sim-reason.c (sim_stop_reason): Call sim_signal_to_host. + * sim-resume.c: Don't include <signal.h>. + (SIGTRAP): Delete definition. + (has_stepped): Replace SIGTRAP with SIM_SIGTRAP. + * sim-stop.c: Don't include <signal.h>. + (control_c_simulation): Replace SIGINT with SIM_SIGINT. + * sim-watch.c: Don't include <signal.h>. + (handle_watchpoint): Replace SIGINT with SIM_SIGINT. + + * Make-common.in (SIM_NEW_COMMON_OBJS): New variable. + + * sim-base.h (CIA_ADDR): Provide default definition. + * sim-core.c (sim_core_signal): Use CIA_ADDR to fetch value. + * sim-break.c (sim_handle_breakpoint): Likewise. + +Mon Nov 17 14:15:31 1997 Doug Evans <devans@seba.cygnus.com> + + * Make-common.in (srccom): New variable. + + * Make-common.in (DEP, COMMON_DEP_CFLAGS): Define. + (LIB_OBJS): Add syscall.o. + (gentmap): Pass $(NL_TARGET) to $(CC). + (syscall.o): Add rule for. + (sim_main_headers): Add $(SIM_EXTRA_DEPS). + (sim-bits.o): Depend on $(sim-n-bits_h). + (sim-load.o): Depend on callback.h. + + * Make-common.in (cgen-*.o): Update dependencies, mem-ops.h renamed to + cgen-mem.h, sem-ops.h renamed to cgen-ops.h. + * cgen-mem.h, cgen-ops.h: New files. + + * aclocal.m4 (--enable-sim-scache): Pass -DWITH_SCACHE=0 for "=no". + + * Makefile.in (nltvals.def): Depend on gennltvals.sh. + Rewrite build rule. + * callback.c: #include string.h or strings.h. + #include sys/types.h and sys/stat.h. + (cb_init_syscall_map,cb_init_errno_map,cb_init_open_map): Declare. + (os_get_errno,os_open): Update. + (os_stat,os_fstat): New functions. + (os_init): Initialize syscall_map, errno_map, open_map. + (default_callback): Add entries for os_stat, os_fstat, syscall_map, + errno_map, open_map, signal_map, stat_map. + (cb_read_target_syscall_maps): New function. + (cb_target_to_host_syscall): New function. + (cb_host_to_target_errno): Renamed from host_to_target_errno. + (cb_target_to_host_open): Renamed from target_to_host_open. + (store): New function. + (cb_host_to_target_stat): New function. + * syscall.c: New file. + * gentmap.c (sys_tdefs): New global. + (gen_targ_vals_h): Output target syscall numbers. + (gen_targ_map_c): Update. Output target syscall translation map. + * gentvals.sh: New first argument `target'. Preface table with + #ifdef NL_TARGET_$target if non-null target passed. + * gennltvals.sh: New file. + * nltvals.def: Regenerated. + +Fri Nov 14 11:33:34 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-n-core.h (sim_core_read_unaligned_N): Return static + sim_core_dummy_M. + (sim_core_dummy_M): Declare. + +Wed Nov 12 18:16:15 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-core.c (sim_core_signal): Print the address of the + instruction. + +Thu Nov 13 11:49:41 1997 Doug Evans <devans@seba.cygnus.com> + + * sim-base.h (sim_state_base): Move `magic' to end of struct. + + * sim-base.h (sim_state_base): Add member trace_data. + (STATE_TRACE_DATA): New macro. + * sim-trace.h (TRACE_DEBUG_IDX,TRACE_debug): New macros. + ({WITH_,}TRACE_DEBUG_P): New macros. + (STATE_TRACE_FLAGS,STRACE_P,STRACE_DEBUG_P): New macros. + (_sim_cpu): Delete forward reference. + (debug_printf): Update. + * sim-trace.c (OPTION_TRACE_DEBUG): Define. + (trace_options): Add --trace-debug. + (set_trace_options): Handle it. + (trace_option_handler): Likewise. + (trace_install): Init state trace_data struct. + (trace_uninstall): Close state trace file. + * sim-events.c (ETRACE): Only print source file and line number if + --trace-debug. + * sim-n-core.h (sim_core_trace_M): Likewise. + + * sim-core.c (sim_core_signal): Add missing "\n" in message. + +1997-11-13 Felix Lee <flee@cygnus.com> + + * sim-n-core.h (sim_core_read_unaligned_N): illegal empty + initializer. + * sim-types.h (unsigned128,signed128): fix typo for MSVC. + +Wed Nov 12 12:18:08 1997 Doug Evans <devans@canuck.cygnus.com> + + * aclocal.m4 (SIM_AC_OPTION_SCACHE): Fix typo. + + * Make-common.in (BUILT_SRC_FROM_COMMON): Remove files no longer + built this way. + (sim-config.o): Remove non-existent $(sim-nconfig_h) dependency. + (clean): Don't delete $(BUILT_SRC_FROM_COMMON) if building in + source tree. + +Tue Nov 11 13:28:02 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-events.c (sim_events_process): Re-compute the time - + update_time_from_event - as each event is processed. Reverses + previous change. + +Fri Nov 7 00:37:36 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * callback.c (os_poll_quit): Replace _WIN32 with _MSC_VER. + +Fri Nov 7 00:37:36 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-events.c (sim_events_process): Delete redundant call to + update_time_from_event. + (sim_events_slip): Always decrement time_from_event. + (sim_events_tick, sim_events_deschedule, update_time_from_event): + Delete assertion that time_from_event >=0 when work in queue, no + longer applicable. + +Thu Nov 6 12:06:46 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-options.c (STANDARD_OPTIONS): Change OPTION_* to an enum. + (standard_option_handler): Update. + + * sim-options.h: Clarify documentation. + (OPTION_LONG_ONLY_P): Delete definition. + (OPTION_VALID_P): Define. + + * sim-options.c (sim_print_help): Allow short only options. + (sim_parse_args): Ditto. + (sim_args_command): Skip short only options. + (sim_parse_args): Allocate space for NUM_OPTS not just 256. Make + separate entries for short and long options in the HANDLERS and + ORIG_VAL tables. + (sim_parse_args): Disable argument permutation. + +Wed Nov 5 13:40:31 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-core.h (DECLARE_SIM_CORE_WRITE_N. DECLARE_SIM_CORE_READ_N): + Add argument M, size of data type. + (sim_core_read_misaligned_3, sim_core_write_misaligned_3): + Declare, ditto for 5, 6 & 7 byte transfers. + (sim_core_write_unaligned_1, sim_core_write_unaligned_1): Define + as aligned variant. + + * sim-n-core.h (sim_core_trace_M): Rename from + sim_core_trace_N. Add nr_bytes argument. Replace transfer argument + with transfer type. Print transfer direction. Handle 1 and 2 byte + transfers. + (sim_core_read_unaligned_N, sim_core_write_unaligned_N): Trace + unaligned accesses. + (unsigned_M, T2H_M, H2T_M): Rename from unsigned_N, T2H_N, H2T_N. + Update all functions. + + * sim-core.c: Generate functions starting with 16 not 1. + (sim_core_read_unaligned_3): Generate. Ditto for 3 byte write and + all 5, 6 & 7 byte transfers. + + * sim-n-core.h (sim_core_read_misaligned_N, + sim_core_write_misaligned_N): Implement. + +Mon Nov 3 15:03:04 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-endian.h (U16_8): Implement + + * sim-endian.c (sim_endian_split_16, sim_endian_join_16): New functions + + * sim-endian.h (VL8_16, VH8_16): Implement. + + * sim-memopt.c (memory_option_handler): Typecast 64bit value to + long in printf. + (memory_option_handler): Only zalloc modulo bytes when non-zero. + (memory_option_handler): Skip comma in alias address list + +Fri Oct 31 13:03:33 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-memopt.c (do_memopt_add, do_memopt_delete): Add level and + space params. + (parse_size, parse_addr): New functions + (memory_option_handler, memory_options): Parse address & size + using new functions. Pass level, space, modulo to do_memopt_add & + do_memopt_del. + + * sim-memopt.h (struct _sim_memopt): Add level & space fields. + + * sim-core.h (sim_core_arrach, sim_core_detach): Replace + `attach_type attach' argument with `unsigned level' argument. + Document. + + * sim-core.c (new_sim_core_mapping, sim_core_map_attach, + sim_core_attach): Replace argument attach with level. Update + verification of arguments. + (sim_core_map_detach, sim_core_detach): Replace argument attach + with level. + + * sim-basics.h (enum _attach_type): Delete. + +Thu Oct 30 13:45:00 1997 Doug Evans <devans@seba.cygnus.com> + + * sim-core.h (sim_core_write_8): Define. + +Tue Oct 28 12:29:22 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-bits.h: Document ROTn macro. + + * sim-endian.h (H2T): Handle 16 byte variables. + + * sim-n-core.h (sim_core_read_unaligned_N): Return a dummy when an + error. + + * sim-core.c: Do not generate sim_core_*_word. + + * sim-n-core.h (sim_core_trace_N): Add line_nr argument. + (sim_core_write_aligned_N, sim_core_read_aligned_N): Update. + + * sim-core.h (sim_core_read_unaligned_word, + sim_core_read_aligned_word, sim_core_read_word, + sim_core_write_unaligned_word, sim_core_write_aligned_word, + sim_core_write_word): Change to macros that map onto sim_core_*_N. + +Mon Oct 27 11:25:10 1997 Doug Evans <devans@canuck.cygnus.com> + + * sim-n-endian.h: Add TAGS entrys for 16 byte versions. + + * sim-endian.h: Disable 16 byte support. + +Mon Oct 27 12:00:48 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-endian.c (_SWAP_16): Define. Generate 126 bit swap code. + + * sim-n-core.h (sim_core_trace_N): New function. + (sim_core_read_aligned_N, sim_core_write_aligned_N): Use, + (sim_core_read_unaligned_N): Do not retyrn bogus value wden error. + + * sim-endian.h: Add 128 bit variant. + + * sim-core.h, sim-core.c: Add 128 bit variant. + + * sim-types.h: Add signed128 and unsigned128 types using a struct. + +Fri Oct 24 11:33:07 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-events.c (sim_events_process): Clear events->work_pending. + (sim_events_tickn, sim_events_tick): Accumulate, instead of + setting, nr_ticks_to_process. + (sim_events_preprocess): Allow nr_ticks_to_process to be non-zero + when the event queue isn't next. + + * sim-events.h, sim-events.c (sim_events_slip): New function. + +Wed Oct 22 14:18:38 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-hload.c (sim_load): Pass lma_p==0 and do_load=sim_load. + + * sim-utils.h, sim-load.c (sim_load_file): Add lma_p and do_load + arguments. + +Tue Oct 21 18:37:57 1997 Doug Evans <devans@canuck.cygnus.com> + + * nrun.c (main): Remove useless test of name != NULL. + Exit if bfd_openr fails. Call bfd_check_format after bfd_openr. + +Tue Oct 21 10:42:38 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-fpu.c (EXPMAX): Type is unsigned. + (MIN_INT, MAX_INT): Type is signed64. + (i2fpu): Type of val is signed64. + +Tue Oct 21 10:42:38 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-profile.h (PROFILE_PC_BUCKET_SIZE): Treat a shift of zero as + a bucket size of zero. + + * sim-profile.c (OPTION_PROFILE_PC_GRANULARITY, + OPTION_PROFILE_PC): Define. + (profile_option_handler): Add support for --profile-pc and + --profile-pc-granularity options. + (profile_pc_init): When possible, compute nr buckets from bucket + size. + + * sim-profile.c (profile_pc_init): Align the profile-pc end + address with the profile-pc bucket size. + + * sim-profile.h (PROFILE_PC_NR_BUCKETS): Rename PROFILE_PC_SIZE to + something less ambiguous. + (PROFILE_PC_BUCKET_SIZE): Ditto for PROFILE_PC_SAMPLE_SIZE. + + * sim-profile.c (profile_pc_cleanup): New function. Move + profile_pc_uninstall code to here. + (profile_pc_uninstall): Call. + (profile_pc_init): Call. + +Mon Oct 20 17:23:58 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-profile.c (profile_print_pc): Dump pc profile to dmon.out + file using BSD gprof format. + + * sim-bits.h (LSBIT, MSBIT, BIT): Force result to type + unsigned_word. + (LSBIT8, LSBIT16, LSBIT32, LSBIT64, MSBIT8, MSBIT16, MSBIT32, + MSBIT64): Force result to unsignedN. + +Thu Oct 16 11:38:56 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-alu.h (ALU16_BEGIN, ALU32_BEGIN, ALU64_BEGIN): Drop opening + brace from macro. + (ALU8_BEGIN, ALU8_SET, ALU8_ADD, ALU8_SUB, ALU8_NEGATE): Define. + (ALU16_ADD, ALU16_SUB, ALU16_NEGATE): Simplify arrithmetic. + (ALU32_ADD, ALU32_SUB, ALU32_NEGATE): Simplify arrithmetic. + (ALU64_ADD, ALU64_SUB, ALU64_NEGATE): Simplify arrithmetic. + +Wed Oct 15 09:24:19 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-core.h (struct _sim_core_mapping): Change free_buffer to + type void*. + + * sim-core.c (sim_core_uninstall, new_sim_core_mapping, + sim_core_map_attach, sim_core_map_detach): Change free_buffer to + type void*. + (sim_core_attach): Rename buffer_freed to free_buffer, type + void*. Ensure that allocated buffer is alligned according to + region's address. + +Mon Oct 13 11:34:50 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-alu.h (ALU64_HAD_OVERFLOW): Define. + (ALU64_SUB): Define. + + * Make-common.in (all): Build SIM_EXTRA_ALL first. + (.gdbinit): Remove dependencies, generate once per build. + +Tue Oct 14 19:20:09 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-n-core.h (sim_core_read_aligned_N, + sim_core_write_aligned_N): Make xaddr param type address_word not + unsigned_word. + +Fri Oct 3 09:49:18 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-fpu.h, sim-fpu.c: Rewrite. Change sim_fpu object to an + unpacked floating point struct. Pass sim_fpu object by reference. + Add preliminary support for rounding modes. + +Fri Oct 3 09:28:00 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * configure: Regenerated to track ../common/aclocal.m4 changes. + +Thu Oct 2 19:43:52 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * aclocal.m4 (sim-bitsize): Fix typo, WITH_TARGET_WORD_BITSIZE not + WITH_TARGET_BITSIZE. + +Thu Sep 25 23:20:20 1997 Felix Lee <flee@yin.cygnus.com> + + * sim-profile.c (profile_print_core): label needs empty statement. + +Thu Sep 25 11:20:47 1997 Stu Grossman <grossman@babylon-5.cygnus.com> + + * sim-break.c (sim_set_breakpoint sim_clear_breakpoint): Use ZALLOC + and zfree instead of xmalloc and free. Prevents warnings. + +Wed Sep 24 17:38:57 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * configure: Regenerated to track ../common/aclocal.m4 changes. + +Wed Sep 24 17:23:31 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * Make-common.in (SIM_BITSIZE): Assign from configured value. + (CONFIG_CFLAGS): Add SIM_BITSIZE. + + * aclocal.m4 (--enable-sim-bitsize): Developer option for + controling the bitsize/msb of the target. + +Wed Sep 24 17:41:40 1997 Stu Grossman <grossman@babylon-5.cygnus.com> + + * Make-common.in: New files sim-break.c, sim-break.h. + * sim-base.h: Add point to breakpoint list to sim_state_base. + * sim-break.c sim-break.h: New modules that implement intrinsic + breakpoint support. + * sim-module.c: Add breakpoint module. + +Tue Sep 23 00:26:39 1997 Felix Lee <flee@yin.cygnus.com> + + * sim-events.c (SIM_EVENTS_POLL_RATE): poll more often than once + an hour. + * sim-n-core.h (WITH_XOR_ENDIAN): MSVC barfs on + if (0) { 1 % 0; } + * sim-core.c (sim_core_xor_write_buffer): WITH_XOR_ENDIAN + 1. + (SIGBUS) define for Windows. + * sim-trace.c (trace_printf,debug_printf): added ALMOST_STDC. + * sim-resume.c: define SIGTRAP for windows. + * sim-xcat.h: use token pasting if ALMOST_STDC. + +Tue Sep 23 11:04:38 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * Make-common.in (SIM_SCACHE, SIM_DEFAULT_MODEL): Assign + configured values. + (CONFIG_CFLAGS): Add same. + +Mon Sep 22 17:20:27 1997 Felix Lee <flee@cygnus.com> + + * sim-types.h (SIGNED64): ##i64 when _MSC_VER, not _WIN32. + (SIGNED32): use ##i32. + +Tue Sep 23 11:04:38 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * configure: Regenerated to track ../common/aclocal.m4 changes. + +Tue Sep 23 10:07:47 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * aclocal.m4 (sim-endian): Simplify logic determining [default] + endian of target. + + * Make-common.in (SIM_WARNINGS, SIM_ALIGNMENT, SIM_ENDIAN, + SIM_HOSTENDIAN, SIM_RESERVED_BITS, SIM_ASSERT, SIM_FLOAT, + SIM_HARDWARE, SIM_INLINE, SIM_PACKAGES, SIM_REGPARM, SIM_SMP, + SIM_STDCALL, SIM_XOR_ENDIAN): Assign configured values. + (CONFIG_CFLAGS): Add same. + + * aclocal.m4: Perform AC_SUBST on optional options. + +Mon Sep 22 11:46:20 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-config.h (WITH_DEFAULT_ALIGNMENT): Don't hardwire any alignment. + + * sim-options.c (standard_option_handler): Typo in warning message. + + * sim-base.h (STATE_MODEL): Make conditional on SIM_HAVE_MODEL. + + * sim-profile.c (profile_print_insn): Check 0 .. MAX_INSN for any + insn count. Make count conditional on there being a valid + INSN_NAME. + (profile_pc_init): Make default PC profile frequency an arbitrary + 256. + + * sim-base.h: Ditto. + + * sim-profile.h (WITH_PROFILE_MODEL_P): Only enable modeling when + SIM_HAVE_MODEL. + + * sim-model.h (struct MACH): Depreciate, to be replaced by bfd + archure struct. + +Mon Sep 22 11:46:20 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * configure: Regenerated to track ../common/aclocal.m4 changes. + +Mon Sep 22 11:45:00 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * aclocal.m4 (sim_alignment): Simplify logic for selecting the + configured alignment. + +Fri Sep 19 17:45:25 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * configure: Regenerated to track ../common/aclocal.m4 changes. + +Fri Sep 19 17:26:14 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-config.c (sim_config): Check for default alignment. + + * sim-options.c (standard_option_handler): Add alignment option. + + * aclocal.m4 (sim_alignment): Allow configuration of hardwired and + default alignment requirements on memory accesses. + +Fri Sep 19 11:51:35 1997 Jeffrey A Law (law@cygnus.com) + + * sim-load.c (sim_load_file): Return failure if the executable + had no loadable sections. + +Wed Sep 17 13:33:28 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-events.c (ETRACE): Use trace_printf not sim_io_printf for + trace output. + + * sim-core.c (sim_core_signal): When bad access halt simulator + SIGSEGV / SIGBUS instead of aborting. + (signal.h): Include. + + * sim-watch.c (sim_watchpoint_install): Handler for watchpoint + options was missing. + + * sim-bits.h (MOVED): Define + +Wed Sep 17 10:33:28 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-alu.h (ALU32_HAD_OVERFLOW): Pacify GCC, Use MSBIT instead of + BIT. + + * sim-bits.h (LSBIT, MSBIT): Check for overflow of shift value. + + * sim-bits.c: Add 8 bit versions of bit macros. + + * sim-bits.h: Ditto. + +Tue Sep 16 16:15:16 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-bits.c (LSSEXT, MSSEXT): Replace SEXT. + (LSINSERTED, MSINSERTED): Ditto for INSERTED. + + * sim-n-bits.h (MSSEXTn, LSSEXTn): Replace SEXTn. + (LSINSERTDn, MSINSERTEDN): Ditto for INSERTEDn. + + * sim-bits.h (SEXT*): Define as MSEXT/LSEXT. + (INSERTED*): Ditto for LSINSERTED/MSINSERTED. + +Mon Sep 15 17:36:15 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * aclocal.m4 (SIM_AC_COMMON): Add optional config.h file argument. + configure.in: Output to cconfig.h instead of config.h. + + * configure: Regenerated to track ../common/aclocal.m4 changes. + +Mon Sep 15 15:39:28 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-utils.c (sim_analyze_program): Set STATE_ARCHITECTURE from + BFD if known. + +Tue Sep 9 21:46:46 1997 Felix Lee <flee@cygnus.com> + + * callback.c (os_write): divert stdout and stderr to their + respective hooks. + +Thu Sep 11 10:08:48 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-profile.c (profile_print_speed): Call + sim_events_elapsed_time instead of PROFILE_EXEC_TIME for moment. + + * sim-events.c (sim_events_elapsed_time): New function return nr + host MS consumed by the simulator. + (sim_watch_valid): Use. + + * sim-module.c (modules): Install sim_events very very early. + + * sim-profile.c (profile_print): Call profile_print_pc. + (print_bar): + (profile_pc_init): New function, set up processor for PC + profiling. + (profile_print_pc): New function, print a PC profile. + (profile_pc_event): New function, sample PC. + + * sim-profile.h (PROFILE_PC_COUNT, PROFILE_PC_START, + PROFILE_PC_END, PROFILE_PC_SHIFT, PROFILE_PC_SAMPLE_SIZE): Add to + profile struct. + + * sim-options.c (sim_print_help): Pacify GCC. + + * sim-n-core.h (sim_core_read_aligned_N, + sim_core_write_aligned_N): Add un-conditional profile call. + (sim_core_read_unaligned_N, sim_core_write_unaligned_N): Add + profile call when aligned read/write isn't used. + + * sim-base.h: Include sim-profile, sim-model after sim-core & + sim-events allow sim-core to define useful values. + + * sim-profile.c (OPTION_PROFILE_CORE): Define. + (profile_option_handler, profile_options): Add support for + --profile-core option. + (print_bar): Include when core profiling. + (profile_print_core): New function, print core profile. + + * sim-config.c (print_sim_config): Print profile status. + + * sim-profile.h (PROFILE_NEXT_IDX, PROFILE_core, + WITH_PROFILE_PC_P): Define. + (PROFILE_CORE_COUNT): Count each core-map/size separatly. + (PROFILE_COUNT_CORE): Define. + +Thu Sep 11 08:44:52 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-watch.c (handle_watchpoint): Pass a char** index into the + interrupt_names array as the data. + (sim-watch.h): Document. + +Wed Sep 10 16:15:22 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-options.c (sim_print_help): When the doc string is to long + word wrap it. + + * sim-watch.c (sim_watchpoint_install): Use option.doc_name so + that only the first few the watch options are listed. Generate + meanginful usage messages. + + * sim-options.h (struct OPTION): Clarify use of doc_name field + +Wed Sep 10 13:23:24 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-options.c (OPTION_ARCHITECTURE_INFO): New option. + (standard_option_handler): Handle --architecture-info. + +Tue Sep 9 21:46:46 1997 Felix Lee <flee@cygnus.com> + + * sim-core.h (sim_cpu_core): [WITH_XOR_ENDIAN + 1], to avoid + illegal zero-sized array. + * sim-core.c (sim_core_xor_read_buffer): same. + +Tue Sep 9 11:20:35 1997 Doug Evans <dje@canuck.cygnus.com> + + * nltvals.def: Regenerate. + +Tue Sep 9 02:10:36 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-fpu.c (DP_FRACHIGH2): Define LL using SIGNED64. + +Mon Sep 8 12:22:20 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-bits.c (MASKED): Delete. + (EXTRACTED): Delete. + (LSEXTRACTED, MSEXTRACTED): New functions. + + * sim-n-bits.h (MASKEDn): Delete, define as MSMASKED or LSMASKED. + (MSMASKEDn, LSMASKEDn): Add last argument. + (MSMASK*): Ditto. + + * sim-bits.h (EXTEND8, EXTEND16): Define. + (EXTRACTED64): Define as 64 bit extract, not 32 bit. + + * sim-run.c (sim_engine_run): Use CPU_CIA macro. + + * sim-engine.h (SIM_ENGINE_HALT_HOOK): Use CPU_CIA to get at + current instruction address. + + * sim-inline.h (*_ENGINE): Define. + +Fri Sep 5 08:39:02 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-core.c (sim_core_attach): Fix checks of modulo/mask. + + * sim-watch.c (delete_watchpoint): Delete by ident and type. + (watch_option_handler): Call delete_watchpoint with ident or type. + (sim_watchpoint_install): Create interrupt specific watchpoint + commands on the fly. + (do_watchpoint_create): New function, create a watch point using + type/int-nr info encoded in the option nr. + (do_watchpoint_info): New function. List active watchpoints. + + * sim-watch.h: Change data structure to a list. + + * sim-memopt.c (memory_option_handler): Require explicit "all" + before deleting all memory regions. + + * sim-utils.c (sim_do_commandf): New function, printf version of + sim_do_command. + + * sim-basics.h (asprintf, vasprintf): Hack, define for CYGWIN32. + + * sim-alu.h (ALU64_ADD): Use explicit MSEXTRACTED64, do not assume + bit endianness. + (SIGNED64, UNSIGNED64): Delete. + (ALU64_ADD): Don't rely on bit endianness. + (ALU64_BEGIN): Define. + + * sim-n-bits.h (MSEXTRACTEDn, LSEXTRACTED): New functions. + (EXTRACTEDn): Delete, define as either LSEXTRACTED or MSEXTRACTED. + + * sim-types.h (SIGNED64, UNSIGNED64): New macros, attach relevant + suffix - u64, LL - to 64 bit constants. + +Thu Sep 4 09:27:54 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-config.c (sim_config): Add assert for SIM_MAGIC_NUMBER. + + * sim-utils.h (NZALLOC): Define - zalloc * N. + + * sim-hrw.c (sim_read, sim_write): New file. Provide generic + implementation of read/write functions. + + * Make-common.in (sim-hrw.o): New target. + + * sim-base.h (STATE_MEMOPT_P): Delete, simulators _always_ add + memory. + + * sim-memopt.c (memory_option_handler): Implement memory-size + command. Implement memory-alias command. Let memory-delete delete + all memory regions. + (add_memopt): New function. Add a memory region. + (do_memopt_delete): New function. Delete a memory region. + + * sim-utils.c (sim_elapsed_time_get): Never return zero. + + * sim-core.c (sim_core_detach): New function. + (sim_core_map_detach): New function. Perform the actual detach. + (sim_core_init): Move initialization code from here. + (sim_core_install): To here. + (sim_core_uninstall): And here. + + * sim-module.c: Add memopt module. + + * sim-base.h (STATE_MEMOPT, STATE_MEMOPT_P): Add memopt to + simulator base type. + + * Make-common.in (sim_main_headers): Add sim-memopt.h + (sim-memopt.o): New target. + + * sim-core.c (sim_core_install): Add core_options to the option + table. + + * sim-watch.c (watch_options): Make --delete-watch a synonym for + --watch-delete. + + * sim-config.h (WITH_MODULO_MEMORY): Define as 0. Update + comments. + + * sim-core.h (struct _sim_core_mapping): Change nr_bytes to type + address_word, add mask member. + + * sim-core.h, sim-core.c (sim_core_attach): Make nr_bytes of type + address_word, allow for 64bit targets in 32bit host. Add modulo + argument. + (sim_core_map_attach): Ditto. + (new_sim_core_mapping): Ditto. + (sim_core_translate): Mask address when modulo memory. + +Wed Sep 3 17:32:54 1997 Doug Evans <dje@seba.cygnus.com> + + * sim-hload.c (sim_load): Add assert for SIM_MAGIC_NUMBER. + + * gdbinit.in: New file. + * aclocal.m4 (SIM_AC_OUTPUT): Build .gdbinit. + * Make-common.in (distclean): Delete .gdbinit. + (.gdbinit): Add rule for. + * configure: Regenerated to track ../common/aclocal.m4 changes. + + * Make-common.in (cgen-run.o): Add rule for. + +Wed Sep 3 10:08:21 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-resume.c (sim_resume): Suspend/resume the simulator. + + * sim-events.c (sim_watch_valid): Compute total elapsed time from + both resumed and previous elapsed time. + (sim_events_init): Set initial_wallclock and current_wallclock to + zero. + (sim_events_install): Install sim_events_suspend and + sim_events_resume. + (sim_events_watch_clock): Allow for suspended simulator when + computing the time of the clock event. + + * sim-events.h (struct _sim_event): Add resume_wallclock, rename + initial_wallclock to elapsed_wallclock, set both to zero. + (sim_events_init, sim_events_uninstall): Delete prototypes. + + * sim-module.h (MODULE_SUSPEND_FN, MODULE_RESUME_FN): Define types. + + * sim-module.c(sim_module_resume, sim_module_suspend): New + functions. + +Wed Sep 3 10:08:21 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-core.c (sim_core_map_attach): Clarify memory overlap error + message. + +Tue Sep 2 14:57:06 1997 Doug Evans <dje@canuck.cygnus.com> + + * Makefile.in (TAGS): Add support for "/* TAGS: foo */" marker. + * Make-common.in (TAGS): Likewise. + * sim-n-bits.h: Add TAGS comments for all functions. + * sim-n-core.h: Likewise. + * sim-n-endian.h: Likewise. + +Mon Sep 1 10:50:11 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-utils.c (sim_state_alloc): Set CPU backlinks, callback and + kind. + + * sim-base.h (sim_state_alloc): Add callback and kind arguments. + + * sim-base.h (INVALID_INSTRUCTION_ADDRESS): Add default + definition. + +Sat Aug 30 09:47:21 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-fpu.c (DP_GARDMSB, ...): Make unsigned. + (DP_FRACHIGH, DP_FRACHIGH2, ..): Use MSMASK to avoid LL. + +Fri Aug 29 13:37:44 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-core.c (sim_core_map_attach): Cast attach enum to int. + (sim_core_xor_read_buffer, sim_core_xor_write_buffer): Make + nr_transfered and nr_this_transfer unsigned. + + * sim-events.c (sim_events_tickn): N is signed, as limited to + MAXINT. + + * sim-n-endian.h (offset_N): Change size to unsigned. + + * callback.c (os_poll_quit): Add prototypes for kbhit and getkey. + +Fri Aug 29 10:10:53 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-utils.c (sim_copy_argv): Delete, replaced by dupargv. + + * sim-options.c (sim_parse_args): Use dupargv. + +Thu Aug 28 10:36:34 1997 Doug Evans <dje@canuck.cygnus.com> + + * sim-options.c (standard_option_handler): Use xstrdup, not strdup. + +Thu Aug 28 12:09:15 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-base.h (STATE_ARCHITECTURE, STATE_TARGET): Add to simulator + base type. + + * sim-options.c (standard_options): Add --architecture=MACHINE and + --target=TARGET options. + (OPTION_ARCHITECTURE, OPTION_TARGET): Define. + (standard_option_handler): Handle architecture and target options. + (bfd.h): Include. + + * sim-utils.c (sim_analyze_program): Pass STATE_TARGET to + bfd_openr. + (sim_analyze_program): Set prog_bfd architecture from + STATE_ARCHITECTURE if known. + +Wed Aug 27 18:13:22 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * configure: Regenerated to track ../common/aclocal.m4 changes. + * config.in: Ditto. + +Wed Aug 27 18:11:30 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * aclocal.m4 (enable-sim-warnings): Remove comment stating + that option does not apply to certain files. + +Wed Aug 27 15:13:04 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-bits.h (LSBIT8, LSBIT16, LSBIT32, LSBIT64, LSBIT, MSBIT8, + MSBIT16, MSBIT32, MSBIT64, MSBIT): New macros - single bit as + offset from MSB/LSB. + + * sim-endian.h (A1_8, A2_8, A4_8, A1_4, A2_4, A1_2): New macro, + access address of sub word quantity of a hosts 16, 32, 64 bit word + type. + (V1_2, V1_4, V2_4, V1_8, V2_8, V4_8): Ditto for values. + (U8_1, U8_2, U8_4, U4_1, U4_2, U2_1): Ditto for set of values. + (V2_H1, V2_L1, V4_H2, V4_L2, V8_L4, V8_H4): Given N byte argument, + return N*2 byte value with argument in Hi/Lo word. Renamed from + V1_H2, V1_L2, V2_H4, V2_L4, V4_H8, V4_L8. + + * sim-alu.h (ALU32_HAD_OVERFLOW): Use 64 bit mask not 32bit. + (ALU16_HAD_CARRY, ALU32_HAD_CARRY, ALU16_HAD_OVERFLOW): Use MSBIT + so that bit offset is explicit. + +Wed Aug 27 11:55:35 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-utils.c (sim_analyze_program): Add prog_name argument. + Update STATE_PROG_BFD when needed with a dup'd copy of the + program. + + * sim-config.c (sim_config): Delete ABFD argument, use + STATE_PROG_BFD directly. + +Tue Aug 26 12:55:26 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * run.c (main): Pass the open ABFD to sim_create_inferior. + + * nrun.c (main): Determine prog_bfd. Pass to sim_create_inferior + and sim_load. + (bfd.h): Include. + + * sim-hload.c (sim_load): New file. Implement generic sim_load for + hardware only simulator targets. + + * Make-common.in (sim-hload.o): Add rule. + +Wed Aug 27 09:51:42 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-utils.c (sim_copy_argv): Rewrite to match malloc strategy + used by copyargv and freeargv. + + * sim-options.c (sim_parse_args): Save a copy of PROG-ARGS in + STATE_PROG_ARGV, not just a pointer. + +Mon Aug 25 17:50:22 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * configure: Regenerated to track ../common/aclocal.m4 changes. + * config.in: Ditto. + +Mon Aug 25 12:11:06 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * aclocal.m4 (sim-endian): Add second argument to + SIM_AC_OPTION_ENDIAN. First is hardwired endian, second is + default endian when not hardwired. + + * sim-config.h (WITH_DEFAULT_TARGET_BYTE_ORDER): New macro, if all + else failes value for target byte order. + + * sim-config.c (sim_config): Add abfd arguments. Set + STATE_PROG_BFD accordingly. Determine prefered_target_byte_order + from same. + (sim_config): Return SIM_RC, don't abort. + (bfd.h): Include. + + * run.c (main): Update call to sim_open - add ABFD argument. + * nrun.c (main): Add NULL ABFD argument. + +Thu Aug 14 12:48:57 1997 Doug Evans <dje@canuck.cygnus.com> + + * callback.c (os_poll_quit): Make static. + Call sim_cb_eprintf, not p->eprintf. + (sim_cb_printf, sim_cb_eprintf): New functions. + * sim-utils.h (sim_cb_printf, sim_cb_eprintf): Declare. + + * sim-basics.h (zalloc,zfree,sim_add_commas,SIM_ELAPSED_TIME, + sim_elapsed_time_get,sim_elapsed_time_since): Move decls to + sim-utils.h. #include sim-utils.h. + * sim-utils.h: Above decls moved here. + (sim_analyze_program,sim_load_file): Use `struct _bfd', not `bfd'. + + * sim-watch.c (action_watchpoint): Fix thinkos. + +Thu Jul 24 08:48:05 1997 Stu Grossman (grossman@critters.cygnus.com) + + * sim-types.h: Fix defs of 64 bit data types for MSVC. + +Tue Jul 22 10:35:37 1997 Doug Evans <dje@canuck.cygnus.com> + + * sim-n-core.h (sim_core_write_unaligned_N): Add missing break + to FORCED_ALIGNMENT case. + +Thu Jun 5 13:48:37 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * callback.c (target_to_host_open): Handle hosts with O_BINARY. + +Thu Jun 5 08:47:10 1997 Jeffrey A Law (law@cygnus.com) + + * Make-common.in (libsim.a): Fix typo. + +Thu Jun 5 13:48:37 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * nrun.c (main): Verify the structure returned before using it. + +Wed Jun 4 11:44:06 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-config.h (WITH_ENGINE): Enable the sim-engine module by + default. + + * sim-engine.c (sim_engine_install): New function. Install the + engine init functions. + (sim_engine_init): [Re]initialize the simulator engine. + + * sim-module.c: Add sim_engine to list of modules that always + install. + +Tue Jun 3 04:52:04 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-watch.c (schedule_watchpoint): Use sim_unschedule_watchpoint + to remove the old watchpoint, not delete_watchpoint. + (watch_option_handler): Action the correct watchpoint, not just + cycles. + +Wed May 28 14:47:41 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-n-core.h (sim_core_write_aligned_N): For 8byte reads, output + both low and high word. + (sim_core_write_aligned_N): Ditto. + + * sim-trace.c (set_trace_options): Delete code explicitly setting + core->trace. + + * sim-options.c (sim_print_help): Call the list commands if not a + standalone simulator. + (sim_print_help): Advise that some options may not be applicable. + + * sim-trace.c (set_trace_options): Assume core present. + + * sim-events.c (sim_events_schedule_after_signal): Overflow signal + buffer when full not almost full. + +Tue May 27 14:32:00 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-events.c (sim_events_process): Don't blat the event queue + when processing watchpoints. + + * sim-watch.h: Make arg unsigned long - stop sign extension. + + * sim-events.c (sim_watch_valid): rewrite so debugable. + + * sim-config.h (WITH_XOR_ENDIAN): Default to zero. + + * sim-watch.c (schedule_watchpoint): Add is_within option so that + inequality test is possible. + (handle_watchpoint): Re-pass is_within arg. + (watch_option_handler): When `!' prefix to pc-watchpoint arg pass + 0 to schedule_watchpoint's is_within arg. + (sim_watchpoint_init): Re-pass is_within arg. + + * sim-options.c (sim_print_help): Add is_command argument. Don't + include -- prefix when called from the command line interpreter. + + * sim-watch.c (schedule_watchpoint): Pass true is_within argument. + + * sim-events.c (sim_events_watch_sim): Add is_within argument, + zero indicates that the test should be reversed. + (sim_events_watch_core): Ditto. + (WATCH_CORE): Compare range against is_within. + (WATCH_SIM): Ditto. + +Tue May 27 12:48:03 1997 Andrew Cagney <cagney@b2.cygnus.com> + + * sim-events.c (WATCH_CORE): Pass NULL cpu argument to + sim_core_read_buffer. Check nr-bytes transfered. + + * sim-core.h (sim_core_common): Define a new struct that contains + the common data. to sd and cpu structures. + * sim-core.c (sim_core_attach): Update. + (sim_core_init): Update. Remember to copy initialized data to each + cpu. + (sim_core_find_mapping): Ditto. + + * sim-core.c (sim_core_read_buffer): Add cpu argument. + (sim_core_write_buffer): Ditto. + + * sim-n-core.h (sim_core_read_unaligned_N): When mis-aligned + transfer use xor version of read buffer. + (sim_core_write_unaligned_N): Ditto for write. + + * sim-core.c (sim_core_xor_read_buffer): New function implement + xor-endian data read breaking transfer up into xor-endian sized + blocks. + (sim_core_xor_write_buffer): Ditto for write. + (reverse_n): Reverse order of arbitrary number of bytes in buffer + - needed for xor-endian transfers. + +Fri May 23 14:24:31 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-inline.h: Review description. + + * sim-core.h, sim-core.c: Reduce number of functions being inlined + to just those involved in data transfers and configuration. + + * sim-xcat.h (XSTRING): New macro, map macro definition onto + string. + * sim-n-core.h (sim_core_read_aligned_N): Use. + (sim_core_read_unaligned_N): Ditto. + (sim_core_read_unaligned_N): Ditto.. + (sim_core_write_unaligned_N): Ditto. + + * sim-core.h: Add xor endian bitmap to main structure. * + + sim-n-core.h (sim_core_write_aligned_N): Add suport for xor + endian. + (sim_core_read_aligned_N): Ditto. + + * sim-core.c (sim_core_set_xor_endian): New function. + (sim_core_attach): Don't overwrite the per-cpu xor map when + cloning the global core. + +Fri May 23 10:53:13 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-engine.h: Update below so that it is using an enumerated + type. + +Thu May 22 09:12:16 1997 Gavin Koch <gavin@cygnus.com> + + * sim-engine.c (sim_engine_restart): + * sim-resume.c (sim_resume): Change longjmp param/setjmp + return value used for simulator restart from 0 to 2. + +Wed May 21 08:47:30 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * cgen-scache.c (scache_option_handler): Add is_command arg. + + * sim-model.c (model_option_handler): Add is_command argument. + + * sim-profile.c (profile_option_handler): Add is_command arg. + + * sim-events.c (sim_watch_valid): Use ub64, lb64 when 64bit value + involved. + + * sim-module.c (sim_module_add_init_fn): Call init fn in the same + order that they are registered. + + * sim-options.h (OPTION_HANDLER): Add argument to differentiate + between option and command line processing. + + * sim-options.c: Include stdlib.h, ctype.h. + + * Make-common.in (sim-watch.o): Add rule. + (sim_main_headers): Assume sim-assert.h included. + (sim-*.o): Simplify make rule. + + * sim-module.c: Add sim_watch_install to module list. + +Tue May 20 14:15:23 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-base.h (STATE_LOADED_P): New predicate. Set once everything + has been loaded. + + * sim-trace.c (trace_install): Check magic. Include sim-assert.h. + * sim-events.c (sim_events_install): Ditto. + * sim-core.c (sim_core_install): Ditto. + * sim-model.c (model_install): Ditto. + * sim-options.c (standard_install): Ditto. + * sim-profile.c (profile_install): Ditto. + * sim-reason.c (sim_stop_reason): Ditto. + * sim-run.c (sim_engine_run): Ditto. + * sim-utils.c (sim_analyze_program): Ditto. + + * sim-module.c (modules): Make profile_install and trace_install + optional. + + * sim-base.h (STATE_MEM_BASE): Define for flat memory systems. + + * sim-options.c (standard_option_handler): Set the byte order. + + * sim-events.c (sim_events_process): Allow multi tick processing. + (sim_events_tickn): New function - multi cycle tick. + + * sim-events.h (sim_events_tickn, sim_events_timewarp): Add + prototypes. Under development. + (sim_events): Replace processing with nr_ticks_to_process. + +Tue May 20 09:39:22 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * nrun.c (main): Pass callbacks to sim_open instead of using + sim_set_callbacks. + + * run.c (main): Ditto. + +Mon May 19 12:07:22 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-events.c (sim_events_zalloc): Signal save memory allocator - + stop tk interrupting malloc calls. + (sim_events_zalloc): Converse. + + * Make-common.in (sim_main_headers): Add sim-events.h. + + * sim-events.c (sim_events_schedule_after_signal): Change return + type to void - signal events are strictly internal. + (sim_events_init): Allocate a finite buffer for signal events. + (sim_events_schedule_after_signal): Enter signal events into the + signal buffer. + + * sim-engine.c (sim_engine_halt): Check SIM_DESC magic. + (sim_engine_restart): Ditto. + (sim_engine_abort): Ditto. + * sim-stop.c (sim_stop): Ditto. + (control_c_simulation): Ditto. + * sim-resume.c (sim_resume): Ditto. + (has_stepped): Ditto. + * sim-abort.c (sim_engine_abort): Ditto. + + * sim-basics.h (transfer_type): New type. + + * sim-core.c (sim_core_signal): New function. Print core signal + information. + (sim_core_find_mapping): Add transfer argument. + + * sim-n-core.h (sim_core_{write,write}_unaligned_N): Call + SIM_CORE_SIGNAL if a recoverable abort. + * sim-core.c (sim_core_find_mapping): Ditto. + +Fri May 16 15:13:21 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-core.c (sim_core_find_mapping): Replace calls to + sim_io_error to more resiliant sim_engine_abort. + + * sim-n-core.h (sim_core_read_unaligned_N): Ditto. + (sim_core_write_unaligned_N): Ditto. + +Tue May 13 13:50:06 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-module.c: Add sim_events_install to list. + + * sim-events.c (sim_events_install, sim_events_uninstall): Clonse + from sim_core_*. + (sim_events_init): Now returns SIG_RC. + + * sim-run.c: New file. Generic sim_engine_run. + * sim-reason.c: New file. Generic sim_stop_reason. + * sim-stop.c: New file. Generic sim_stop. + * sim-resume.c: New file. Generic sim_resume. + + * Make-common.in (sim-engine.o): Add rule. + (sim-run.o, sim-reason.o, sim-stop.o, sim-resume.o): Ditto. + + * sim-engine.h, sim-engine.c: New file. Provide generic + implementation of sim_engine_halt, sim_engine_error. et.al. + + * sim-base.h (sim_state_base): Add member halt. + (sim-engine.h): Include. + + * sim-events.h (sim_event_handler): Always pass SIM_DESC to event + handlers. + * sim-events.c (sim_events_poll): Update event handler. + +Tue May 13 09:57:49 1997 Andrew Cagney <cagney@b2.cygnus.com> + + * sim-events.h, sim-events.c (sim_events_watch_clock): New + function. + (sim_events_watch_sim): New function. + (sim_events_watch_core): New function. + (sim_watch_valid): New function. + (sim_events_preprocess): New function. + (sim_events_process): Process the watchpoints as well as the timer + queue. + (sim_events_tick): Check WORK_PENDING instead of the hold queue. + (sim_events_deschedule): Check all the queues when removing an + event. + (sim_events_init): Ditto for cleaning. + +Mon May 19 12:07:22 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-fpu.c (is_ufpu_number): Comment out - currently unused. + +Mon May 19 11:23:03 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * callback.c (os_open): Type of arg flags is int. + +Fri May 16 22:26:43 1997 Michael Meissner <meissner@cygnus.com> + + * sim-fpu.c (sim_fpu_is_{eq,ne,lt,le,gt,ge}): Compare Infinities + just like normal numbers as per IEEE rules. + +Wed May 14 21:20:38 1997 Bob Manson <manson@charmed.cygnus.com> + + * callback.c (os_close): Mark the descriptor as being + available if the close succeeded. + (os_open): Pass 0644 as the mode of the file being created. + +Thu May 15 10:58:52 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-fpu.c (pack_fpu, unpack_fpu): New functions - decode a + float. + + * sim-inline.c (SIM_INLINE_C): Rename from _SIM_INLINE_C_. + * sim-lnline.h: Update. + + * sim-fpu.h, sim-fpu.c (sim_fpu_[iu]{32,64}to): New int2fp + conversion functions. + (sim_fpu_to{32,64}[iu]): New fp2int functions. + + * sim-fpu.h, sim-fpu.c (sim_fpu_is_{lt,le,eq,ne,ge,gt}): New fp + compare functions. Replacing. + (sim_fpu_cmp): This. Delete. + +Mon May 12 14:49:05 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-core.c (sim_core_find_mapping): Call engine_error not + sim_io_error when possible. + +Mon May 12 08:55:07 1997 Andrew Cagney <cagney@b2.cygnus.com> + + * sim-endian.h (V1_H2): Add macro's to insert a word into a + high/low double word. + + * sim-trace.h: Remove definition of attribute - defined in + sim_basics.h. + +Mon May 12 08:55:07 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-options.h (struct OPTION): Add doc_opt as the documenting + name of the option - or family of options. + + * sim-options.c (sim_args_command): Match command `a-b c' with + option `--a-b-c' from option table. + +Thu May 8 12:40:07 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-options.c (sim_print_help): For optional arguments, wrap + them in []. + + * sim-trace.c (set_trace_options): New function, handle optional + argument and multiple assignment. + (trace_option_handler): Update. + + * sim-trace.c (trace_option_handler): Trace branch and not fpu + when branch tracing selected. + +Wed May 7 15:19:58 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-trace.c (trace_one_insn): Make a va-args function. + + * sim-trace.c (trace_vprintf): New function, va-arg version of + trace_printf. + +Tue May 6 16:38:16 1997 Doug Evans <dje@canuck.cygnus.com> + + * sim-trace.c (trace_uninstall): Don't close a file twice. + * sim-profile.c (profile_uninstall): Likewise. + +Tue May 6 06:14:01 1997 Mike Meissner <meissner@cygnus.com> + + * sim-trace.c (toplevel): Include bfd.h. + (trace_options): Note that --trace-linenum also turns on + --trace-insn. Add --trace-{branch,semantics}. + (trace_option_handler): If --trace-linenum, also turn on + --trace-insn. Add --trace-branch support. If --trace-semantics, + turn on ALU, FPU, branch, and memory tracing. + (trace_one_insn): New function to trace an instruction. Support + --trace-linenum. + (OPTION_TRACE_*): Use an enum, rather than lots of defines. + + * sim-trace.h (TRACE_{SEMANTICS,BRANCH}_IDX): Add new macros. + (MAX_TRACE_VALUES): Use 32, not 12 by default. + (TRACE_branch): Add new mask. + (TRACE_*_P): Define all possible trace_p macros. + (trace_one_insn): Declare function. + +Mon May 5 14:08:34 1997 Mike Meissner <meissner@cygnus.com> + + * sim-trace.h (__attribute__): Define as nothing if not GNU C or + GNU C doesn't support __attributes__. + ({trace,debug}_printf): Add attribute's so -Wformat can check the + format strings. + +Mon May 5 11:16:12 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-config.h (FORCED_ALIGNMENT): New alignment option - + addresses are masked forcing them to be correctly aligned. + (WITH_ALIGNMENT): Make NONSTRICT_ALIGNMENT the default. + * sim-config.c (config_alignment_to_a): Update. + + * sim-core.h (sim_cpu_core): New data type contains cpu specific + core data. + * sim-base.h (CPU_CORE): Add cpu specific core data to cpu base + type. + * sim-core.c (sim_core_attach): Add CPU argument. Ready for + processor specific core maps. + (sim_core_map_attach): Copy the core map data to each of the + processor specific core data structures. + * sim-core.c (sim_core_find_mapping): Update. + + * sim-n-core.h (sim_core_read_N, sim_core_write_N): Rename. + (sim_core_write_aligned_N, sim_core_write_aligned_N): New names. + (sim_core_write_unaligned_N, sim_core_write_unaligned_N): New + alternatives that handle unaligned addresses. + (sim_core_{read,write}_{,un}aligned_N): Drop SIM_DESC arg, replace + with just CPU arg. + * cgen-utils.c (sim_disassemble_insn): Update. + +Mon May 5 13:19:16 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-trace.h (TRACE_FPU_IDX): Add Floating-point specific + tracing. + + * sim-fpu.h, sim-fpu.c: New files - prototype for generic target + fpu support. + + * sim-inline.h, sim-inline.c: Add support for SIM_FPU. + +Fri May 2 17:59:42 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-core.c (sim_core_map_to_str): New function ascii equivalent + to map type. + + * sim-n-core.h (sim_core_read_N, sim_core_write_N): Use in trace + statement. + +Fri May 2 17:28:02 1997 Andrew Cagney <cagney@b2.cygnus.com> + + * cgen-trace.c: Prepend additional trace_printf argument. + + * cgen-utils.c (sim_disassemble_insn): Add additional core + arguments. + +Fri May 2 11:40:23 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * nrun.c (main): Catch/report errorenous simulator states. + + * sim-module.c: #include "libiberty.h" so that xmalloc is defined. + * sim-trace.c: #include string.h/strings.h so that memset is + defined. + * sim-utils.c: Ditto. + * sim-profile.c: Ditto. And stdlib.h. + (print_bar): Only define when used by instruction or memory profiler. + + * sim-options.c (standard_option_handler): Make ul more local. + + * sim-load.c (sim_load_file): Make the name constant. + (sim_load_file): Passify gcc. + + * sim-utils.h: New file, pre-declare utilites in corresponding .c + file. + * sim-utils.c, sim-load.c: Include sim-utils.h. + + * sim-base.h (sim_cpu): Pre define here so available to all. + + * sim-core.h (DECLARE_SIM_CORE_WRITE_N, DECLARE_SIM_CORE_READ_N): + Restore the sim_cpu and instruction_address arguments so that full + information is available to the abort function. + * sim-core.c (sim_core_find_mapping, sim_core_write_buffer): Ditto. + * sim-n-core.h (sim_core_write_N, sim_core_read_N): Update. + + * sim-trace.h, sim-trace.c (trace_option_handler): Add interim + tracing support for sim-events and sim-core. + (trace_option_handler): Convert #if to if where possible so always + compiled/checked by C compiler. + * sim-n-core.h (sim_core_write_N, sim_core_read_N): Update. + + * sim-base.h: Adjust comment documenting how to define the cpu + structure. + (sim_state_base): Add sim_core and sim_events to simulator base + object. + + * sim-trace.h, sim-trace.c (trace_printf): Add SIM_DESC argument. + * sim-core.c (sim_core_init, sim_core_attach, + sim_core_find_mapping): Update. + * sim-events.c (ETRACE, sim_events_init, sim_events_time, + update_time_from_event, insert_sim_event, + sim_events_schedule_after_signal, sim_events_deschedule, + sim_events_tick): Ditto. + + * sim-basics.h (sim-module.h, sim-trace.h, sim-profile.h, + sim-model.h): Move #includes from here. + * sim-base.h: To here. + (sim-core.h, sim-events.h, sim-io.h): Include also + +Wed Apr 30 15:37:54 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * callback.c (default_callback): Missing initialisers. + +Thu May 1 10:40:47 1997 Doug Evans <dje@canuck.cygnus.com> + + * sim-utils.c (sim_add_commas): New function. + * sim-basics.h (sim_add_commas): Add prototype. + * cgen-scache.c (scache_print_profile): Print commas in numbers. + * sim-profile.c (COMMAS): New macro. + (print_*): Use it to print commas in numbers. + + * configure: Regenerated. + + * cgen-sim.h (sim_signal_type): Add SIM_SIGINT. + (cgen_state): New member run_fast_p. + (cgen_init): Add prototype. + (sim_disassemble_insn): New arg `cpu'. + * cgen-trace.c (trace_insn): Update call to sim_disassemble_insn. + * cgen-utils.c (cgen_init): New function. + (sim_disassemble_insn): New arg `cpu'. Rewrite fetching of insn. + * genmloop.sh: Call engine_halt if loop exits. + + * Makefile.in (sim-options_h): Define. + (sim-{module,options,trace,profile,utils}.o): Clean up dependencies. + (sim-model.o): Add new rule. + (cgen-{scache,trace,utils}.o): Add new rules. + * aclocal.m4 (SIM_AC_OPTION_{SCACHE,DEFAULT_MODEL}): Add. + * cgen-scache.c (scache_print_profile): Change `sd' arg to `cpu'. + Indent output by 2 spaces. + * cgen-scache.h (scache_print_profile): Update. + * cgen-trace.c (trace_insn_fini): Indent output by 2 spaces. + Use trace_printf, not fprintf. + (trace_extract): Use trace_printf, not cgen_trace_printf. + * genmloop.sh (!FAST case): Increment `insn_count'. + * sim-base.h (sim_state_base): Only include scache_size if WITH_SCACHE. + (sim_cpu_base): Rename member `sd' to `state' to be consistent with + access macro's name. + * sim-core.c (sim_core_init): Use EXTERN_SIM_CORE to define it. + Change return type to SIM_RC. + (sim_core_{install,uninstall}): New functions. + * sim-core.h (sim_core_{install,uninstall}): Declare. + (sim_core_init): Use EXTERN_SIM_CORE to define it. + Change return type to SIM_RC. + * sim-model.h (models,machs,model_install): Declare. + * sim-module.c (modules): Add scache_install, model_install. + (sim_post_argv_init): Set cpu->state backlinks. + * sim-options.c (standard_options): Delete --simcache-size,--max-insns. + (standard_option_handler): Likewise. + * sim-profile.c (PROFILE_{HISTOGRAM,LABEL}_WIDTH): Move to + sim-profile.h. + (*): Assume ANSI C. + (profile_options): Delete --profile-simcache. + (profile_option_handler): Likewise. + (profile_print_insn): Change `sd' arg to `cpu'. Indent output 2 + spaces. + (profile_print_{memory,model}): Likewise. + (profile_print_simcache): Delete. + (profile_print_speed): New function. + (profile_print): Rewrite. + * sim-profile.h (PROFILE_scache): Renamed from PROFILE_simcache. + (WITH_PROFILE_SCACHE_P): Renamed from WITH_PROFILE_SIMCACHE_P. + (PROFILE_DATA): Delete members simcache_{hits,misses}. + (PROFILE_COUNT_SIMCACHE_{HIT,MISS}): Delete. + (PROFILE_{CALLBACK,CPU_CALLBACK}): New types. + (profile_print): Update prototype. + +Wed Apr 30 11:34:14 1997 Doug Evans <dje@canuck.cygnus.com> + + * cgen-scache.[ch], cgen-sim.h: New files. + * cgen-trace.[ch], cgen-types.h, cgen-utils.c, genmloop.sh: New files. + * sim-model.c: New file. + + * Make-common.in (clean targets): Undo patch of Apr. 22. + +Fri Apr 25 15:28:32 1997 Mike Meissner <meissner@cygnus.com> + + * sim-n-bits.h (signed): If we have a standard compiler, undef + signed, so that signedN is defined correctly. + +Thu Apr 24 00:00:07 1997 Doug Evans <dje@canuck.cygnus.com> + + * sim-module.h, sim-model.h, sim-profile.h: New files. + * sim-module.c, sim-profile.c: New files. + * Make-common.in (SIM_PROFILE): Define + (CONFIG_CFLAGS): Add $(SIM_PROFILE). + (sim_main_headers): Add sim-module.h, sim-model.h, sim-profile.h. + (sim_module.o,sim-profile.o): Add rules for. + * aclocal.m4 (--enable-sim-trace): Allow symbolic arguments. + (--enable-sim-profile): Add. + * configure: Regenerated. + * sim-base.h (sim_state_base): New members init_list, uninstall_list, + model. Move trace and profile support to sim-{trace,profile}.h. + New members trace_data, profile_data. + * sim-basics.h: #include sim-module.h, sim-model.h, sim-profile.h. + * sim-config.h: Provide default definition of WITH_PROFILE. + (WITH_TRACE): Change default to -1. + (MAX_NR_PROCESSORS): Always define. + * sim-options.c: Move trace and profile support to + sim-{trace,profile}.h. + (sim_pre_argv_init): Moved to sim-model.c. + (standard_install): New function. + * sim-options.h (sim_pre_argv_init): Move decl to sim-model.c. + (standard_install): Declare. + * sim-trace.c: Tracing option handling moved here from sim-options.c. + (trace_install, trace_uninstall): New functions. + (trace_printf): Update reference to TRACE_FILE. + * sim-trace.h (TRACE_FOO_IDX): Moved here from sim-base.h. + (TRACE_foo): Bit masks for symbolic arguments to --enable-sim-trace. + (WITH_TRACE_FOO_P): Define. + (trace_install): Declare. + (TRACE_DATA): New struct. + +Wed Apr 23 17:23:15 1997 Doug Evans <dje@canuck.cygnus.com> + + * run.c: Undo last exec_bfd patch. + (main): Only pass -E ifdef SIM_HAVE_BIENDIAN. + +Wed Apr 23 17:54:27 1997 Mike Meissner <meissner@cygnus.com> + + * run.c (exec_bfd): Add back in. + (main): Set exec_bfd. + +Tue Apr 22 14:43:46 1997 Doug Evans <dje@canuck.cygnus.com> + + * sim-load.c (sim_load_file): #include <stdio.h> for NULL. + +Wed Apr 23 02:55:54 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-events.c (insert_sim_event): Call sim_io_error instead of + less well defined engine_error. + * sim-core.c: Ditto. + +Tue Apr 22 08:48:16 1997 Stu Grossman (grossman@critters.cygnus.com) + + * Make-common.in: Change clean targets to use :: so that other + Makefiles can have their own clean targets. + * sim-load.c (xprintf eprintf): Use ANSI_PROTOTYPES instead of + __STDC__ to control use of stdarg vs. varargs syntax. Some + systems can't use __STDC__, but require stdarg. + +Fri Apr 18 11:14:43 1997 Doug Evans <dje@canuck.cygnus.com> + + * sim-options.c (standard_options): Add --endian. + (standard_option_handler): Likewise. + + * nrun.c: #include <signal.h>. + (main, cntrl_c): Wrap calls to sim_resume in a SIGINT + handler that calls sim_stop (). + +Fri Apr 18 13:11:36 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * run.c (main, cntrl_c): Wrap calls to sim_resume in a SIGINT + handler that calls sim_stop (). Simulators may still be + establishing their own handler. + + * sim-events.c (sim_events_poll): Rename from + sim_events_at_large_int. Poll IO. + + * sim-io.c (sim_io_poll_quit): New function - pass on a polling + request. + + * callback.c (os_poll_quit): New function poll for quit signal + where needed. + (default_callback): Include magic number. + +Thu Apr 17 02:25:11 1997 Doug Evans <dje@canuck.cygnus.com> + + * aclocal.m4: Check for headers time.h, sys/time.h, sys/resource.h. + Check for functions getrusage, time. + * sim-basics.h (SIM_ELAPSED_TIME): New typedef. + (sim_elapsed_time_get, sim_elapsed_time_since): Add prototypes. + * sim-utils.c: #include time.h, sys/time.h, sys/resource.h if able. + (sim_elapsed_time_get, sim_elapsed_time_since): New functions. + + * sim-utils.c (sim_copy_argv, sim_analyze_program): New functions. + + * sim-options.c, sim-options.h: New files. + * sim-config.h (WITH_DEBUG): Provide default value of zero. + * Make-common.in (nrun.o): Add rules for. + * nrun.c: New file. + + * run.c (main): Check return value of sim_open. + + * Make-common.in (sim-options.o, sim-load.o, sim-trace.o): Add rules. + (sim_main_headers): Add sim-trace.h. + * run.c (exec_bfd, target_byte_order): Delete. + (main): Pass -E <endian> to sim_open. Delete code to load sections, + call sim_load instead. Check return code of sim_create_inferior. + * sim-base.h (CURRENT_STATE): Define. + (sim_state_base): Make typedef. New members options, prog_argv, + prog_bfd, text_{section,start,end}, start_addr, simcache_size, + mem_size, memory [+ corresponding access macros]. + (sim_cpu_base): New typedef. + * sim-trace.h: New file. + * sim-trace.c: New file. + * sim-basics.h: #include it. + * sim-load.c: New file. + +Tue Apr 15 15:10:13 1997 Ian Lance Taylor <ian@cygnus.com> + + * Make-common.in (INSTALL): Set to @INSTALL@. + (INSTALL_XFORM, INSTALL_XFORM1): Remove. + (install-common): Depend upon installdirs. Use + $(program_transform_name) directly, rather than using + $(INSTALL_XFORM). + (installdirs): New target. + * Makefile.in (INSTALL): Set to @INSTALL@. + (INSTALL_XFORM, INSTALL_XFORM1): Remove. + (install-man): Depend upon installdirs. Use + $(program_transform_name) directly, rather than using + $(INSTALL_XFORM). + (installdirs): New target. + +Tue Apr 15 15:08:12 1997 Andrew Cagney <cagney@b1.cygnus.com> + + * sim-assert.h (SIM_ASSERT, ASSERT): Allow these macros to + be overriden. + +Wed Apr 9 16:06:44 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * sim-basics.h: Only bring in config.h and tconfig.h if + HAVE_CONFIG_H. + +Mon Apr 7 11:39:45 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * sim-config.h (WITH_TARGET_WORD_MSB): New Macro. Define the bit + numbering convention of the target. + * sim-config.c (print_sim_config): Print WITH_TARGET_WORD_BITSIZE + and WITH_TARGET_WORD_MSB. + (sim_config): When possible, check for consistency with bitsize + and msb. + + * sim-bits.h: Allow MSB to be other than zero. + * sim-bits.c: Ditto. + * sim-n-bits.h: Ditto. + + * sim-bits.h (MSMASK*): New macros - converce to LSMASK*. + * sim-n-bits.h (MSMASKEDn): Ditto. + +Mon Apr 14 16:29:21 1997 Ian Lance Taylor <ian@cygnus.com> + + * Makefile.in (INSTALL): Change install.sh to install-sh. + +Mon Apr 7 10:46:38 1997 Doug Evans <dje@canuck.cygnus.com> + + * sim-base.h (sim_state_base): Move `magic' to end of struct. + +Mon Apr 7 15:53:21 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * run.c (main): Check that a program to run was specified. + +Mon Apr 7 15:45:02 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * aclocal.m4 (AC_TYPE_SIGNAL): Add check. + + * configure: Regenerated to track ../common/aclocal.m4 changes. + * config.in: Ditto. + +Wed Apr 2 15:06:28 1997 Doug Evans <dje@canuck.cygnus.com> + + * sim-endian.h: Move host {LITTLE,BIG}_ENDIAN support from here, + * sim-config.h: To here. + + * Make-common.in (SIM_EXTRA_DEPS): New config var. + (sim_main_headers): Define. + (sim-*.o): Depend on $(SIM_EXTRA_DEPS). + (BUILT_SRC_FROM_COMMON): Move here from ../d30v/Makefile.in. + (clean): Use it. + (sim-utils.o): Add rule for. + * sim-utils.o: New file. + * sim-basics.h: #include sim-base.h. + (zalloc): Make argument unsigned long. + * sim-base.h: New file. + * sim-inline.h (SIM_IO support): Delete. + * sim-io.h: Delete inline support. + * sim-io.c: Likewise. sim-state.h renamed to sim-main.h. + * sim-config.c: sim-state.h renamed to sim-main.h. + * sim-core.c: Likewise. + * sim-events.c: Likewise. + + * run.c (main): Pass SIM_OPEN_STANDALONE to sim_open. + + * aclocal.m4: Check for stdlib.h, string.h, strings.h, unistd.h. + (sim-debug): Allow arguments. Define WITH_DEBUG in addition to + -DDEBUG. + * configure: Regenerated to track ../common/aclocal.m4 changes. + +Wed Apr 2 14:34:19 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * configure: Regenerated to track ../common/aclocal.m4 changes. + +Wed Apr 2 11:08:11 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * sim-config.h (WITH_ALIGNMENT, WITH_FLOATING_POINT, + WITH_XOR_ENDIAN, WITH_SMP, WITH_RESERVED_BITS): Assume that these + are defined by the configure. + + * aclocal.m4 (sim-stdio): Add option stdio from ../ppc configure. + + * aclocal.m4 (floating-point, xor-endian, alignment, smp, + reserved-bits): Always define. + + * sim-config.h, sim-config.c (sim_config): New function - and new + file - co-ordinate the setting/checking of the common simulator + configuration options. + + * Make-common.in (sim-config.o): Add rule. + +Fri Mar 28 15:32:00 1997 Mike Meissner <meissner@cygnus.com> + + * callback.c (os_{,e}vprintf_filtered): Change stdarg type to + va_list from void *, since va_list might not be a pointer type. + +Mon Mar 24 15:27:12 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * sim-n-endian.h (offset_N): Correct assertion - word and sub word + in wrong order. + (offset_N): Correct computation of LE offset. + + * sim-io.c (sim_io_error): Include a new line when reporting + errors. + + * sim-assert.h (SIM_FILTER_PATH): Out by one when locating last + `/'. + +Thu Mar 20 22:31:06 1997 Jeffrey A Law (law@cygnus.com) + + * run.c: Include alloca-conf.h. + + * callback.c (os_evprintf_filtered): Fix typo. + +Fri Mar 21 13:36:20 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * run.c (string.h, strings.h, stdlib.h): Include. + + * sim-events.c (sim_events_tick): Recent cleanup failed to return + 0 when nothing pending. + + * run.c (sim_size, sim_trace): Plicate GCC - these two functions + will soon be going away. + (getopt): Plicate GCC. + + * sim-endian.c (sim-io.h): Plicate GCC. + * sim-bits.c (sim-io.h): Ditto. + * sim-n-bits.h (ROTn): Ditto. + + * sim-io.c (sim_io_error): Correct check for NULL. + + * sim-assert.h (SIM_FILTER_PATH): Separate out the code filtering + the __FILE__. + * sim-events.c: Use SIM_FILTER_PATH to filter out the filename + path. + +Wed Mar 19 01:12:06 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * aclocal.m4 (SIM_AC_OPTION_*: Move so that they are outside of + SIM_AC_COMMON - SIM_AC_COMMON was gobling arguments. + +Tue Mar 18 20:48:12 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * sim-alu.h: Include sim-xcat.h. + +Tue Mar 18 13:58:18 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * Make-common.in (sim-bits.c, sim-core.c, sim-endian.c, + sim-events.c, sim-inline.c, sim-io.c): Define rules for building + these. + + * sim-events.c (sim_events_at_large_int): New function. Just + schedules an event every large-int ticks. + (sim_events_init): Call. + (sim_events_tick, sim_events_process): Move async handing to + sim_events_process. Move timer decrement so that it occures after + events have been processed. + + * sim-basics.h (struct _engine): Remove declaration. + + * sim-events.h, sim-events.c: Rename type to sim_events. Prefix + everything with same. Rename global struct to SIM_DESC. + * sim-core.h, sim-core.c, sim-n-core.c: Ditto for sim_core. + * sim-io.h, sim-io.c: Ditto. + + * sim-assert.h: New file. Optional assertion checking macros. + * sim-io.c (sim_io_error): Make just this function tolerant to + null pointers. + + * sim-xcat.h: New file. Define concatenate macros. + * sim-basics.h (XCONCAT*): Move to sim-xcat.h. + * sim-n-core.h, sim-n-bits.h, sim-n-endian.h: Explicitly include + concat macros. + + +Tue Mar 18 12:44:55 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * sim-bits.h (LSMASK): New macro. Create mask of LS bits. + +Mon Mar 17 18:10:05 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * sim-inline.h: Add definitions for sim-types. + (ALL_BY_MODULE): New macro, encapsulate full inlining by the + module. + +Mon Mar 17 15:38:27 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * sim-events.h: Remove defunct reference to callback struct. + +Mon Mar 17 15:10:07 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * configure: Re-generate. + +Mon Mar 17 15:04:47 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * Make-common.in (CSEARCH): Do not include the gdb directory in + the search path. + +Mon Mar 17 13:16:26 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * Make-common.in (SIM_ENDIAN, SIM_HOSTENDIAN, SIM_INLINE, + SIM_WARNING): Drop, requiring the simulator specific Makefile.in + to explicitly incorporate these. + + * aclocal.m4 (--enable-sim-alignment); New option. Strongly + specify the alignment restrictions of the target architecture - + without this option all alignment restrictions are accomodated. + (--enable-sim-assert): New option. Conditionally compile in + assertion statements. + (--enable-sim-float): New option. Strongly specify the target's + floating point support. + (--enable-sim-hardware): New option. Specify the hardware devices + included in the simulation. + (--enable-sim-packages): New option. Specify the hardware + packages included in the simulation. + (--enable-sim-regparm): New option. Specify that parameters be + passed in registers instead of on the stack. + (--enable-sim-reserved-bits): New option. Specify that reserved + bits within an instruction are are correctly set. + (--enable-sim-smp): New option. Specify the level of SMP support + to be included in the simulator. + (--enable-sim-stdcall): New option. Specify an alternative + function call convention. + (--enable-sim-xor-endian): New option. Configure xor-endian + support used by some targets to implement bi-endian support. + +Fri Mar 14 19:51:21 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * aclocal.m4 (--enable-sim-hostendian): New option. Allow the + host endianness to be overridden. + (--enable-sim-endian): Allow the target platform's byte order + to be overridden. + (--enable-sim-inline): Control the inlining of common components. + (--enable-sim-bswap): For compatibility, also define WITH_BSWAP. + (--enable-sim-warnings): Enable additional GCC compiler checks. + * Make-common.in (SIM_ENDIAN, SIM_HOSTENDIAN, SIM_INLINE, + SIM_WARNINGS): Add. + + * sim-n-core.h, sim-n-bits.h, sim-n-endian.h: Rename from + sim-*-n.h so that the names are uniq on dos machines + * sim-core.c, sim-bits.c, sim-endian.c: Update. + +Thu Mar 13 12:32:42 1997 Doug Evans <dje@canuck.cygnus.com> + + * run.c: #include "libiberty.h". + (main): New locals sd,no_args,sim_argv. + Run buildargv on -a option. Pass argv to sim_open, argv[0] + is program name. Update call to sim_set_callbacks. + Record result of sim_open, pass to other sim_foo routines. + +Thu Mar 13 10:24:05 1997 Michael Meissner <meissner@cygnus.com> + + * callback.c (os_printf_filtered): Do not call exit(1) or print a + final newline. + +Thu Mar 6 15:50:28 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * callback.c: Add os_flush_stdout and vprintf_filtered callbacks. + Route stdout through buffered IO. + + * callback.c: Add os_flush_stderr, os_write_stderr, + os_evprintf_filtered functions to route error output through + stderr. + + * sim-io.h, sim-io.c (sim_io_flush_stderr, sim_io_flush_stdout): + Correct return type - should be void. + +Fri Mar 7 20:14:37 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * sim-basics.h: Clean up. Many macro's moved to sim-inline.h. + + * sim-config.h: Ditto. For some options - eg WITH_DEVICES - do + not provide a default value as undefined indicates disable code. + +Thu Mar 6 15:50:28 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * sim-core.h, sim-core-n.h, sim-core.c: Borrow code from ppc + directory. + * sim-events.h, sim-events.c: Ditto. + * sim-io.h, sim-io.c: Ditto. + +Tue Mar 4 09:35:56 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * sim-alu.h (ALU_SUB_CA, ALU*_SUB_CA): New alu operation. + + * sim-bits.h, sim-bits-n.h, sim-bits.c (LSMASKED*): New macro's + extract the tail or least signifiant bits from an integer of the + specified size. + + * sim-bits.h, sim-bits.c: Clean up conditionally compiled #if + WITH_TARGET_BITSIZE so that the compilation will fail when an + unsupported bitsize value is defined. + + (INSERTED*): Convert to functions. + (EXTRACTED*): Ditto. + + (SIGN_EXTEND, SEXT): Change to more terse name. + +Tue Mar 4 09:35:56 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * sim-inline.h: Allow explicit control over which .c files will be + included by their header. + + * sim-inline.h: Allow explicit control over which .c files use the + alternative - REGPARM - parameter passing mechanism. + + * sim-inline.h, sim-inline.c: Don't attempt to include any of + icache.c, idecode.c, semantics.c or support.c. Those names are + not generally applicable. + +Thu Feb 27 10:17:23 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * sim-bits.c, sim-bits-n.h (new): Split sim-bits.c into two parts + in a fashion similar to sim-endian-n. + + * sim-endian.h: (H_word, L_word, AL_*, VL_*): Extend to include + both value and address macro's. + +Tue Feb 25 18:51:57 1997 Andrew Cagney <cagney@kremvax.cygnus.com> + + * sim-alu.h (ALU16_BEGIN, ALU16_SET, ...): Fill in. + + * sim-endian.h (L_word, H_word): Replace MS2W_4, LS2W_4 with more + generic L_word, H_word macro's. + +Thu Feb 20 18:36:55 1997 Andrew Cagney <cagney@critters.cygnus.com> + + * sim-basics.h: Borrow code from ppc directory. + * sim-bits.c: Ditto. + * sim-bits.h: Ditto. + * sim-config.h: Ditto. + * sim-endian-n.h: Ditto. + * sim-endian.c: Ditto. + * sim-endian.h: Ditto. + * sim-inline.c: Ditto. + * sim-inline.h: Ditto. + * sim-types.h: Ditto. + +Wed Feb 19 12:40:50 1997 Andrew Cagney <cagney@critters.cygnus.com> + + * sim-alu.h (ALU_SET16, ALU_SET32, ALU_SET64, etc): Make available + all the ALU size alternatives and then auto-configure a default. + + * sim-alu.h: Copy ppc/idecode_expression.h. + +Mon Feb 17 10:44:18 1997 Andrew Cagney <cagney@critters.cygnus.com> + + * bits.h, bits.c (SIGN_EXTEND32, SIGN_EXTEND64): New functions, + sign extend a bit within a value. + + * sim-endian.h, sim-endian-n.h (offset_N): New functions - return + a pointer into the middle of a host word. + * sim-endian.h (MS2W_4, LS2W_4): Use this function. + +Tue Feb 11 13:46:49 1997 Michael Meissner <meissner@tiktok.cygnus.com> + + * callback.c: If HAVE_CONFIG_H is defined, include config.h from + autoconf. If HAVE_UNISTD_H is defined, include unistd.h to get + appropriate definitions of read, write, etc. Add prototype for + system. + +Tue Feb 4 13:24:44 1997 Doug Evans <dje@canuck.cygnus.com> + + * Makefile.in (libcommon.a): Delete. + (callback.o,targ-map.o): Delete, moved to Make-common.in. + (gentmap,targ-vals.h,targ-map.c): Likewise. + (run-autoconf): Delete. + * aclocal.m4 (SIM_AC_OUTPUT): Redo creation of Makefile. + (common makefile fragment): Moved back into ... + * Make-common.in: Resurrect. + * configure.in (AC_LINK_FILES): Delete, unnecessary now. + * configure: Regenerated. + +Fri Jan 31 07:16:49 1997 Doug Evans <dje@canuck.cygnus.com> + + * aclocal.m4 (SIM_AC_COMMON): Move COMMON_MAKEFILE_FRAG from here. + (SIM_AC_OUTPUT): To here. + +Fri Jan 24 10:37:17 1997 Stu Grossman (grossman@critters.cygnus.com) + + * aclocal.m4 (COMMON_MAKEFILE_FRAG): Quote a couple of $'s in + comments and single quotes. Fixes a problem found on hpux. + +Thu Jan 23 13:35:03 1997 Stu Grossman (grossman@critters.cygnus.com) + + * aclocal.m4: Remove Make-common.in from dependencies. + * (distclean): Remove targ-vals.def. + + * aclocal.m4 (SIM_AC_COMMON): Move contents of Make-common.in + into here. Makes insertion into makefiles easier. Also, change + the way that callback.o, gentmap, targ-vals.h, targ-map.c, + targ-map.o, and run are built. They are now built in the + individual simulator directories, taking sources from ../common as + necessary. This replaces the merging of libcommon.a into + linsim.a, which was problematic for the WinGDB build process. + * run.c: Include config.h from . instead of ../common. + * Make-common.in: Remove. It's no longer necessary. + +Mon Dec 16 15:02:33 1996 Ian Lance Taylor <ian@cygnus.com> + + * Make-common.in (ALL_CLAGS): Put CFLAGS at the end. + (.c.o): Put $(ALL_CFLAGS) before the file being compiled. + +Wed Dec 11 11:30:58 1996 Jim Wilson <wilson@cygnus.com> + + * run.c (main): Set target_byte_order before call to sim_open. + +Sun Dec 8 18:22:06 1996 Doug Evans <dje@canuck.cygnus.com> + + * callback.c: #include <stdlib.h> + (os_error): New function. + (default_callback): Add os_error. + +Mon Nov 25 19:44:35 1996 Doug Evans <dje@canuck.cygnus.com> + + * Make-common.in (Makefile): Set CONFIG_HEADERS="". + * aclocal.m4: Mark the fact that --enable-sim-bswap isn't host + specific. + (SIM_AC_OUTPUT): Don't build Makefile if CONFIG_FILES="". + +Wed Nov 20 01:11:04 1996 Doug Evans <dje@canuck.cygnus.com> + + * run.c: #include ../common/config.h, tconfig.h. + (myname): New static global. + (main): Recognize new options -a, -c. Also recognize -h if h8/300. + Only process -c ifdef SIM_HAVE_SIMCACHE. + Only process -p/-s ifdef SIM_HAVE_PROFILE. + Parse program name from argv[0] and use in error messages. + Pass sim_args to sim_open. Pass prog_args to sim_create_inferior. + Add support for incomplete h8/300 termination indicators. + (usage): Make more verbose. + * aclocal.m4,config.in,tconfig.in,configure.in,configure: New files. + * Makefile.in,Make-common.in,callback.c: New files. + * nltvals.def,gentmap.c,gentvals.sh: New files. + +Tue Nov 12 13:34:00 1996 Dawn Perchik <dawn@cygnus.com> + + * run.c: Include stdarg.h if __STDC__. + +Tue Oct 15 11:16:31 1996 Jeffrey A Law (law@cygnus.com) + + * run.c (main): Don't print out anything if the signal + number is zero (ie no signal). + +Tue Oct 15 11:20:44 1996 Michael Meissner <meissner@tiktok.cygnus.com> + + * run.c (main): Print out if the program raised a signal. + +Wed Sep 18 09:52:14 1996 Michael Meissner <meissner@tiktok.cygnus.com> + + * run.c (exec_bfd): Rename from sim_bfd, to use the gdb name. + (main): Ditto. + +Tue Sep 17 11:04:50 1996 James G. Smith <jsmith@cygnus.co.uk> + + * run.c (main): Explicitly cast malloc() parameter. + +Thu Sep 12 11:27:21 1996 Michael Meissner <meissner@tiktok.cygnus.com> + + * run.c (sim_bfd): New global to hold the bfd pointer for the + executable. + (main): Initialize sim_bfd. + +Fri Dec 15 16:27:49 1995 Ian Lance Taylor <ian@cygnus.com> + + * run.c (main): Use new bfd_big_endian macro. + +Wed Nov 8 15:49:49 1995 James G. Smith <jsmith@pasanda.cygnus.co.uk> + + * run.c (main): Removed SH specific comments, so source is + generic. Also updated to only load relevant sections. Moved + sim_open() to after callback attach (to match GDB). + + * run.1: Removed SH specific comments. + +Sat Oct 21 12:31:01 1995 Jim Wilson <wilson@chestnut.cygnus.com> + + * run.c (main): Always return sigrc at end. + +Tue Oct 10 12:03:13 1995 J.T. Conklin <jtc@rtl.cygnus.com> + + * run.c (main): Print error diagnostic and exit if bfd_openr() or + bfd_check_format() fails. + +Thu Sep 28 15:40:36 1995 steve chamberlain <sac@slash.cygnus.com> + + * run.c, run.1: From sh directory. diff --git a/sim/common/Make-common.in b/sim/common/Make-common.in new file mode 100644 index 0000000..71b4f69 --- /dev/null +++ b/sim/common/Make-common.in @@ -0,0 +1,642 @@ +# Makefile fragment for common parts of all simulators. +# Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc. +# Contributed by Cygnus Support. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# This Makefile fragment consists of two separate parts. +# They are merged into the final Makefile at points denoted by +# "## COMMON_PRE_CONFIG_FRAG" and "## COMMON_POST_CONFIG_FRAG". +# +# The target Makefile should look like: +# +#># Copyright blah blah +#> +#>## COMMON_PRE_CONFIG_FRAG +#> +#># Any overrides necessary for the SIM_FOO config vars. +#>SIM_FOO = ... +#> +#>## COMMON_POST_CONFIG_FRAG +#> +#># Rules to build target specific .o's. + +## COMMON_PRE_CONFIG_FRAG + +VPATH = @srcdir@ +srcdir = @srcdir@ +srccom = $(srcdir)/../common +srcroot = $(srcdir)/../.. + +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +host_alias = @host_alias@ +target_alias = @target_alias@ +program_transform_name = @program_transform_name@ +bindir = @bindir@ + +libdir = @libdir@ +tooldir = $(libdir)/$(target_alias) + +datadir = @datadir@ +mandir = @mandir@ +man1dir = $(mandir)/man1 +infodir = @infodir@ +includedir = @includedir@ + +# This can be referenced by the gettext configuration code. +top_builddir = .. + +EXEEXT = @EXEEXT@ +SHELL = @SHELL@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +CC = @CC@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +CFLAGS = @CFLAGS@ +SIM_BSWAP = @sim_bswap@ +SIM_CFLAGS = @sim_cflags@ +SIM_DEBUG = @sim_debug@ +SIM_TRACE = @sim_trace@ +SIM_PROFILE = @sim_profile@ + +SIM_ASSERT = @sim_assert@ +SIM_ALIGNMENT = @sim_alignment@ +SIM_BITSIZE = @sim_bitsize@ +SIM_DEFAULT_MODEL = @sim_default_model@ +SIM_ENDIAN = @sim_endian@ +SIM_ENVIRONMENT = @sim_environment@ +SIM_FLOAT = @sim_float@ +SIM_HW_CFLAGS = @sim_hw_cflags@ +SIM_HW_OBJS = @sim_hw_objs@ +SIM_HW = @sim_hw@ +SIM_HOSTENDIAN = @sim_hostendian@ +SIM_INLINE = @sim_inline@ +SIM_PACKAGES = @sim_packages@ +SIM_REGPARM = @sim_regparm@ +SIM_RESERVED_BITS = @sim_reserved_bits@ +SIM_SCACHE = @sim_scache@ +SIM_SMP = @sim_smp@ +SIM_STDCALL = @sim_stdcall@ +SIM_WARNINGS = @build_warnings@ +SIM_XOR_ENDIAN = @sim_xor_endian@ + +HDEFINES = @HDEFINES@ +TDEFINES = + +AR = @AR@ +AR_FLAGS = rc +RANLIB = @RANLIB@ +MAKEINFO = makeinfo + +DEP = $(srcroot)/mkdep + +# Each simulator's Makefile.in defines one or more of these variables +# to override our settings as necessary. There is no need to define these +# in the simulator's Makefile.in if one is using the default value. In fact +# it's preferable not to. + +# List of object files, less common parts. +SIM_OBJS = +# List of extra dependencies. +# Generally this consists of simulator specific files included by sim-main.h. +SIM_EXTRA_DEPS = +# List of flags to always pass to $(CC). +SIM_EXTRA_CFLAGS = +# List of extra libraries to link with. +SIM_EXTRA_LIBS = +# List of extra program dependencies. +SIM_EXTRA_LIBDEPS = +# List of main object files for `run'. +SIM_RUN_OBJS = run.o +# Dependency of `all' to build any extra files. +SIM_EXTRA_ALL = +# Dependency of `install' to install any extra files. +SIM_EXTRA_INSTALL = +# Dependency of `clean' to clean any extra files. +SIM_EXTRA_CLEAN = + +# Every time a new general purpose source file was added every target's +# Makefile.in needed to be updated to include the file in SIM_OBJS. +# This doesn't scale. +# This variable specifies all the generic stuff common to the newer simulators. +# Things like sim-reason.o can't go here as the cpu may provide its own +# (though hopefully in time that won't be so). Things like sim-bits.o can go +# here. Some files are used by all simulators (e.g. callback.o). +# Those files are specified in LIB_OBJS below. + +SIM_COMMON_HW_OBJS = \ + hw-alloc.o \ + hw-base.o \ + hw-device.o \ + hw-events.o \ + hw-handles.o \ + hw-instances.o \ + hw-ports.o \ + hw-properties.o \ + hw-tree.o \ + sim-hw.o \ + +SIM_NEW_COMMON_OBJS = \ + sim-arange.o \ + sim-bits.o \ + sim-break.o \ + sim-config.o \ + sim-core.o \ + sim-endian.o \ + sim-events.o \ + sim-fpu.o \ + sim-io.o \ + sim-info.o \ + sim-load.o \ + sim-memopt.o \ + sim-module.o \ + sim-options.o \ + sim-profile.o \ + sim-signal.o \ + sim-trace.o \ + sim-utils.o \ + sim-watch.o \ + \ + $(SIM_HW_OBJS) \ + +# Add this to SIM_EXTRA_DEPS. +CGEN_INCLUDE_DEPS = \ + $(srccom)/cgen-cpu.h \ + $(srccom)/cgen-defs.h \ + $(srccom)/cgen-engine.h \ + $(srccom)/cgen-scache.h \ + $(srccom)/cgen-sim.h \ + $(srccom)/cgen-trace.h \ + $(srccom)/cgen-types.h \ + $(srcdir)/../../include/opcode/cgen.h + +## End COMMON_PRE_CONFIG_FRAG + +## COMMON_POST_CONFIG_FRAG + +CONFIG_CFLAGS = \ + @DEFS@ \ + $(SIM_CFLAGS) \ + $(SIM_DEBUG) \ + $(SIM_DEFAULT_MODEL) \ + $(SIM_TRACE) \ + $(SIM_PROFILE) \ + $(SIM_BSWAP) \ + $(SIM_ASSERT) \ + $(SIM_ALIGNMENT) \ + $(SIM_BITSIZE) \ + $(SIM_ENDIAN) \ + $(SIM_ENVIRONMENT) \ + $(SIM_FLOAT) \ + $(SIM_HW_CFLAGS) \ + $(SIM_HOSTENDIAN) \ + $(SIM_INLINE) \ + $(SIM_PACKAGES) \ + $(SIM_REGPARM) \ + $(SIM_RESERVED_BITS) \ + $(SIM_SCACHE) \ + $(SIM_SMP) \ + $(SIM_STDCALL) \ + $(SIM_WARNINGS) \ + $(SIM_XOR_ENDIAN) \ + $(SIM_HARDWARE) \ + $(SIM_EXTRA_CFLAGS) \ + $(HDEFINES) $(TDEFINES) +CSEARCH = -I. -I$(srcdir) -I../common -I$(srccom) \ + -I../../include -I$(srcroot)/include \ + -I../../bfd -I$(srcroot)/bfd \ + -I../../opcodes -I$(srcroot)/opcodes \ + -I../../intl -I$(srcroot)/intl +ALL_CFLAGS = $(CONFIG_CFLAGS) $(CSEARCH) $(CFLAGS) +BUILD_CFLAGS = -g -O $(CSEARCH) + +COMMON_DEP_CFLAGS = $(CONFIG_CFLAGS) $(CSEARCH) + +LIBIBERTY_LIB = ../../libiberty/libiberty.a +BFD_LIB = ../../bfd/libbfd.a +OPCODES_LIB = ../../opcodes/libopcodes.a +INTLLIBS = @INTLLIBS@ +INTLDEPS = @INTLDEPS@ +CONFIG_LIBS = @LIBS@ +LIBDEPS = $(BFD_LIB) $(OPCODES_LIB) $(INTLLIBS) $(LIBIBERTY_LIB) \ + $(SIM_EXTRA_LIBDEPS) +EXTRA_LIBS = $(BFD_LIB) $(OPCODES_LIB) $(INTLLIBS) $(LIBIBERTY_LIB) \ + $(CONFIG_LIBS) $(SIM_EXTRA_LIBS) + +LIB_OBJS = callback.o syscall.o targ-map.o $(SIM_OBJS) + +RUNTESTFLAGS = + +all: $(SIM_EXTRA_ALL) libsim.a run .gdbinit + +libsim.a: $(LIB_OBJS) + rm -f libsim.a + $(AR) $(AR_FLAGS) libsim.a $(LIB_OBJS) + $(RANLIB) libsim.a + +run: $(SIM_RUN_OBJS) libsim.a $(LIBDEPS) + $(CC) $(ALL_CFLAGS) -o run$(EXEEXT) \ + $(SIM_RUN_OBJS) libsim.a $(EXTRA_LIBS) + +run.o: $(srccom)/run.c config.h tconfig.h \ + $(srcroot)/include/remote-sim.h $(srcroot)/include/callback.h + $(CC) -c $(srccom)/run.c $(ALL_CFLAGS) + +# FIXME: Ideally, callback.o and friends live in a library outside of +# both the gdb and simulator source trees (e.g. devo/remote. Not +# devo/libremote because this directory would contain more than just +# a library). + +callback.o: $(srccom)/callback.c config.h tconfig.h \ + $(srcroot)/include/callback.h targ-vals.h + $(CC) -c $(srccom)/callback.c $(ALL_CFLAGS) + +syscall.o: $(srccom)/syscall.c config.h tconfig.h \ + $(srcroot)/include/callback.h targ-vals.h + $(CC) -c $(srccom)/syscall.c $(ALL_CFLAGS) + +targ-map.o: targ-map.c targ-vals.h + +gentmap: Makefile $(srccom)/gentmap.c targ-vals.def + $(CC_FOR_BUILD) $(srccom)/gentmap.c -o gentmap $(BUILD_CFLAGS) $(NL_TARGET) + +targ-vals.h targ-map.c: stamp-tvals +stamp-tvals: gentmap + rm -f tmp-tvals.h tmp-tmap.c + ./gentmap -h >tmp-tvals.h + $(SHELL) $(srcroot)/move-if-change tmp-tvals.h targ-vals.h + ./gentmap -c >tmp-tmap.c + $(SHELL) $(srcroot)/move-if-change tmp-tmap.c targ-map.c + touch stamp-tvals + +# +# Rules for building sim-* components. Triggered by listing the corresponding +# .o file in the list of simulator targets. +# + +sim_main_headers = \ + sim-main.h \ + $(srccom)/sim-assert.h \ + $(srccom)/sim-base.h \ + $(srccom)/sim-basics.h \ + $(srccom)/sim-config.h \ + $(srccom)/sim-cpu.h \ + $(srccom)/sim-engine.h \ + $(srccom)/sim-events.h \ + $(srccom)/sim-inline.h \ + $(srccom)/sim-memopt.h \ + $(srccom)/sim-model.h \ + $(srccom)/sim-module.h \ + $(srccom)/sim-profile.h \ + $(srccom)/sim-signal.h \ + $(srccom)/sim-trace.h \ + $(srccom)/sim-watch.h \ + tconfig.h \ + $(SIM_EXTRA_DEPS) + +# Exported version of sim_main_headers. +SIM_MAIN_DEPS = \ + $(sim_main_headers) + +sim-assert_h = $(srccom)/sim-assert.h +sim-endian_h = $(srccom)/sim-endian.h +sim-n-endian_h = $(srccom)/sim-n-endian.h +sim-arange_h = $(srccom)/sim-arange.h +sim-bits_h = $(srccom)/sim-bits.h +sim-config_h = $(srccom)/sim-config.h +sim-n-bits_h = $(srccom)/sim-n-bits.h +sim-core_h = $(srccom)/sim-core.h +sim-n-core_h = $(srccom)/sim-n-core.h +sim-engine_h = $(srccom)/sim-engine.h +sim-events_h = $(srccom)/sim-events.h +sim-fpu_h = $(srccom)/sim-fpu.h +sim-io_h = $(srccom)/sim-io.h +sim-options_h = $(srccom)/sim-options.h +sim-break_h = $(srccom)/sim-break.h +sim-signal_h = $(srccom)/sim-signal.h + +hw-alloc_h = $(srccom)/hw-alloc.h +hw-base_h = $(srccom)/hw-base.h +hw-device_h = $(srccom)/hw-device.h +hw-events_h = $(srccom)/hw-events.h +hw-handles_h = $(srccom)/hw-handles.h +hw-instances_h = $(srccom)/hw-instances.h +hw-ports_h = $(srccom)/hw-ports.h +hw-properties_h = $(srccom)/hw-properties.h +hw-tree_h = $(srccom)/hw-tree.h + +hw_main_headers = \ + $(srccom)/hw-main.h \ + $(hw-alloc_h) \ + $(hw-base_h) \ + $(hw-device_h) \ + $(hw-events_h) \ + $(hw-instances_h) \ + $(hw-handles_h) \ + $(hw-ports_h) \ + $(hw-properties_h) \ + +# FIXME: If this complicated way of building .o files from ../common is +# necessary, the reason should be documented here. + +BUILT_SRC_FROM_COMMON= \ + sim-inline.c + +sim-abort.o: $(srccom)/sim-abort.c \ + $(SIM_EXTRA_DEPS) + $(CC) -c $(srccom)/sim-abort.c $(ALL_CFLAGS) + +sim-arange.o: $(srccom)/sim-arange.c $(sim-arange_h) $(SIM_EXTRA_DEPS) + $(CC) -c $(srccom)/sim-arange.c $(ALL_CFLAGS) + +sim-bits.o: $(srccom)/sim-bits.c $(sim-bits_h) $(sim-n-bits_h) \ + $(SIM_EXTRA_DEPS) + $(CC) -c $(srccom)/sim-bits.c $(ALL_CFLAGS) + +sim-config.o: $(srccom)/sim-config.c $(sim-config_h) \ + $(SIM_EXTRA_DEPS) + $(CC) -c $(srccom)/sim-config.c $(ALL_CFLAGS) + +sim-core.o: $(srccom)/sim-core.c $(sim_main_headers) \ + $(sim-core_h) $(sim-n-core_h) + $(CC) -c $(srccom)/sim-core.c $(ALL_CFLAGS) + +sim-cpu.o: $(srccom)/sim-cpu.c $(sim_main_headers) + $(CC) -c $(srccom)/sim-cpu.c $(ALL_CFLAGS) + +sim-endian.o: $(srccom)/sim-endian.c $(sim-endian_h) $(sim-n-endian_h) + $(CC) -c $(srccom)/sim-endian.c $(ALL_CFLAGS) + +sim-engine.o: $(srccom)/sim-engine.c $(sim_main_headers) $(sim-engine_h) + $(CC) -c $(srccom)/sim-engine.c $(ALL_CFLAGS) + +sim-events.o: $(srccom)/sim-events.c $(sim-events_h) \ + $(SIM_EXTRA_DEPS) + $(CC) -c $(srccom)/sim-events.c $(ALL_CFLAGS) + +sim-fpu.o: $(srccom)/sim-fpu.c $(sim-fpu_h) \ + $(SIM_EXTRA_DEPS) + $(CC) -c $(srccom)/sim-fpu.c $(ALL_CFLAGS) + + +sim-hload.o: $(srccom)/sim-hload.c $(sim-assert_h) \ + $(srcroot)/include/remote-sim.h \ + $(SIM_EXTRA_DEPS) + $(CC) -c $(srccom)/sim-hload.c $(ALL_CFLAGS) + +sim-hrw.o: $(srccom)/sim-hrw.c $(sim-assert_h) $(sim_core_h) \ + $(srcroot)/include/remote-sim.h \ + $(SIM_EXTRA_DEPS) + $(CC) -c $(srccom)/sim-hrw.c $(ALL_CFLAGS) + +sim-hw.o: $(srccom)/sim-hw.c $(sim_main_headers) + $(CC) -c $(srccom)/sim-hw.c $(ALL_CFLAGS) + +sim-info.o: $(srccom)/sim-info.c $(sim-assert_h) \ + $(srcroot)/include/remote-sim.h \ + $(SIM_EXTRA_DEPS) + $(CC) -c $(srccom)/sim-info.c $(ALL_CFLAGS) + +sim-inline.c: $(srccom)/sim-inline.c + rm -f $@ tmp-$@ + echo "# 1 \"$(srccom)/$@\"" > tmp-$@ + cat $(srccom)/$@ >> tmp-$@ + $(SHELL) $(srcdir)/../../move-if-change tmp-$@ $@ + +sim-io.o: $(srccom)/sim-io.c $(sim_main_headers) $(sim-io_h) \ + $(srcroot)/include/remote-sim.h + $(CC) -c $(srccom)/sim-io.c $(ALL_CFLAGS) + +sim-memopt.o: $(srccom)/sim-memopt.c $(sim_main_headers) \ + $(sim-io_h) + $(CC) -c $(srccom)/sim-memopt.c $(ALL_CFLAGS) + +sim-module.o: $(srccom)/sim-module.c $(sim_main_headers) \ + $(sim-io_h) + $(CC) -c $(srccom)/sim-module.c $(ALL_CFLAGS) + +sim-options.o: $(srccom)/sim-options.c $(sim_main_headers) \ + $(sim-options_h) $(sim-io_h) + $(CC) -c $(srccom)/sim-options.c $(ALL_CFLAGS) + +sim-reason.o: $(srccom)/sim-reason.c $(sim_main_headers) \ + $(srcroot)/include/remote-sim.h + $(CC) -c $(srccom)/sim-reason.c $(ALL_CFLAGS) + +sim-reg.o: $(srccom)/sim-reg.c $(sim_main_headers) \ + $(srcroot)/include/remote-sim.h + $(CC) -c $(srccom)/sim-reg.c $(ALL_CFLAGS) + +sim-resume.o: $(srccom)/sim-resume.c $(sim_main_headers) \ + $(srcroot)/include/remote-sim.h + $(CC) -c $(srccom)/sim-resume.c $(ALL_CFLAGS) + +sim-run.o: $(srccom)/sim-run.c $(sim_main_headers) + $(CC) -c $(srccom)/sim-run.c $(ALL_CFLAGS) + +sim-signal.o: $(srccom)/sim-signal.c $(sim_main_headers) $(sim-signal_h) + $(CC) -c $(srccom)/sim-signal.c $(ALL_CFLAGS) + +sim-stop.o: $(srccom)/sim-stop.c $(sim_main_headers) + $(CC) -c $(srccom)/sim-stop.c $(ALL_CFLAGS) + +sim-trace.o: $(srccom)/sim-trace.c $(sim_main_headers) \ + $(sim-options_h) $(sim-io_h) + $(CC) -c $(srccom)/sim-trace.c $(ALL_CFLAGS) + +sim-profile.o: $(srccom)/sim-profile.c $(sim_main_headers) \ + $(sim-options_h) $(sim-io_h) + $(CC) -c $(srccom)/sim-profile.c $(ALL_CFLAGS) + +sim-model.o: $(srccom)/sim-model.c $(sim_main_headers) \ + $(sim-io_h) + $(CC) -c $(srccom)/sim-model.c $(ALL_CFLAGS) + +sim-utils.o: $(srccom)/sim-utils.c $(sim_main_headers) + $(CC) -c $(srccom)/sim-utils.c $(ALL_CFLAGS) + +sim-watch.o: $(srccom)/sim-watch.c $(sim_main_headers) + $(CC) -c $(srccom)/sim-watch.c $(ALL_CFLAGS) + +sim-load.o: $(srccom)/sim-load.c $(srcroot)/include/callback.h + $(CC) -c $(srccom)/sim-load.c $(ALL_CFLAGS) + +sim-break.o: $(srccom)/sim-break.c $(sim_main_headers) \ + $(sim_break_h) + $(CC) -c $(srccom)/sim-break.c $(ALL_CFLAGS) + + +# FIXME This is one very simple-minded way of generating the file hw-config.h +hw-config.h: Makefile.in $(srccom)/Make-common.in config.status Makefile + rm -f tmp-hw.h + echo "/* generated by Makefile */" > tmp-hw.h + for hw in $(SIM_HW) ; do \ + echo "extern const struct hw_descriptor dv_$${hw}_descriptor[];" ; \ + done >> tmp-hw.h + echo "const struct hw_descriptor *hw_descriptors[] = {" >> tmp-hw.h + for hw in $(SIM_HW) ; do \ + echo " dv_$${hw}_descriptor," ; \ + done >> tmp-hw.h + echo " NULL," >> tmp-hw.h + echo "};" >> tmp-hw.h + mv tmp-hw.h hw-config.h + +hw-alloc.o: $(srccom)/hw-alloc.c $(hw_main_headers) + $(CC) -c $(srccom)/hw-alloc.c $(ALL_CFLAGS) + +hw-base.o: $(srccom)/hw-base.c $(hw_main_headers) hw-config.h + $(CC) -c $(srccom)/hw-base.c $(ALL_CFLAGS) + +hw-device.o: $(srccom)/hw-device.c $(hw_main_headers) + $(CC) -c $(srccom)/hw-device.c $(ALL_CFLAGS) + +hw-events.o: $(srccom)/hw-events.c $(hw_main_headers) $(sim_main_headers) + $(CC) -c $(srccom)/hw-events.c $(ALL_CFLAGS) + +test-hw-events: $(srccom)/hw-events.c libsim.a + $(CC) $(ALL_CFLAGS) -DMAIN -o test-hw-events$(EXEEXT) \ + $(srccom)/hw-events.c libsim.a $(EXTRA_LIBS) + +hw-instances.o: $(srccom)/hw-instances.c $(hw_main_headers) + $(CC) -c $(srccom)/hw-instances.c $(ALL_CFLAGS) + +hw-handles.o: $(srccom)/hw-handles.c $(hw_main_headers) + $(CC) -c $(srccom)/hw-handles.c $(ALL_CFLAGS) + +hw-ports.o: $(srccom)/hw-ports.c $(hw_main_headers) + $(CC) -c $(srccom)/hw-ports.c $(ALL_CFLAGS) + +hw-properties.o: $(srccom)/hw-properties.c $(hw_main_headers) + $(CC) -c $(srccom)/hw-properties.c $(ALL_CFLAGS) + +hw-tree.o: $(srccom)/hw-tree.c $(hw_main_headers) $(hw-tree_h) + $(CC) -c $(srccom)/hw-tree.c $(ALL_CFLAGS) + +# Devices. + +dv-core.o: $(srccom)/dv-core.c $(hw_main_headers) $(sim_main_headers) + $(CC) -c $(srccom)/dv-core.c $(ALL_CFLAGS) + +dv-glue.o: $(srccom)/dv-glue.c $(hw_main_headers) $(sim_main_headers) + $(CC) -c $(srccom)/dv-glue.c $(ALL_CFLAGS) + +dv-pal.o: $(srccom)/dv-pal.c $(hw_main_headers) $(sim_main_headers) + $(CC) -c $(srccom)/dv-pal.c $(ALL_CFLAGS) + +dv-sockser.o: $(srccom)/dv-sockser.h $(sim_main_headers) + $(CC) -c $(srccom)/dv-sockser.c $(ALL_CFLAGS) + + +nrun.o: $(srccom)/nrun.c config.h tconfig.h \ + $(srcroot)/include/remote-sim.h $(srcroot)/include/callback.h \ + $(sim_main_headers) + $(CC) -c $(srccom)/nrun.c $(ALL_CFLAGS) + +# CGEN support. + +# For use in Makefile.in for cpu-specific files. +CGEN_MAIN_CPU_DEPS = \ + $(SIM_MAIN_DEPS) \ + $(CGEN_INCLUDE_DEPS) \ + $(srccom)/cgen-ops.h \ + $(srccom)/cgen-mem.h + +cgen-run.o: $(srccom)/cgen-run.c $(sim_main_headers) + $(CC) -c $(srccom)/cgen-run.c $(ALL_CFLAGS) + +cgen-scache.o: $(srccom)/cgen-scache.c $(sim_main_headers) + $(CC) -c $(srccom)/cgen-scache.c $(ALL_CFLAGS) + +cgen-trace.o: $(srccom)/cgen-trace.c $(sim_main_headers) + $(CC) -c $(srccom)/cgen-trace.c $(ALL_CFLAGS) + +cgen-utils.o: $(srccom)/cgen-utils.c $(sim_main_headers) \ + $(srccom)/cgen-mem.h $(srccom)/cgen-ops.h $(srccom)/cgen-engine.h + $(CC) -c $(srccom)/cgen-utils.c $(ALL_CFLAGS) + +# Support targets. + +install: install-common $(SIM_EXTRA_INSTALL) + +install-common: installdirs + n=`echo run | sed '$(program_transform_name)'`; \ + $(INSTALL_PROGRAM) run$(EXEEXT) $(bindir)/$$n$(EXEEXT) + n=`echo libsim.a | sed s/libsim.a/lib$(target_alias)-sim.a/`; \ + $(INSTALL_DATA) libsim.a $(libdir)/$$n ; \ + ( cd $(libdir) ; $(RANLIB) $$n ) + +installdirs: + $(SHELL) $(srcdir)/../../mkinstalldirs $(bindir) + +check: + cd ../testsuite && $(MAKE) check RUNTESTFLAGS="$(RUNTESTFLAGS)" + +info: +clean-info: +install-info: + +.NOEXPORT: +MAKEOVERRIDES= + +tags etags: TAGS + +# Macros like EXTERN_SIM_CORE confuse tags. +# And the sim-n-foo.h files create functions that can't be found either. +TAGS: force + cd $(srcdir) && \ + etags --regex '/^\([a-z_]+\) (/\1/' --regex '/^\/[*] TAGS: .*/' \ + *.[ch] ../common/*.[ch] + +clean: $(SIM_EXTRA_CLEAN) + rm -f *.[oa] *~ core + rm -f run libsim.a + rm -f gentmap targ-map.c targ-vals.h stamp-tvals + if [ ! -f Make-common.in ] ; then \ + rm -f $(BUILT_SRC_FROM_COMMON) ; \ + fi + rm -f tmp-mloop.hin tmp-mloop.h tmp-mloop.cin tmp-mloop.c + +distclean mostlyclean maintainer-clean realclean: clean + rm -f TAGS + rm -f Makefile config.cache config.log config.status .gdbinit + rm -f tconfig.h config.h stamp-h + rm -f targ-vals.def + +.c.o: + $(CC) -c $(ALL_CFLAGS) $< + +# Dummy target to force execution of dependent targets. +force: + +Makefile: Makefile.in $(srccom)/Make-common.in config.status + CONFIG_HEADERS= $(SHELL) ./config.status + +config.status: configure + $(SHELL) ./config.status --recheck + +config.h: stamp-h ; @true +stamp-h: config.in config.status + CONFIG_FILES= CONFIG_HEADERS=config.h:config.in $(SHELL) ./config.status + +.gdbinit: # config.status $(srccom)/gdbinit.in + CONFIG_FILES=$@:../common/gdbinit.in CONFIG_HEADERS= $(SHELL) ./config.status + + +## End COMMON_POST_CONFIG_FRAG diff --git a/sim/common/Makefile.in b/sim/common/Makefile.in new file mode 100644 index 0000000..dd7c5e0 --- /dev/null +++ b/sim/common/Makefile.in @@ -0,0 +1,139 @@ +# Makefile template for Configure for simulator common directory +# Copyright (C) 1996, 1997 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +default: all + +VPATH = @srcdir@ +srcdir = @srcdir@ +srcroot = $(srcdir)/../.. + +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +host_alias = @host_alias@ +target_alias = @target_alias@ +program_transform_name = @program_transform_name@ +bindir = @bindir@ + +libdir = @libdir@ +tooldir = $(libdir)/$(target_alias) + +datadir = @datadir@ +mandir = @mandir@ +man1dir = $(mandir)/man1 +infodir = @infodir@ +includedir = @includedir@ + +SHELL = /bin/sh + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +CC = @CC@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +CFLAGS = @CFLAGS@ +SIM_CFLAGS = @sim_cflags@ + +# These are used to rebuild nltvals.def. +CPP_FOR_TARGET = @CPP_FOR_TARGET@ +TARGET_SUBDIR = @TARGET_SUBDIR@ + +HDEFINES = @HDEFINES@ +TDEFINES = + +CONFIG_CFLAGS = @DEFS@ $(SIM_CFLAGS) $(HDEFINES) $(TDEFINES) +CSEARCH = -I. -I$(srcdir) -I$(srcroot)/include +ALL_CFLAGS = $(CFLAGS) $(CONFIG_CFLAGS) $(CSEARCH) +BUILD_CFLAGS = -g -O $(CSEARCH) + +AR = @AR@ +AR_FLAGS = rc +RANLIB = @RANLIB@ +MAKEINFO = makeinfo + +.NOEXPORT: +MAKEOVERRIDES= + +all: + +# Generate TARG_VALS_H for newlib/libgloss using devo and build tree. +# This file is shipped with distributions so we build in the source dir. +# This is built in srcdir so putting dependencies here is risky. +# Use `make headers' to rebuild. +headers: nltvals.def +.PHONY: headers + +# Note: If gdb releases begin to contain target header files, generate +# targ-vals.def at build time. + +nltvals.def: Makefile gennltvals.sh gentvals.sh + rootme=`pwd` ; \ + cd $(srcdir) ; \ + rm -f nltvals.new ; \ + $(SHELL) $(srcdir)/gennltvals.sh $(SHELL) $(srcroot) "$(CPP_FOR_TARGET)" > nltvals.new ; \ + $(SHELL) $(srcroot)/move-if-change nltvals.new nltvals.def + +.c.o: + $(CC) -c $< $(ALL_CFLAGS) + +check: + +info: +clean-info: +install-info: + +tags etags: TAGS + +# Macros like EXTERN_SIM_CORE confuse tags. +# And the sim-n-foo.h files create functions that can't be found either. +TAGS: force + cd $(srcdir) && \ + etags --regex '/^\([a-z_]+\) (/\1/' --regex '/^\/[*] TAGS: .*/' \ + *.[ch] + +clean: + rm -f *.[oa] *~ core + rm -f $(ALL) + +distclean mostlyclean maintainer-clean realclean: clean + rm -f TAGS + rm -f Makefile config.cache config.log config.status + rm -f config.h stamp-h + +# Dummy target to force execution of dependent targets. +force: + +# Copy the files into directories where they will be run. +install: + +install-man: installdirs + n=`echo run | sed '$(program_transform_name)'`; \ + $(INSTALL_DATA) $(srcdir)/run.1 $(man1dir)/$$n.1 + +installdirs: + $(SHELL) $(srcdir)/../../mkinstalldirs $(man1dir) + +Makefile: Makefile.in config.status + $(SHELL) ./config.status + +config.status: configure + $(SHELL) ./config.status --recheck + +config.h: stamp-h ; @true +stamp-h: config.in config.status + CONFIG_FILES= CONFIG_HEADERS=config.h:config.in $(SHELL) ./config.status diff --git a/sim/common/acconfig.h b/sim/common/acconfig.h new file mode 100644 index 0000000..f9b87a1 --- /dev/null +++ b/sim/common/acconfig.h @@ -0,0 +1,15 @@ + +/* Define to 1 if NLS is requested. */ +#undef ENABLE_NLS + +/* Define as 1 if you have catgets and don't want to use GNU gettext. */ +#undef HAVE_CATGETS + +/* Define as 1 if you have gettext and don't want to use GNU gettext. */ +#undef HAVE_GETTEXT + +/* Define as 1 if you have the stpcpy function. */ +#undef HAVE_STPCPY + +/* Define if your locale.h file contains LC_MESSAGES. */ +#undef HAVE_LC_MESSAGES diff --git a/sim/common/aclocal.m4 b/sim/common/aclocal.m4 new file mode 100644 index 0000000..e3b595a --- /dev/null +++ b/sim/common/aclocal.m4 @@ -0,0 +1,1259 @@ +# This file contains common code used by all simulators. +# +# SIM_AC_COMMON invokes AC macros used by all simulators and by the common +# directory. It is intended to be invoked before any target specific stuff. +# SIM_AC_OUTPUT is a cover function to AC_OUTPUT to generate the Makefile. +# It is intended to be invoked last. +# +# The simulator's configure.in should look like: +# +# dnl Process this file with autoconf to produce a configure script. +# sinclude(../common/aclocal.m4) +# AC_PREREQ(2.5)dnl +# AC_INIT(Makefile.in) +# +# SIM_AC_COMMON +# +# ... target specific stuff ... +# +# SIM_AC_OUTPUT + +AC_DEFUN(SIM_AC_COMMON, +[ +# autoconf.info says this should be called right after AC_INIT. +AC_CONFIG_HEADER(ifelse([$1],,config.h,[$1]):config.in) + +AC_CONFIG_AUX_DIR(`cd $srcdir;pwd`/../..) +AC_CANONICAL_SYSTEM +AC_ARG_PROGRAM +AC_PROG_CC +AC_PROG_INSTALL + +# Put a plausible default for CC_FOR_BUILD in Makefile. +if test "x$cross_compiling" = "xno"; then + CC_FOR_BUILD='$(CC)' +else + CC_FOR_BUILD=gcc +fi +AC_SUBST(CC_FOR_BUILD) + +AC_SUBST(CFLAGS) +AC_SUBST(HDEFINES) +AR=${AR-ar} +AC_SUBST(AR) +AC_PROG_RANLIB + +dnl We don't use gettext, but bfd does. So we do the appropriate checks +dnl to see if there are intl libraries we should link against. +ALL_LINGUAS= +CY_GNU_GETTEXT + +# Check for common headers. +# FIXME: Seems to me this can cause problems for i386-windows hosts. +# At one point there were hardcoded AC_DEFINE's if ${host} = i386-*-windows*. +AC_CHECK_HEADERS(stdlib.h string.h strings.h unistd.h time.h) +AC_CHECK_HEADERS(sys/time.h sys/resource.h) +AC_CHECK_HEADERS(fcntl.h fpu_control.h) +AC_CHECK_HEADERS(dlfcn.h errno.h sys/stat.h) +AC_CHECK_FUNCS(getrusage time sigaction __setfpucw) + +# Check for socket libraries +AC_CHECK_LIB(socket, bind) +AC_CHECK_LIB(nsl, gethostbyname) + +. ${srcdir}/../../bfd/configure.host + +dnl Standard (and optional) simulator options. +dnl Eventually all simulators will support these. +dnl Do not add any here that cannot be supported by all simulators. +dnl Do not add similar but different options to a particular simulator, +dnl all shall eventually behave the same way. + + +dnl We don't use automake, but we still want to support +dnl --enable-maintainer-mode. +USE_MAINTAINER_MODE=no +AC_ARG_ENABLE(maintainer-mode, +[ --enable-maintainer-mode Enable developer functionality.], +[case "${enableval}" in + yes) MAINT="" USE_MAINTAINER_MODE=yes ;; + no) MAINT="#" ;; + *) AC_MSG_ERROR("--enable-maintainer-mode does not take a value"); MAINT="#" ;; +esac +if test x"$silent" != x"yes" && test x"$MAINT" = x""; then + echo "Setting maintainer mode" 6>&1 +fi],[MAINT="#"])dnl +AC_SUBST(MAINT) + + +dnl This is a generic option to enable special byte swapping +dnl insns on *any* cpu. +AC_ARG_ENABLE(sim-bswap, +[ --enable-sim-bswap Use Host specific BSWAP instruction.], +[case "${enableval}" in + yes) sim_bswap="-DWITH_BSWAP=1 -DUSE_BSWAP=1";; + no) sim_bswap="-DWITH_BSWAP=0";; + *) AC_MSG_ERROR("--enable-sim-bswap does not take a value"); sim_bswap="";; +esac +if test x"$silent" != x"yes" && test x"$sim_bswap" != x""; then + echo "Setting bswap flags = $sim_bswap" 6>&1 +fi],[sim_bswap=""])dnl +AC_SUBST(sim_bswap) + + +AC_ARG_ENABLE(sim-cflags, +[ --enable-sim-cflags=opts Extra CFLAGS for use in building simulator], +[case "${enableval}" in + yes) sim_cflags="-O2 -fomit-frame-pointer";; + trace) AC_MSG_ERROR("Please use --enable-sim-debug instead."); sim_cflags="";; + no) sim_cflags="";; + *) sim_cflags=`echo "${enableval}" | sed -e "s/,/ /g"`;; +esac +if test x"$silent" != x"yes" && test x"$sim_cflags" != x""; then + echo "Setting sim cflags = $sim_cflags" 6>&1 +fi],[sim_cflags=""])dnl +AC_SUBST(sim_cflags) + + +dnl --enable-sim-debug is for developers of the simulator +dnl the allowable values are work-in-progress +AC_ARG_ENABLE(sim-debug, +[ --enable-sim-debug=opts Enable debugging flags], +[case "${enableval}" in + yes) sim_debug="-DDEBUG=7 -DWITH_DEBUG=7";; + no) sim_debug="-DDEBUG=0 -DWITH_DEBUG=0";; + *) sim_debug="-DDEBUG='(${enableval})' -DWITH_DEBUG='(${enableval})'";; +esac +if test x"$silent" != x"yes" && test x"$sim_debug" != x""; then + echo "Setting sim debug = $sim_debug" 6>&1 +fi],[sim_debug=""])dnl +AC_SUBST(sim_debug) + + +dnl --enable-sim-stdio is for users of the simulator +dnl It determines if IO from the program is routed through STDIO (buffered) +AC_ARG_ENABLE(sim-stdio, +[ --enable-sim-stdio Specify whether to use stdio for console input/output.], +[case "${enableval}" in + yes) sim_stdio="-DWITH_STDIO=DO_USE_STDIO";; + no) sim_stdio="-DWITH_STDIO=DONT_USE_STDIO";; + *) AC_MSG_ERROR("Unknown value $enableval passed to --enable-sim-stdio"); sim_stdio="";; +esac +if test x"$silent" != x"yes" && test x"$sim_stdio" != x""; then + echo "Setting stdio flags = $sim_stdio" 6>&1 +fi],[sim_stdio=""])dnl +AC_SUBST(sim_stdio) + + +dnl --enable-sim-trace is for users of the simulator +dnl The argument is either a bitmask of things to enable [exactly what is +dnl up to the simulator], or is a comma separated list of names of tracing +dnl elements to enable. The latter is only supported on simulators that +dnl use WITH_TRACE. +AC_ARG_ENABLE(sim-trace, +[ --enable-sim-trace=opts Enable tracing flags], +[case "${enableval}" in + yes) sim_trace="-DTRACE=1 -DWITH_TRACE=-1";; + no) sim_trace="-DTRACE=0 -DWITH_TRACE=0";; + [[-0-9]]*) + sim_trace="-DTRACE='(${enableval})' -DWITH_TRACE='(${enableval})'";; + [[a-z]]*) + sim_trace="" + for x in `echo "$enableval" | sed -e "s/,/ /g"`; do + if test x"$sim_trace" = x; then + sim_trace="-DWITH_TRACE='(TRACE_$x" + else + sim_trace="${sim_trace}|TRACE_$x" + fi + done + sim_trace="$sim_trace)'" ;; +esac +if test x"$silent" != x"yes" && test x"$sim_trace" != x""; then + echo "Setting sim trace = $sim_trace" 6>&1 +fi],[sim_trace=""])dnl +AC_SUBST(sim_trace) + + +dnl --enable-sim-profile +dnl The argument is either a bitmask of things to enable [exactly what is +dnl up to the simulator], or is a comma separated list of names of profiling +dnl elements to enable. The latter is only supported on simulators that +dnl use WITH_PROFILE. +AC_ARG_ENABLE(sim-profile, +[ --enable-sim-profile=opts Enable profiling flags], +[case "${enableval}" in + yes) sim_profile="-DPROFILE=1 -DWITH_PROFILE=-1";; + no) sim_profile="-DPROFILE=0 -DWITH_PROFILE=0";; + [[-0-9]]*) + sim_profile="-DPROFILE='(${enableval})' -DWITH_PROFILE='(${enableval})'";; + [[a-z]]*) + sim_profile="" + for x in `echo "$enableval" | sed -e "s/,/ /g"`; do + if test x"$sim_profile" = x; then + sim_profile="-DWITH_PROFILE='(PROFILE_$x" + else + sim_profile="${sim_profile}|PROFILE_$x" + fi + done + sim_profile="$sim_profile)'" ;; +esac +if test x"$silent" != x"yes" && test x"$sim_profile" != x""; then + echo "Setting sim profile = $sim_profile" 6>&1 +fi],[sim_profile=""])dnl +AC_SUBST(sim_profile) + + +dnl Types used by common code +AC_TYPE_SIGNAL + +dnl Detect exe extension +AM_EXEEXT + +dnl These are available to append to as desired. +sim_link_files= +sim_link_links= + +dnl Create tconfig.h either from simulator's tconfig.in or default one +dnl in common. +sim_link_links=tconfig.h +if test -f ${srcdir}/tconfig.in +then + sim_link_files=tconfig.in +else + sim_link_files=../common/tconfig.in +fi + +# targ-vals.def points to the libc macro description file. +case "${target}" in +*-*-*) TARG_VALS_DEF=../common/nltvals.def ;; +esac +sim_link_files="${sim_link_files} ${TARG_VALS_DEF}" +sim_link_links="${sim_link_links} targ-vals.def" + +]) dnl End of SIM_AC_COMMON + + +dnl Additional SIM options that can (optionally) be configured +dnl For optional simulator options, a macro SIM_AC_OPTION_* is defined. +dnl Simulators that wish to use the relevant option specify the macro +dnl in the simulator specific configure.in file between the SIM_AC_COMMON +dnl and SIM_AC_OUTPUT lines. + + +dnl Specify the running environment. +dnl If the simulator invokes this in its configure.in then without this option +dnl the default is the user environment and all are runtime selectable. +dnl If the simulator doesn't invoke this, only the user environment is +dnl supported. +dnl ??? Until there is demonstrable value in doing something more complicated, +dnl let's not. +AC_DEFUN(SIM_AC_OPTION_ENVIRONMENT, +[ +AC_ARG_ENABLE(sim-environment, +[ --enable-sim-environment=environment Specify mixed, user, virtual or operating environment.], +[case "${enableval}" in + all | ALL) sim_environment="-DWITH_ENVIRONMENT=ALL_ENVIRONMENT";; + user | USER) sim_environment="-DWITH_ENVIRONMENT=USER_ENVIRONMENT";; + virtual | VIRTUAL) sim_environment="-DWITH_ENVIRONMENT=VIRTUAL_ENVIRONMENT";; + operating | OPERATING) sim_environment="-DWITH_ENVIRONMENT=OPERATING_ENVIRONMENT";; + *) AC_MSG_ERROR("Unknown value $enableval passed to --enable-sim-environment"); + sim_environment="";; +esac +if test x"$silent" != x"yes" && test x"$sim_environment" != x""; then + echo "Setting sim environment = $sim_environment" 6>&1 +fi], +[sim_environment="-DWITH_ENVIRONMENT=ALL_ENVIRONMENT"])dnl +]) +AC_SUBST(sim_environment) + + +dnl Specify the alignment restrictions of the target architecture. +dnl Without this option all possible alignment restrictions are accommodated. +dnl arg[1] is hardwired target alignment +dnl arg[2] is default target alignment +AC_DEFUN(SIM_AC_OPTION_ALIGNMENT, +wire_alignment="[$1]" +default_alignment="[$2]" +[ +AC_ARG_ENABLE(sim-alignment, +[ --enable-sim-alignment=align Specify strict, nonstrict or forced alignment of memory accesses.], +[case "${enableval}" in + strict | STRICT) sim_alignment="-DWITH_ALIGNMENT=STRICT_ALIGNMENT";; + nonstrict | NONSTRICT) sim_alignment="-DWITH_ALIGNMENT=NONSTRICT_ALIGNMENT";; + forced | FORCED) sim_alignment="-DWITH_ALIGNMENT=FORCED_ALIGNMENT";; + yes) if test x"$wire_alignment" != x; then + sim_alignment="-DWITH_ALIGNMENT=${wire_alignment}" + else + if test x"$default_alignment" != x; then + sim_alignment="-DWITH_ALIGNMENT=${default_alignment}" + else + echo "No hard-wired alignment for target $target" 1>&6 + sim_alignment="-DWITH_ALIGNMENT=0" + fi + fi;; + no) if test x"$default_alignment" != x; then + sim_alignment="-DWITH_DEFAULT_ALIGNMENT=${default_alignment}" + else + if test x"$wire_alignment" != x; then + sim_alignment="-DWITH_DEFAULT_ALIGNMENT=${wire_alignment}" + else + echo "No default alignment for target $target" 1>&6 + sim_alignment="-DWITH_DEFAULT_ALIGNMENT=0" + fi + fi;; + *) AC_MSG_ERROR("Unknown value $enableval passed to --enable-sim-alignment"); sim_alignment="";; +esac +if test x"$silent" != x"yes" && test x"$sim_alignment" != x""; then + echo "Setting alignment flags = $sim_alignment" 6>&1 +fi], +[if test x"$default_alignment" != x; then + sim_alignment="-DWITH_DEFAULT_ALIGNMENT=${default_alignment}" +else + if test x"$wire_alignment" != x; then + sim_alignment="-DWITH_ALIGNMENT=${wire_alignment}" + else + sim_alignment= + fi +fi])dnl +])dnl +AC_SUBST(sim_alignment) + + +dnl Conditionally compile in assertion statements. +AC_DEFUN(SIM_AC_OPTION_ASSERT, +[ +AC_ARG_ENABLE(sim-assert, +[ --enable-sim-assert Specify whether to perform random assertions.], +[case "${enableval}" in + yes) sim_assert="-DWITH_ASSERT=1";; + no) sim_assert="-DWITH_ASSERT=0";; + *) AC_MSG_ERROR("--enable-sim-assert does not take a value"); sim_assert="";; +esac +if test x"$silent" != x"yes" && test x"$sim_assert" != x""; then + echo "Setting assert flags = $sim_assert" 6>&1 +fi],[sim_assert=""])dnl +]) +AC_SUBST(sim_assert) + + + +dnl --enable-sim-bitsize is for developers of the simulator +dnl It specifies the number of BITS in the target. +dnl arg[1] is the number of bits in a word +dnl arg[2] is the number assigned to the most significant bit +dnl arg[3] is the number of bits in an address +dnl arg[4] is the number of bits in an OpenFirmware cell. +dnl FIXME: this information should be obtained from bfd/archure +AC_DEFUN(SIM_AC_OPTION_BITSIZE, +wire_word_bitsize="[$1]" +wire_word_msb="[$2]" +wire_address_bitsize="[$3]" +wire_cell_bitsize="[$4]" +[AC_ARG_ENABLE(sim-bitsize, +[ --enable-sim-bitsize=N Specify target bitsize (32 or 64).], +[sim_bitsize= +case "${enableval}" in + 64,63 | 64,63,* ) sim_bitsize="-DWITH_TARGET_WORD_BITSIZE=64 -DWITH_TARGET_WORD_MSB=63";; + 32,31 | 32,31,* ) sim_bitsize="-DWITH_TARGET_WORD_BITSIZE=32 -DWITH_TARGET_WORD_MSB=31";; + 64,0 | 64,0,* ) sim_bitsize="-DWITH_TARGET_WORD_BITSIZE=32 -DWITH_TARGET_WORD_MSB=0";; + 32,0 | 64,0,* ) sim_bitsize="-DWITH_TARGET_WORD_BITSIZE=32 -DWITH_TARGET_WORD_MSB=0";; + 32) if test x"$wire_word_msb" != x -a x"$wire_word_msb" != x0; then + sim_bitsize="-DWITH_TARGET_WORD_BITSIZE=32 -DWITH_TARGET_WORD_MSB=31" + else + sim_bitsize="-DWITH_TARGET_WORD_BITSIZE=32 -DWITH_TARGET_WORD_MSB=0" + fi ;; + 64) if test x"$wire_word_msb" != x -a x"$wire_word_msb" != x0; then + sim_bitsize="-DWITH_TARGET_WORD_BITSIZE=64 -DWITH_TARGET_WORD_MSB=63" + else + sim_bitsize="-DWITH_TARGET_WORD_BITSIZE=64 -DWITH_TARGET_WORD_MSB=0" + fi ;; + *) AC_MSG_ERROR("--enable-sim-bitsize was given $enableval. Expected 32 or 64") ;; +esac +# address bitsize +tmp=`echo "${enableval}" | sed -e "s/^[[0-9]]*,*[[0-9]]*,*//"` +case x"${tmp}" in + x ) ;; + x32 | x32,* ) sim_bitsize="${sim_bitsize} -DWITH_TARGET_ADDRESS_BITSIZE=32" ;; + x64 | x64,* ) sim_bitsize="${sim_bitsize} -DWITH_TARGET_ADDRESS_BITSIZE=64" ;; + * ) AC_MSG_ERROR("--enable-sim-bitsize was given address size $enableval. Expected 32 or 64") ;; +esac +# cell bitsize +tmp=`echo "${enableval}" | sed -e "s/^[[0-9]]*,*[[0-9*]]*,*[[0-9]]*,*//"` +case x"${tmp}" in + x ) ;; + x32 | x32,* ) sim_bitsize="${sim_bitsize} -DWITH_TARGET_CELL_BITSIZE=32" ;; + x64 | x64,* ) sim_bitsize="${sim_bitsize} -DWITH_TARGET_CELL_BITSIZE=64" ;; + * ) AC_MSG_ERROR("--enable-sim-bitsize was given cell size $enableval. Expected 32 or 64") ;; +esac +if test x"$silent" != x"yes" && test x"$sim_bitsize" != x""; then + echo "Setting bitsize flags = $sim_bitsize" 6>&1 +fi], +[sim_bitsize="" +if test x"$wire_word_bitsize" != x; then + sim_bitsize="$sim_bitsize -DWITH_TARGET_WORD_BITSIZE=$wire_word_bitsize" +fi +if test x"$wire_word_msb" != x; then + sim_bitsize="$sim_bitsize -DWITH_TARGET_WORD_MSB=$wire_word_msb" +fi +if test x"$wire_address_bitsize" != x; then + sim_bitsize="$sim_bitsize -DWITH_TARGET_ADDRESS_BITSIZE=$wire_address_bitsize" +fi +if test x"$wire_cell_bitsize" != x; then + sim_bitsize="$sim_bitsize -DWITH_TARGET_CELL_BITSIZE=$wire_cell_bitsize" +fi])dnl +]) +AC_SUBST(sim_bitsize) + + + +dnl --enable-sim-endian={yes,no,big,little} is for simulators +dnl that support both big and little endian targets. +dnl arg[1] is hardwired target endianness. +dnl arg[2] is default target endianness. +AC_DEFUN(SIM_AC_OPTION_ENDIAN, +[ +wire_endian="[$1]" +default_endian="[$2]" +AC_ARG_ENABLE(sim-endian, +[ --enable-sim-endian=endian Specify target byte endian orientation.], +[case "${enableval}" in + b*|B*) sim_endian="-DWITH_TARGET_BYTE_ORDER=BIG_ENDIAN";; + l*|L*) sim_endian="-DWITH_TARGET_BYTE_ORDER=LITTLE_ENDIAN";; + yes) if test x"$wire_endian" != x; then + sim_endian="-DWITH_TARGET_BYTE_ORDER=${wire_endian}" + else + if test x"$default_endian" != x; then + sim_endian="-DWITH_TARGET_BYTE_ORDER=${default_endian}" + else + echo "No hard-wired endian for target $target" 1>&6 + sim_endian="-DWITH_TARGET_BYTE_ORDER=0" + fi + fi;; + no) if test x"$default_endian" != x; then + sim_endian="-DWITH_DEFAULT_TARGET_BYTE_ORDER=${default_endian}" + else + if test x"$wire_endian" != x; then + sim_endian="-DWITH_DEFAULT_TARGET_BYTE_ORDER=${wire_endian}" + else + echo "No default endian for target $target" 1>&6 + sim_endian="-DWITH_DEFAULT_TARGET_BYTE_ORDER=0" + fi + fi;; + *) AC_MSG_ERROR("Unknown value $enableval for --enable-sim-endian"); sim_endian="";; +esac +if test x"$silent" != x"yes" && test x"$sim_endian" != x""; then + echo "Setting endian flags = $sim_endian" 6>&1 +fi], +[if test x"$default_endian" != x; then + sim_endian="-DWITH_DEFAULT_TARGET_BYTE_ORDER=${default_endian}" +else + if test x"$wire_endian" != x; then + sim_endian="-DWITH_TARGET_BYTE_ORDER=${wire_endian}" + else + sim_endian= + fi +fi])dnl +]) +AC_SUBST(sim_endian) + + +dnl --enable-sim-hostendian is for users of the simulator when +dnl they find that AC_C_BIGENDIAN does not function correctly +dnl (for instance in a canadian cross) +AC_DEFUN(SIM_AC_OPTION_HOSTENDIAN, +[ +AC_ARG_ENABLE(sim-hostendian, +[ --enable-sim-hostendian=end Specify host byte endian orientation.], +[case "${enableval}" in + no) sim_hostendian="-DWITH_HOST_BYTE_ORDER=0";; + b*|B*) sim_hostendian="-DWITH_HOST_BYTE_ORDER=BIG_ENDIAN";; + l*|L*) sim_hostendian="-DWITH_HOST_BYTE_ORDER=LITTLE_ENDIAN";; + *) AC_MSG_ERROR("Unknown value $enableval for --enable-sim-hostendian"); sim_hostendian="";; +esac +if test x"$silent" != x"yes" && test x"$sim_hostendian" != x""; then + echo "Setting hostendian flags = $sim_hostendian" 6>&1 +fi],[ +if test "x$cross_compiling" = "xno"; then + AC_C_BIGENDIAN + if test $ac_cv_c_bigendian = yes; then + sim_hostendian="-DWITH_HOST_BYTE_ORDER=BIG_ENDIAN" + else + sim_hostendian="-DWITH_HOST_BYTE_ORDER=LITTLE_ENDIAN" + fi +else + sim_hostendian="-DWITH_HOST_BYTE_ORDER=0" +fi])dnl +]) +AC_SUBST(sim_hostendian) + + +dnl --enable-sim-float is for developers of the simulator +dnl It specifies the presence of hardware floating point +dnl And optionally the bitsize of the floating point register. +dnl arg[1] specifies the presence (or absence) of floating point hardware +dnl arg[2] specifies the number of bits in a floating point register +AC_DEFUN(SIM_AC_OPTION_FLOAT, +[ +default_sim_float="[$1]" +default_sim_float_bitsize="[$2]" +AC_ARG_ENABLE(sim-float, +[ --enable-sim-float Specify that the target processor has floating point hardware.], +[case "${enableval}" in + yes | hard) sim_float="-DWITH_FLOATING_POINT=HARD_FLOATING_POINT";; + no | soft) sim_float="-DWITH_FLOATING_POINT=SOFT_FLOATING_POINT";; + 32) sim_float="-DWITH_FLOATING_POINT=HARD_FLOATING_POINT -DWITH_TARGET_FLOATING_POINT_BITSIZE=32";; + 64) sim_float="-DWITH_FLOATING_POINT=HARD_FLOATING_POINT -DWITH_TARGET_FLOATING_POINT_BITSIZE=64";; + *) AC_MSG_ERROR("Unknown value $enableval passed to --enable-sim-float"); sim_float="";; +esac +if test x"$silent" != x"yes" && test x"$sim_float" != x""; then + echo "Setting float flags = $sim_float" 6>&1 +fi],[ +sim_float= +if test x"${default_sim_float}" != x""; then + sim_float="-DWITH_FLOATING_POINT=${default_sim_float}" +fi +if test x"${default_sim_float_bitsize}" != x""; then + sim_float="$sim_float -DWITH_TARGET_FLOATING_POINT_BITSIZE=${default_sim_float_bitsize}" +fi +])dnl +]) +AC_SUBST(sim_float) + + +dnl The argument is the default cache size if none is specified. +AC_DEFUN(SIM_AC_OPTION_SCACHE, +[ +default_sim_scache="ifelse([$1],,0,[$1])" +AC_ARG_ENABLE(sim-scache, +[ --enable-sim-scache=size Specify simulator execution cache size.], +[case "${enableval}" in + yes) sim_scache="-DWITH_SCACHE=${default_sim_scache}";; + no) sim_scache="-DWITH_SCACHE=0" ;; + [[0-9]]*) sim_cache=${enableval};; + *) AC_MSG_ERROR("Bad value $enableval passed to --enable-sim-scache"); + sim_scache="";; +esac +if test x"$silent" != x"yes" && test x"$sim_scache" != x""; then + echo "Setting scache size = $sim_scache" 6>&1 +fi],[sim_scache="-DWITH_SCACHE=${default_sim_scache}"]) +]) +AC_SUBST(sim_scache) + + +dnl The argument is the default model if none is specified. +AC_DEFUN(SIM_AC_OPTION_DEFAULT_MODEL, +[ +default_sim_default_model="ifelse([$1],,0,[$1])" +AC_ARG_ENABLE(sim-default-model, +[ --enable-sim-default-model=model Specify default model to simulate.], +[case "${enableval}" in + yes|no) AC_MSG_ERROR("Missing argument to --enable-sim-default-model");; + *) sim_default_model="-DWITH_DEFAULT_MODEL='\"${enableval}\"'";; +esac +if test x"$silent" != x"yes" && test x"$sim_default_model" != x""; then + echo "Setting default model = $sim_default_model" 6>&1 +fi],[sim_default_model="-DWITH_DEFAULT_MODEL='\"${default_sim_default_model}\"'"]) +]) +AC_SUBST(sim_default_model) + + +dnl --enable-sim-hardware is for users of the simulator +dnl arg[1] Enable sim-hw by default? ("yes" or "no") +dnl arg[2] is a space separated list of devices that override the defaults +dnl arg[3] is a space separated list of extra target specific devices. +AC_DEFUN(SIM_AC_OPTION_HARDWARE, +[ +if test x"[$1]" = x"yes"; then + sim_hw_p=yes +else + sim_hw_p=no +fi +if test "[$2]"; then + hardware="core pal glue" +else + hardware="core pal glue [$3]" +fi +sim_hw_cflags="-DWITH_HW=1" +sim_hw="$hardware" +sim_hw_objs="\$(SIM_COMMON_HW_OBJS) `echo $sim_hw | sed -e 's/\([[^ ]][[^ ]]*\)/dv-\1.o/g'`" +AC_ARG_ENABLE(sim-hardware, +[ --enable-sim-hardware=LIST Specify the hardware to be included in the build.], +[ +case "${enableval}" in + yes) sim_hw_p=yes;; + no) sim_hw_p=no;; + ,*) sim_hw_p=yes; hardware="${hardware} `echo ${enableval} | sed -e 's/,/ /'`";; + *,) sim_hw_p=yes; hardware="`echo ${enableval} | sed -e 's/,/ /'` ${hardware}";; + *) sim_hw_p=yes; hardware="`echo ${enableval} | sed -e 's/,/ /'`"'';; +esac +if test "$sim_hw_p" != yes; then + sim_hw_objs= + sim_hw_cflags="-DWITH_HW=0" + sim_hw= +else + sim_hw_cflags="-DWITH_HW=1" + # remove duplicates + sim_hw="" + sim_hw_objs="\$(SIM_COMMON_HW_OBJS)" + for i in x $hardware ; do + case " $f " in + x) ;; + *" $i "*) ;; + *) sim_hw="$sim_hw $i" ; sim_hw_objs="$sim_hw_objs dv-$i.o";; + esac + done +fi +if test x"$silent" != x"yes" && test "$sim_hw_p" = "yes"; then + echo "Setting hardware to $sim_hw_cflags, $sim_hw, $sim_hw_objs" +fi],[ +if test "$sim_hw_p" != yes; then + sim_hw_objs= + sim_hw_cflags="-DWITH_HW=0" + sim_hw= +fi +if test x"$silent" != x"yes"; then + echo "Setting hardware to $sim_hw_cflags, $sim_hw, $sim_hw_objs" +fi])dnl +]) +AC_SUBST(sim_hw_cflags) +AC_SUBST(sim_hw_objs) +AC_SUBST(sim_hw) + + +dnl --enable-sim-inline is for users that wish to ramp up the simulator's +dnl performance by inlining functions. +dnl Guarantee that unconfigured simulators do not do any inlining +sim_inline="-DDEFAULT_INLINE=0" +AC_DEFUN(SIM_AC_OPTION_INLINE, +[ +default_sim_inline="ifelse([$1],,,-DDEFAULT_INLINE=[$1])" +AC_ARG_ENABLE(sim-inline, +[ --enable-sim-inline=inlines Specify which functions should be inlined.], +[sim_inline="" +case "$enableval" in + no) sim_inline="-DDEFAULT_INLINE=0";; + 0) sim_inline="-DDEFAULT_INLINE=0";; + yes | 2) sim_inline="-DDEFAULT_INLINE=ALL_C_INLINE";; + 1) sim_inline="-DDEFAULT_INLINE=INLINE_LOCALS";; + *) for x in `echo "$enableval" | sed -e "s/,/ /g"`; do + new_flag="" + case "$x" in + *_INLINE=*) new_flag="-D$x";; + *=*) new_flag=`echo "$x" | sed -e "s/=/_INLINE=/" -e "s/^/-D/"`;; + *_INLINE) new_flag="-D$x=ALL_C_INLINE";; + *) new_flag="-D$x""_INLINE=ALL_C_INLINE";; + esac + if test x"$sim_inline" = x""; then + sim_inline="$new_flag" + else + sim_inline="$sim_inline $new_flag" + fi + done;; +esac +if test x"$silent" != x"yes" && test x"$sim_inline" != x""; then + echo "Setting inline flags = $sim_inline" 6>&1 +fi],[ +if test "x$cross_compiling" = "xno"; then + if test x"$GCC" != "x" -a x"${default_sim_inline}" != "x" ; then + sim_inline="${default_sim_inline}" + if test x"$silent" != x"yes"; then + echo "Setting inline flags = $sim_inline" 6>&1 + fi + else + sim_inline="" + fi +else + sim_inline="-DDEFAULT_INLINE=0" +fi])dnl +]) +AC_SUBST(sim_inline) + + +AC_DEFUN(SIM_AC_OPTION_PACKAGES, +[ +AC_ARG_ENABLE(sim-packages, +[ --enable-sim-packages=list Specify the packages to be included in the build.], +[packages=disklabel +case "${enableval}" in + yes) ;; + no) AC_MSG_ERROR("List of packages must be specified for --enable-sim-packages"); packages="";; + ,*) packages="${packages}${enableval}";; + *,) packages="${enableval}${packages}";; + *) packages="${enableval}"'';; +esac +sim_pk_src=`echo $packages | sed -e 's/,/.c pk_/g' -e 's/^/pk_/' -e 's/$/.c/'` +sim_pk_obj=`echo $sim_pk_src | sed -e 's/\.c/.o/g'` +if test x"$silent" != x"yes" && test x"$packages" != x""; then + echo "Setting packages to $sim_pk_src, $sim_pk_obj" +fi],[packages=disklabel +sim_pk_src=`echo $packages | sed -e 's/,/.c pk_/g' -e 's/^/pk_/' -e 's/$/.c/'` +sim_pk_obj=`echo $sim_pk_src | sed -e 's/\.c/.o/g'` +if test x"$silent" != x"yes"; then + echo "Setting packages to $sim_pk_src, $sim_pk_obj" +fi])dnl +]) +AC_SUBST(sim_packages) + + +AC_DEFUN(SIM_AC_OPTION_REGPARM, +[ +AC_ARG_ENABLE(sim-regparm, +[ --enable-sim-regparm=nr-parm Pass parameters in registers instead of on the stack - x86/GCC specific.], +[case "${enableval}" in + 0*|1*|2*|3*|4*|5*|6*|7*|8*|9*) sim_regparm="-DWITH_REGPARM=${enableval}";; + no) sim_regparm="" ;; + yes) sim_regparm="-DWITH_REGPARM=3";; + *) AC_MSG_ERROR("Unknown value $enableval for --enable-sim-regparm"); sim_regparm="";; +esac +if test x"$silent" != x"yes" && test x"$sim_regparm" != x""; then + echo "Setting regparm flags = $sim_regparm" 6>&1 +fi],[sim_regparm=""])dnl +]) +AC_SUBST(sim_regparm) + + +AC_DEFUN(SIM_AC_OPTION_RESERVED_BITS, +[ +default_sim_reserved_bits="ifelse([$1],,1,[$1])" +AC_ARG_ENABLE(sim-reserved-bits, +[ --enable-sim-reserved-bits Specify whether to check reserved bits in instruction.], +[case "${enableval}" in + yes) sim_reserved_bits="-DWITH_RESERVED_BITS=1";; + no) sim_reserved_bits="-DWITH_RESERVED_BITS=0";; + *) AC_MSG_ERROR("--enable-sim-reserved-bits does not take a value"); sim_reserved_bits="";; +esac +if test x"$silent" != x"yes" && test x"$sim_reserved_bits" != x""; then + echo "Setting reserved flags = $sim_reserved_bits" 6>&1 +fi],[sim_reserved_bits="-DWITH_RESERVED_BITS=${default_sim_reserved_bits}"])dnl +]) +AC_SUBST(sim_reserved_bits) + + +AC_DEFUN(SIM_AC_OPTION_SMP, +[ +default_sim_smp="ifelse([$1],,5,[$1])" +AC_ARG_ENABLE(sim-smp, +[ --enable-sim-smp=n Specify number of processors to configure for (default ${default_sim_smp}).], +[case "${enableval}" in + yes) sim_smp="-DWITH_SMP=5" ; sim_igen_smp="-N 5";; + no) sim_smp="-DWITH_SMP=0" ; sim_igen_smp="-N 0";; + *) sim_smp="-DWITH_SMP=$enableval" ; sim_igen_smp="-N $enableval";; +esac +if test x"$silent" != x"yes" && test x"$sim_smp" != x""; then + echo "Setting smp flags = $sim_smp" 6>&1 +fi],[sim_smp="-DWITH_SMP=${default_sim_smp}" ; sim_igen_smp="-N ${default_sim_smp}" +if test x"$silent" != x"yes"; then + echo "Setting smp flags = $sim_smp" 6>&1 +fi])dnl +]) +AC_SUBST(sim_smp) + + +AC_DEFUN(SIM_AC_OPTION_STDCALL, +[ +AC_ARG_ENABLE(sim-stdcall, +[ --enable-sim-stdcall=type Use an alternative function call/return mechanism - x86/GCC specific.], +[case "${enableval}" in + no) sim_stdcall="" ;; + std*) sim_stdcall="-DWITH_STDCALL=1";; + yes) sim_stdcall="-DWITH_STDCALL=1";; + *) AC_MSG_ERROR("Unknown value $enableval for --enable-sim-stdcall"); sim_stdcall="";; +esac +if test x"$silent" != x"yes" && test x"$sim_stdcall" != x""; then + echo "Setting function call flags = $sim_stdcall" 6>&1 +fi],[sim_stdcall=""])dnl +]) +AC_SUBST(sim_stdcall) + + +AC_DEFUN(SIM_AC_OPTION_XOR_ENDIAN, +[ +default_sim_xor_endian="ifelse([$1],,8,[$1])" +AC_ARG_ENABLE(sim-xor-endian, +[ --enable-sim-xor-endian=n Specify number bytes involved in XOR bi-endian mode (default ${default_sim_xor_endian}).], +[case "${enableval}" in + yes) sim_xor_endian="-DWITH_XOR_ENDIAN=8";; + no) sim_xor_endian="-DWITH_XOR_ENDIAN=0";; + *) sim_xor_endian="-DWITH_XOR_ENDIAN=$enableval";; +esac +if test x"$silent" != x"yes" && test x"$sim_xor_endian" != x""; then + echo "Setting xor-endian flag = $sim_xor_endian" 6>&1 +fi],[sim_xor_endian="-DWITH_XOR_ENDIAN=${default_sim_xor_endian}"])dnl +]) +AC_SUBST(sim_xor_endian) + + +dnl --enable-build-warnings is for developers of the simulator. +dnl it enables extra GCC specific warnings. +AC_DEFUN(SIM_AC_OPTION_WARNINGS, +[ +AC_ARG_ENABLE(build-warnings, +[ --enable-build-warnings[=LIST] Enable build-time compiler warnings], +[build_warnings="-Wall -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations" +case "${enableval}" in + yes) ;; + no) build_warnings="-w";; + ,*) t=`echo "${enableval}" | sed -e "s/,/ /g"` + build_warnings="${build_warnings} ${t}";; + *,) t=`echo "${enableval}" | sed -e "s/,/ /g"` + build_warnings="${t} ${build_warnings}";; + *) build_warnings=`echo "${enableval}" | sed -e "s/,/ /g"`;; +esac +if test x"$silent" != x"yes" && test x"$build_warnings" != x""; then + echo "Setting warning flags = $build_warnings" 6>&1 +fi],[build_warnings=""])dnl +]) +AC_SUBST(build_warnings) + + +dnl Generate the Makefile in a target specific directory. +dnl Substitutions aren't performed on the file in AC_SUBST_FILE, +dnl so this is a cover macro to tuck the details away of how we cope. +dnl We cope by having autoconf generate two files and then merge them into +dnl one afterwards. The two pieces of the common fragment are inserted into +dnl the target's fragment at the appropriate points. + +AC_DEFUN(SIM_AC_OUTPUT, +[ +AC_LINK_FILES($sim_link_files, $sim_link_links) +AC_OUTPUT(Makefile.sim:Makefile.in Make-common.sim:../common/Make-common.in .gdbinit:../common/gdbinit.in, +[case "x$CONFIG_FILES" in + xMakefile*) + echo "Merging Makefile.sim+Make-common.sim into Makefile ..." + rm -f Makesim1.tmp Makesim2.tmp Makefile + sed -n -e '/^## COMMON_PRE_/,/^## End COMMON_PRE_/ p' <Make-common.sim >Makesim1.tmp + sed -n -e '/^## COMMON_POST_/,/^## End COMMON_POST_/ p' <Make-common.sim >Makesim2.tmp + sed -e '/^## COMMON_PRE_/ r Makesim1.tmp' \ + -e '/^## COMMON_POST_/ r Makesim2.tmp' \ + <Makefile.sim >Makefile + rm -f Makefile.sim Make-common.sim Makesim1.tmp Makesim2.tmp + ;; + esac + case "x$CONFIG_HEADERS" in xconfig.h:config.in) echo > stamp-h ;; esac +]) +]) + +# This file is derived from `gettext.m4'. The difference is that the +# included macros assume Cygnus-style source and build trees. + +# Macro to add for using GNU gettext. +# Ulrich Drepper <drepper@cygnus.com>, 1995. +# +# This file file be copied and used freely without restrictions. It can +# be used in projects which are not available under the GNU Public License +# but which still want to provide support for the GNU gettext functionality. +# Please note that the actual code is *not* freely available. + +# serial 3 + +AC_DEFUN(CY_WITH_NLS, + [AC_MSG_CHECKING([whether NLS is requested]) + dnl Default is enabled NLS + AC_ARG_ENABLE(nls, + [ --disable-nls do not use Native Language Support], + USE_NLS=$enableval, USE_NLS=yes) + AC_MSG_RESULT($USE_NLS) + AC_SUBST(USE_NLS) + + USE_INCLUDED_LIBINTL=no + + dnl If we use NLS figure out what method + if test "$USE_NLS" = "yes"; then + AC_DEFINE(ENABLE_NLS) + AC_MSG_CHECKING([whether included gettext is requested]) + AC_ARG_WITH(included-gettext, + [ --with-included-gettext use the GNU gettext library included here], + nls_cv_force_use_gnu_gettext=$withval, + nls_cv_force_use_gnu_gettext=no) + AC_MSG_RESULT($nls_cv_force_use_gnu_gettext) + + nls_cv_use_gnu_gettext="$nls_cv_force_use_gnu_gettext" + if test "$nls_cv_force_use_gnu_gettext" != "yes"; then + dnl User does not insist on using GNU NLS library. Figure out what + dnl to use. If gettext or catgets are available (in this order) we + dnl use this. Else we have to fall back to GNU NLS library. + dnl catgets is only used if permitted by option --with-catgets. + nls_cv_header_intl= + nls_cv_header_libgt= + CATOBJEXT=NONE + + AC_CHECK_HEADER(libintl.h, + [AC_CACHE_CHECK([for gettext in libc], gt_cv_func_gettext_libc, + [AC_TRY_LINK([#include <libintl.h>], [return (int) gettext ("")], + gt_cv_func_gettext_libc=yes, gt_cv_func_gettext_libc=no)]) + + if test "$gt_cv_func_gettext_libc" != "yes"; then + AC_CHECK_LIB(intl, bindtextdomain, + [AC_CACHE_CHECK([for gettext in libintl], + gt_cv_func_gettext_libintl, + [AC_TRY_LINK([], [return (int) gettext ("")], + gt_cv_func_gettext_libintl=yes, + gt_cv_func_gettext_libintl=no)])]) + fi + + if test "$gt_cv_func_gettext_libc" = "yes" \ + || test "$gt_cv_func_gettext_libintl" = "yes"; then + AC_DEFINE(HAVE_GETTEXT) + AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt, + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"], no)dnl + if test "$MSGFMT" != "no"; then + AC_CHECK_FUNCS(dcgettext) + AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) + AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext, + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"], :) + AC_TRY_LINK(, [extern int _nl_msg_cat_cntr; + return _nl_msg_cat_cntr], + [CATOBJEXT=.gmo + DATADIRNAME=share], + [CATOBJEXT=.mo + DATADIRNAME=lib]) + INSTOBJEXT=.mo + fi + fi + ]) + + dnl In the standard gettext, we would now check for catgets. + dnl However, we never want to use catgets for our releases. + + if test "$CATOBJEXT" = "NONE"; then + dnl Neither gettext nor catgets in included in the C library. + dnl Fall back on GNU gettext library. + nls_cv_use_gnu_gettext=yes + fi + fi + + if test "$nls_cv_use_gnu_gettext" = "yes"; then + dnl Mark actions used to generate GNU NLS library. + INTLOBJS="\$(GETTOBJS)" + AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt, + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"], msgfmt) + AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) + AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext, + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"], :) + AC_SUBST(MSGFMT) + USE_INCLUDED_LIBINTL=yes + CATOBJEXT=.gmo + INSTOBJEXT=.mo + DATADIRNAME=share + INTLDEPS='$(top_builddir)/../intl/libintl.a' + INTLLIBS=$INTLDEPS + LIBS=`echo $LIBS | sed -e 's/-lintl//'` + nls_cv_header_intl=libintl.h + nls_cv_header_libgt=libgettext.h + fi + + dnl Test whether we really found GNU xgettext. + if test "$XGETTEXT" != ":"; then + dnl If it is no GNU xgettext we define it as : so that the + dnl Makefiles still can work. + if $XGETTEXT --omit-header /dev/null 2> /dev/null; then + : ; + else + AC_MSG_RESULT( + [found xgettext programs is not GNU xgettext; ignore it]) + XGETTEXT=":" + fi + fi + + # We need to process the po/ directory. + POSUB=po + else + DATADIRNAME=share + nls_cv_header_intl=libintl.h + nls_cv_header_libgt=libgettext.h + fi + + # If this is used in GNU gettext we have to set USE_NLS to `yes' + # because some of the sources are only built for this goal. + if test "$PACKAGE" = gettext; then + USE_NLS=yes + USE_INCLUDED_LIBINTL=yes + fi + + dnl These rules are solely for the distribution goal. While doing this + dnl we only have to keep exactly one list of the available catalogs + dnl in configure.in. + for lang in $ALL_LINGUAS; do + GMOFILES="$GMOFILES $lang.gmo" + POFILES="$POFILES $lang.po" + done + + dnl Make all variables we use known to autoconf. + AC_SUBST(USE_INCLUDED_LIBINTL) + AC_SUBST(CATALOGS) + AC_SUBST(CATOBJEXT) + AC_SUBST(DATADIRNAME) + AC_SUBST(GMOFILES) + AC_SUBST(INSTOBJEXT) + AC_SUBST(INTLDEPS) + AC_SUBST(INTLLIBS) + AC_SUBST(INTLOBJS) + AC_SUBST(POFILES) + AC_SUBST(POSUB) + ]) + +AC_DEFUN(CY_GNU_GETTEXT, + [AC_REQUIRE([AC_PROG_MAKE_SET])dnl + AC_REQUIRE([AC_PROG_CC])dnl + AC_REQUIRE([AC_PROG_RANLIB])dnl + AC_REQUIRE([AC_ISC_POSIX])dnl + AC_REQUIRE([AC_HEADER_STDC])dnl + AC_REQUIRE([AC_C_CONST])dnl + AC_REQUIRE([AC_C_INLINE])dnl + AC_REQUIRE([AC_TYPE_OFF_T])dnl + AC_REQUIRE([AC_TYPE_SIZE_T])dnl + AC_REQUIRE([AC_FUNC_ALLOCA])dnl + AC_REQUIRE([AC_FUNC_MMAP])dnl + + AC_CHECK_HEADERS([argz.h limits.h locale.h nl_types.h malloc.h string.h \ +unistd.h values.h sys/param.h]) + AC_CHECK_FUNCS([getcwd munmap putenv setenv setlocale strchr strcasecmp \ +__argz_count __argz_stringify __argz_next]) + + if test "${ac_cv_func_stpcpy+set}" != "set"; then + AC_CHECK_FUNCS(stpcpy) + fi + if test "${ac_cv_func_stpcpy}" = "yes"; then + AC_DEFINE(HAVE_STPCPY) + fi + + AM_LC_MESSAGES + CY_WITH_NLS + + if test "x$CATOBJEXT" != "x"; then + if test "x$ALL_LINGUAS" = "x"; then + LINGUAS= + else + AC_MSG_CHECKING(for catalogs to be installed) + NEW_LINGUAS= + for lang in ${LINGUAS=$ALL_LINGUAS}; do + case "$ALL_LINGUAS" in + *$lang*) NEW_LINGUAS="$NEW_LINGUAS $lang" ;; + esac + done + LINGUAS=$NEW_LINGUAS + AC_MSG_RESULT($LINGUAS) + fi + + dnl Construct list of names of catalog files to be constructed. + if test -n "$LINGUAS"; then + for lang in $LINGUAS; do CATALOGS="$CATALOGS $lang$CATOBJEXT"; done + fi + fi + + dnl The reference to <locale.h> in the installed <libintl.h> file + dnl must be resolved because we cannot expect the users of this + dnl to define HAVE_LOCALE_H. + if test $ac_cv_header_locale_h = yes; then + INCLUDE_LOCALE_H="#include <locale.h>" + else + INCLUDE_LOCALE_H="\ +/* The system does not provide the header <locale.h>. Take care yourself. */" + fi + AC_SUBST(INCLUDE_LOCALE_H) + + dnl Determine which catalog format we have (if any is needed) + dnl For now we know about two different formats: + dnl Linux libc-5 and the normal X/Open format + if test -f $srcdir/po2tbl.sed.in; then + if test "$CATOBJEXT" = ".cat"; then + AC_CHECK_HEADER(linux/version.h, msgformat=linux, msgformat=xopen) + + dnl Transform the SED scripts while copying because some dumb SEDs + dnl cannot handle comments. + sed -e '/^#/d' $srcdir/$msgformat-msg.sed > po2msg.sed + fi + dnl po2tbl.sed is always needed. + sed -e '/^#.*[^\\]$/d' -e '/^#$/d' \ + $srcdir/po2tbl.sed.in > po2tbl.sed + fi + + dnl In the intl/Makefile.in we have a special dependency which makes + dnl only sense for gettext. We comment this out for non-gettext + dnl packages. + if test "$PACKAGE" = "gettext"; then + GT_NO="#NO#" + GT_YES= + else + GT_NO= + GT_YES="#YES#" + fi + AC_SUBST(GT_NO) + AC_SUBST(GT_YES) + + MKINSTALLDIRS="\$(srcdir)/../../mkinstalldirs" + AC_SUBST(MKINSTALLDIRS) + + dnl *** For now the libtool support in intl/Makefile is not for real. + l= + AC_SUBST(l) + + dnl Generate list of files to be processed by xgettext which will + dnl be included in po/Makefile. But only do this if the po directory + dnl exists in srcdir. + if test -d $srcdir/po; then + test -d po || mkdir po + if test "x$srcdir" != "x."; then + if test "x`echo $srcdir | sed 's@/.*@@'`" = "x"; then + posrcprefix="$srcdir/" + else + posrcprefix="../$srcdir/" + fi + else + posrcprefix="../" + fi + rm -f po/POTFILES + sed -e "/^#/d" -e "/^\$/d" -e "s,.*, $posrcprefix& \\\\," -e "\$s/\(.*\) \\\\/\1/" \ + < $srcdir/po/POTFILES.in > po/POTFILES + fi + ]) + +# Search path for a program which passes the given test. +# Ulrich Drepper <drepper@cygnus.com>, 1996. +# +# This file file be copied and used freely without restrictions. It can +# be used in projects which are not available under the GNU Public License +# but which still want to provide support for the GNU gettext functionality. +# Please note that the actual code is *not* freely available. + +# serial 1 + +dnl AM_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR, +dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) +AC_DEFUN(AM_PATH_PROG_WITH_TEST, +[# Extract the first word of "$2", so it can be a program name with args. +set dummy $2; ac_word=[$]2 +AC_MSG_CHECKING([for $ac_word]) +AC_CACHE_VAL(ac_cv_path_$1, +[case "[$]$1" in + /*) + ac_cv_path_$1="[$]$1" # Let the user override the test with a path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in ifelse([$5], , $PATH, [$5]); do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if [$3]; then + ac_cv_path_$1="$ac_dir/$ac_word" + break + fi + fi + done + IFS="$ac_save_ifs" +dnl If no 4th arg is given, leave the cache variable unset, +dnl so AC_PATH_PROGS will keep looking. +ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" +])dnl + ;; +esac])dnl +$1="$ac_cv_path_$1" +if test -n "[$]$1"; then + AC_MSG_RESULT([$]$1) +else + AC_MSG_RESULT(no) +fi +AC_SUBST($1)dnl +]) + +# Check whether LC_MESSAGES is available in <locale.h>. +# Ulrich Drepper <drepper@cygnus.com>, 1995. +# +# This file file be copied and used freely without restrictions. It can +# be used in projects which are not available under the GNU Public License +# but which still want to provide support for the GNU gettext functionality. +# Please note that the actual code is *not* freely available. + +# serial 1 + +AC_DEFUN(AM_LC_MESSAGES, + [if test $ac_cv_header_locale_h = yes; then + AC_CACHE_CHECK([for LC_MESSAGES], am_cv_val_LC_MESSAGES, + [AC_TRY_LINK([#include <locale.h>], [return LC_MESSAGES], + am_cv_val_LC_MESSAGES=yes, am_cv_val_LC_MESSAGES=no)]) + if test $am_cv_val_LC_MESSAGES = yes; then + AC_DEFINE(HAVE_LC_MESSAGES) + fi + fi]) + +# Check to see if we're running under Cygwin32, without using +# AC_CANONICAL_*. If so, set output variable CYGWIN32 to "yes". +# Otherwise set it to "no". + +dnl AM_CYGWIN32() +dnl You might think we can do this by checking for a cygwin32-specific +dnl cpp define. +AC_DEFUN(AM_CYGWIN32, +[AC_CACHE_CHECK(for Cygwin32 environment, am_cv_cygwin32, +[AC_TRY_COMPILE(,[int main () { return __CYGWIN32__; }], +am_cv_cygwin32=yes, am_cv_cygwin32=no) +rm -f conftest*]) +CYGWIN32= +test "$am_cv_cygwin32" = yes && CYGWIN32=yes]) + +# Check to see if we're running under Win32, without using +# AC_CANONICAL_*. If so, set output variable EXEEXT to ".exe". +# Otherwise set it to "". + +dnl AM_EXEEXT() +dnl This knows we add .exe if we're building in the Cygwin32 +dnl environment. But if we're not, then it compiles a test program +dnl to see if there is a suffix for executables. +AC_DEFUN(AM_EXEEXT, +dnl AC_REQUIRE([AC_PROG_CC])AC_REQUIRE([AM_CYGWIN32]) +AC_MSG_CHECKING([for executable suffix]) +[AC_CACHE_VAL(am_cv_exeext, +[if test "$CYGWIN32" = yes; then +am_cv_exeext=.exe +else +cat > am_c_test.c << 'EOF' +int main() { +/* Nothing needed here */ +} +EOF +${CC-cc} -o am_c_test $CFLAGS $CPPFLAGS $LDFLAGS am_c_test.c $LIBS 1>&5 +am_cv_exeext=`ls am_c_test.* | grep -v am_c_test.c | sed -e s/am_c_test//` +rm -f am_c_test*]) +test x"${am_cv_exeext}" = x && am_cv_exeext=no +fi +EXEEXT="" +test x"${am_cv_exeext}" != xno && EXEEXT=${am_cv_exeext} +AC_MSG_RESULT(${am_cv_exeext}) +AC_SUBST(EXEEXT)]) + + +dnl --enable-cgen-maint support +AC_DEFUN(SIM_AC_OPTION_CGEN_MAINT, +[ +cgen_maint=no +dnl Default is to use one in build tree. +cgen=../../cgen/cgen +cgendir='$(srcdir)/../../cgen' +dnl Having --enable-maintainer-mode take arguments is another way to go. +dnl ??? One can argue --with is more appropriate if one wants to specify +dnl a directory name, but what we're doing here is an enable/disable kind +dnl of thing and specifying both --enable and --with is klunky. +dnl If you reeely want this to be --with, go ahead and change it. +AC_ARG_ENABLE(cgen-maint, +[ --enable-cgen-maint[=DIR] build cgen generated files], +[case "${enableval}" in + yes) cgen_maint=yes ;; + no) cgen_maint=no ;; + *) + # argument is cgen install directory (not implemented yet). + # Having a `share' directory might be more appropriate for the .scm, + # .cpu, etc. files. + cgendir=${cgen_maint}/lib/cgen + cgen=${cgendir}/bin/cgen + ;; +esac])dnl +dnl AM_CONDITIONAL(CGEN_MAINT, test x${cgen_maint} != xno) +if test x${cgen_maint} != xno ; then + CGEN_MAINT='' +else + CGEN_MAINT='#' +fi +AC_SUBST(CGEN_MAINT) +AC_SUBST(cgendir) +AC_SUBST(cgen) +]) diff --git a/sim/common/callback.c b/sim/common/callback.c new file mode 100644 index 0000000..e8a28c4 --- /dev/null +++ b/sim/common/callback.c @@ -0,0 +1,810 @@ +/* Remote target callback routines. + Copyright 1995, 1996, 1997 Free Software Foundation, Inc. + Contributed by Cygnus Solutions. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file provides a standard way for targets to talk to the host OS + level. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "ansidecl.h" +#ifdef ANSI_PROTOTYPES +#include <stdarg.h> +#else +#include <varargs.h> +#endif +#include <stdio.h> +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#ifdef HAVE_STRING_H +#include <string.h> +#else +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#endif +#include <errno.h> +#include <fcntl.h> +#include <time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "callback.h" +#include "targ-vals.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +/* ??? sim_cb_printf should be cb_printf, but until the callback support is + broken out of the simulator directory, these are here to not require + sim-utils.h. */ +void sim_cb_printf PARAMS ((host_callback *, const char *, ...)); +void sim_cb_eprintf PARAMS ((host_callback *, const char *, ...)); + +extern CB_TARGET_DEFS_MAP cb_init_syscall_map[]; +extern CB_TARGET_DEFS_MAP cb_init_errno_map[]; +extern CB_TARGET_DEFS_MAP cb_init_open_map[]; + +extern int system PARAMS ((const char *)); + +static int os_init PARAMS ((host_callback *)); +static int os_shutdown PARAMS ((host_callback *)); +static int os_unlink PARAMS ((host_callback *, const char *)); +static long os_time PARAMS ((host_callback *, long *)); +static int os_system PARAMS ((host_callback *, const char *)); +static int os_rename PARAMS ((host_callback *, const char *, const char *)); +static int os_write_stdout PARAMS ((host_callback *, const char *, int)); +static void os_flush_stdout PARAMS ((host_callback *)); +static int os_write_stderr PARAMS ((host_callback *, const char *, int)); +static void os_flush_stderr PARAMS ((host_callback *)); +static int os_write PARAMS ((host_callback *, int, const char *, int)); +static int os_read_stdin PARAMS ((host_callback *, char *, int)); +static int os_read PARAMS ((host_callback *, int, char *, int)); +static int os_open PARAMS ((host_callback *, const char *, int)); +static int os_lseek PARAMS ((host_callback *, int, long, int)); +static int os_isatty PARAMS ((host_callback *, int)); +static int os_get_errno PARAMS ((host_callback *)); +static int os_close PARAMS ((host_callback *, int)); +static void os_vprintf_filtered PARAMS ((host_callback *, const char *, va_list)); +static void os_evprintf_filtered PARAMS ((host_callback *, const char *, va_list)); +static void os_error PARAMS ((host_callback *, const char *, ...)); +static int fdmap PARAMS ((host_callback *, int)); +static int fdbad PARAMS ((host_callback *, int)); +static int wrap PARAMS ((host_callback *, int)); + +/* Set the callback copy of errno from what we see now. */ + +static int +wrap (p, val) + host_callback *p; + int val; +{ + p->last_errno = errno; + return val; +} + +/* Make sure the FD provided is ok. If not, return non-zero + and set errno. */ + +static int +fdbad (p, fd) + host_callback *p; + int fd; +{ + if (fd < 0 || fd > MAX_CALLBACK_FDS || !p->fdopen[fd]) + { + p->last_errno = EINVAL; + return -1; + } + return 0; +} + +static int +fdmap (p, fd) + host_callback *p; + int fd; +{ + return p->fdmap[fd]; +} + +static int +os_close (p, fd) + host_callback *p; + int fd; +{ + int result; + + result = fdbad (p, fd); + if (result) + return result; + result = wrap (p, close (fdmap (p, fd))); + if (result == 0 && !p->alwaysopen[fd]) + p->fdopen[fd] = 0; + + return result; +} + + +/* taken from gdb/util.c:notice_quit() - should be in a library */ + + +#if defined(__GO32__) || defined (_MSC_VER) +static int +os_poll_quit (p) + host_callback *p; +{ +#if defined(__GO32__) + int kbhit (); + int getkey (); + if (kbhit ()) + { + int k = getkey (); + if (k == 1) + { + return 1; + } + else if (k == 2) + { + return 1; + } + else + { + sim_cb_eprintf (p, "CTRL-A to quit, CTRL-B to quit harder\n"); + } + } +#endif +#if defined (_MSC_VER) + /* NB - this will not compile! */ + int k = win32pollquit(); + if (k == 1) + return 1; + else if (k == 2) + return 1; +#endif + return 0; +} +#else +#define os_poll_quit 0 +#endif /* defined(__GO32__) || defined(_MSC_VER) */ + +static int +os_get_errno (p) + host_callback *p; +{ + return cb_host_to_target_errno (p, p->last_errno); +} + + +static int +os_isatty (p, fd) + host_callback *p; + int fd; +{ + int result; + + result = fdbad (p, fd); + if (result) + return result; + result = wrap (p, isatty (fdmap (p, fd))); + + return result; +} + +static int +os_lseek (p, fd, off, way) + host_callback *p; + int fd; + long off; + int way; +{ + int result; + + result = fdbad (p, fd); + if (result) + return result; + result = lseek (fdmap (p, fd), off, way); + return result; +} + +static int +os_open (p, name, flags) + host_callback *p; + const char *name; + int flags; +{ + int i; + for (i = 0; i < MAX_CALLBACK_FDS; i++) + { + if (!p->fdopen[i]) + { + int f = open (name, cb_target_to_host_open (p, flags), 0644); + if (f < 0) + { + p->last_errno = errno; + return f; + } + p->fdopen[i] = 1; + p->fdmap[i] = f; + return i; + } + } + p->last_errno = EMFILE; + return -1; +} + +static int +os_read (p, fd, buf, len) + host_callback *p; + int fd; + char *buf; + int len; +{ + int result; + + result = fdbad (p, fd); + if (result) + return result; + result = wrap (p, read (fdmap (p, fd), buf, len)); + return result; +} + +static int +os_read_stdin (p, buf, len) + host_callback *p; + char *buf; + int len; +{ + return wrap (p, read (0, buf, len)); +} + +static int +os_write (p, fd, buf, len) + host_callback *p; + int fd; + const char *buf; + int len; +{ + int result; + int real_fd; + + result = fdbad (p, fd); + if (result) + return result; + real_fd = fdmap (p, fd); + switch (real_fd) + { + default: + result = wrap (p, write (real_fd, buf, len)); + break; + case 1: + result = p->write_stdout (p, buf, len); + break; + case 2: + result = p->write_stderr (p, buf, len); + break; + } + return result; +} + +static int +os_write_stdout (p, buf, len) + host_callback *p; + const char *buf; + int len; +{ + return fwrite (buf, 1, len, stdout); +} + +static void +os_flush_stdout (p) + host_callback *p; +{ + fflush (stdout); +} + +static int +os_write_stderr (p, buf, len) + host_callback *p; + const char *buf; + int len; +{ + return fwrite (buf, 1, len, stderr); +} + +static void +os_flush_stderr (p) + host_callback *p; +{ + fflush (stderr); +} + +static int +os_rename (p, f1, f2) + host_callback *p; + const char *f1; + const char *f2; +{ + return wrap (p, rename (f1, f2)); +} + + +static int +os_system (p, s) + host_callback *p; + const char *s; +{ + return wrap (p, system (s)); +} + +static long +os_time (p, t) + host_callback *p; + long *t; +{ + return wrap (p, time (t)); +} + + +static int +os_unlink (p, f1) + host_callback *p; + const char *f1; +{ + return wrap (p, unlink (f1)); +} + +static int +os_stat (p, file, buf) + host_callback *p; + const char *file; + struct stat *buf; +{ + /* ??? There is an issue of when to translate to the target layout. + One could do that inside this function, or one could have the + caller do it. It's more flexible to let the caller do it, though + I'm not sure the flexibility will ever be useful. */ + return wrap (p, stat (file, buf)); +} + +static int +os_fstat (p, fd, buf) + host_callback *p; + int fd; + struct stat *buf; +{ + if (fdbad (p, fd)) + return -1; + /* ??? There is an issue of when to translate to the target layout. + One could do that inside this function, or one could have the + caller do it. It's more flexible to let the caller do it, though + I'm not sure the flexibility will ever be useful. */ + return wrap (p, fstat (fdmap (p, fd), buf)); +} + +static int +os_shutdown (p) + host_callback *p; +{ + int i; + for (i = 0; i < MAX_CALLBACK_FDS; i++) + { + if (p->fdopen[i] && !p->alwaysopen[i]) { + close (p->fdmap[i]); + p->fdopen[i] = 0; + } + } + return 1; +} + +static int +os_init (p) + host_callback *p; +{ + int i; + + os_shutdown (p); + for (i = 0; i < 3; i++) + { + p->fdmap[i] = i; + p->fdopen[i] = 1; + p->alwaysopen[i] = 1; + } + + p->syscall_map = cb_init_syscall_map; + p->errno_map = cb_init_errno_map; + p->open_map = cb_init_open_map; + + return 1; +} + +/* DEPRECIATED */ + +/* VARARGS */ +static void +#ifdef ANSI_PROTOTYPES +os_printf_filtered (host_callback *p, const char *format, ...) +#else +os_printf_filtered (p, va_alist) + host_callback *p; + va_dcl +#endif +{ + va_list args; +#ifdef ANSI_PROTOTYPES + va_start (args, format); +#else + char *format; + + va_start (args); + format = va_arg (args, char *); +#endif + + vfprintf (stdout, format, args); + va_end (args); +} + +/* VARARGS */ +static void +#ifdef ANSI_PROTOTYPES +os_vprintf_filtered (host_callback *p, const char *format, va_list args) +#else +os_vprintf_filtered (p, format, args) + host_callback *p; + const char *format; + va_list args; +#endif +{ + vprintf (format, args); +} + +/* VARARGS */ +static void +#ifdef ANSI_PROTOTYPES +os_evprintf_filtered (host_callback *p, const char *format, va_list args) +#else +os_evprintf_filtered (p, format, args) + host_callback *p; + const char *format; + va_list args; +#endif +{ + vfprintf (stderr, format, args); +} + +/* VARARGS */ +static void +#ifdef ANSI_PROTOTYPES +os_error (host_callback *p, const char *format, ...) +#else +os_error (p, va_alist) + host_callback *p; + va_dcl +#endif +{ + va_list args; +#ifdef ANSI_PROTOTYPES + va_start (args, format); +#else + char *format; + + va_start (args); + format = va_arg (args, char *); +#endif + + vfprintf (stderr, format, args); + fprintf (stderr, "\n"); + + va_end (args); + exit (1); +} + +host_callback default_callback = +{ + os_close, + os_get_errno, + os_isatty, + os_lseek, + os_open, + os_read, + os_read_stdin, + os_rename, + os_system, + os_time, + os_unlink, + os_write, + os_write_stdout, + os_flush_stdout, + os_write_stderr, + os_flush_stderr, + + os_stat, + os_fstat, + + os_poll_quit, + + os_shutdown, + os_init, + + os_printf_filtered, /* deprecated */ + + os_vprintf_filtered, + os_evprintf_filtered, + os_error, + + 0, /* last errno */ + + { 0, }, /* fdmap */ + { 0, }, /* fdopen */ + { 0, }, /* alwaysopen */ + + 0, /* syscall_map */ + 0, /* errno_map */ + 0, /* open_map */ + 0, /* signal_map */ + 0, /* stat_map */ + + HOST_CALLBACK_MAGIC, +}; + +/* Read in a file describing the target's system call values. + E.g. maybe someone will want to use something other than newlib. + This assumes that the basic system call recognition and value passing/ + returning is supported. So maybe some coding/recompilation will be + necessary, but not as much. + + If an error occurs, the existing mapping is not changed. */ + +CB_RC +cb_read_target_syscall_maps (cb, file) + host_callback *cb; + const char *file; +{ + CB_TARGET_DEFS_MAP *syscall_map, *errno_map, *open_map, *signal_map; + const char *stat_map; + FILE *f; + + if ((f = fopen (file, "r")) == NULL) + return CB_RC_ACCESS; + + /* ... read in and parse file ... */ + + fclose (f); + return CB_RC_NO_MEM; /* FIXME:wip */ + + /* Free storage allocated for any existing maps. */ + if (cb->syscall_map) + free (cb->syscall_map); + if (cb->errno_map) + free (cb->errno_map); + if (cb->open_map) + free (cb->open_map); + if (cb->signal_map) + free (cb->signal_map); + if (cb->stat_map) + free ((PTR) cb->stat_map); + + cb->syscall_map = syscall_map; + cb->errno_map = errno_map; + cb->open_map = open_map; + cb->signal_map = signal_map; + cb->stat_map = stat_map; + + return CB_RC_OK; +} + +/* Translate the target's version of a syscall number to the host's. + This isn't actually the host's version, rather a canonical form. + ??? Perhaps this should be renamed to ..._canon_syscall. */ + +int +cb_target_to_host_syscall (cb, target_val) + host_callback *cb; + int target_val; +{ + CB_TARGET_DEFS_MAP *m; + + for (m = &cb->syscall_map[0]; m->target_val != -1; ++m) + if (m->target_val == target_val) + return m->host_val; + + return -1; +} + +/* FIXME: sort tables if large. + Alternatively, an obvious improvement for errno conversion is + to machine generate a function with a large switch(). */ + +/* Translate the host's version of errno to the target's. */ + +int +cb_host_to_target_errno (cb, host_val) + host_callback *cb; + int host_val; +{ + CB_TARGET_DEFS_MAP *m; + + for (m = &cb->errno_map[0]; m->host_val; ++m) + if (m->host_val == host_val) + return m->target_val; + + /* ??? Which error to return in this case is up for grabs. + Note that some missing values may have standard alternatives. + For now return 0 and require caller to deal with it. */ + return 0; +} + +/* Given a set of target bitmasks for the open system call, + return the host equivalent. + Mapping open flag values is best done by looping so there's no need + to machine generate this function. */ + +int +cb_target_to_host_open (cb, target_val) + host_callback *cb; + int target_val; +{ + int host_val = 0; + CB_TARGET_DEFS_MAP *m; + + for (m = &cb->open_map[0]; m->host_val != -1; ++m) + { + switch (m->target_val) + { + /* O_RDONLY can be (and usually is) 0 which needs to be treated + specially. */ + case TARGET_O_RDONLY : + case TARGET_O_WRONLY : + case TARGET_O_RDWR : + if ((target_val & (TARGET_O_RDONLY | TARGET_O_WRONLY | TARGET_O_RDWR)) + == m->target_val) + host_val |= m->host_val; + /* Handle the host/target differentiating between binary and + text mode. Only one case is of importance */ +#if ! defined (TARGET_O_BINARY) && defined (O_BINARY) + host_val |= O_BINARY; +#endif + break; + default : + if ((m->target_val & target_val) == m->target_val) + host_val |= m->host_val; + break; + } + } + + return host_val; +} + +/* Utility for cb_host_to_target_stat to store values in the target's + stat struct. */ + +static void +store (p, size, val, big_p) + char *p; + int size; + long val; /* ??? must be as big as target word size */ + int big_p; +{ + if (big_p) + { + p += size; + while (size-- > 0) + { + *--p = val; + val >>= 8; + } + } + else + { + while (size-- > 0) + { + *p++ = val; + val >>= 8; + } + } +} + +/* Translate a host's stat struct into a target's. + If HS is NULL, just compute the length of the buffer required, + TS is ignored. + + The result is the size of the target's stat struct, + or zero if an error occured during the translation. */ + +int +cb_host_to_target_stat (cb, hs, ts) + host_callback *cb; + const struct stat *hs; + PTR ts; +{ + const char *m = cb->stat_map; + char *p; + int big_p = 0; + + if (hs == NULL) + ts = NULL; + p = ts; + + while (m) + { + char *q = strchr (m, ','); + int size; + + /* FIXME: Use sscanf? */ + if (q == NULL) + { + /* FIXME: print error message */ + return 0; + } + size = atoi (q + 1); + if (size == 0) + { + /* FIXME: print error message */ + return 0; + } + + if (hs != NULL) + { + if (strncmp (m, "st_dev", q - m) == 0) + store (p, size, hs->st_dev, big_p); + else if (strncmp (m, "st_ino", q - m) == 0) + store (p, size, hs->st_ino, big_p); + /* FIXME:wip */ + else + store (p, size, 0, big_p); /* unsupported field, store 0 */ + } + + p += size; + m = strchr (q, ':'); + if (m) + ++m; + } + + return p - (char *) ts; +} + +/* Cover functions to the vfprintf callbacks. + + ??? If one thinks of the callbacks as a subsystem onto itself [or part of + a larger "remote target subsystem"] with a well defined interface, then + one would think that the subsystem would provide these. However, until + one is allowed to create such a subsystem (with its own source tree + independent of any particular user), such a critter can't exist. Thus + these functions are here for the time being. */ + +void +sim_cb_printf (host_callback *p, const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + p->vprintf_filtered (p, fmt, ap); + va_end (ap); +} + +void +sim_cb_eprintf (host_callback *p, const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + p->evprintf_filtered (p, fmt, ap); + va_end (ap); +} diff --git a/sim/common/cgen-cpu.h b/sim/common/cgen-cpu.h new file mode 100644 index 0000000..b212100 --- /dev/null +++ b/sim/common/cgen-cpu.h @@ -0,0 +1,98 @@ +/* Simulator header for cgen cpus. + Copyright (C) 1998, 1999 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef CGEN_CPU_H +#define CGEN_CPU_H + +/* Type of function that is ultimately called by sim_resume. */ +typedef void (ENGINE_FN) (SIM_CPU *); + +/* Type of function to do disassembly. */ +typedef void (CGEN_DISASSEMBLER) (SIM_CPU *, const CGEN_INSN *, + const ARGBUF *, IADDR pc_, char *buf_); + +/* Additional non-machine generated per-cpu data to go in SIM_CPU. + The member's name must be `cgen_cpu'. */ + +typedef struct { + /* Non-zero while cpu simulation is running. */ + int running_p; +#define CPU_RUNNING_P(cpu) ((cpu)->cgen_cpu.running_p) + + /* Instruction count. This is maintained even in fast mode to keep track + of simulator speed. */ + unsigned long insn_count; +#define CPU_INSN_COUNT(cpu) ((cpu)->cgen_cpu.insn_count) + + /* sim_resume handlers */ + ENGINE_FN *fast_engine_fn; +#define CPU_FAST_ENGINE_FN(cpu) ((cpu)->cgen_cpu.fast_engine_fn) + ENGINE_FN *full_engine_fn; +#define CPU_FULL_ENGINE_FN(cpu) ((cpu)->cgen_cpu.full_engine_fn) + + /* Maximum number of instructions per time slice. + When single stepping this is 1. If using the pbb model, this can be + more than 1. 0 means "as long as you want". */ + unsigned int max_slice_insns; +#define CPU_MAX_SLICE_INSNS(cpu) ((cpu)->cgen_cpu.max_slice_insns) + + /* Simulator's execution cache. + Allocate space for this even if not used as some simulators may have + one machine variant that uses the scache and another that doesn't and + we don't want members in this struct to move about. */ + CPU_SCACHE scache; + + /* Instruction descriptor table. */ + IDESC *idesc; +#define CPU_IDESC(cpu) ((cpu)->cgen_cpu.idesc) + + /* Whether the read,write,semantic entries (computed goto labels) have been + initialized or not. */ + int idesc_read_init_p; +#define CPU_IDESC_READ_INIT_P(cpu) ((cpu)->cgen_cpu.idesc_read_init_p) + int idesc_write_init_p; +#define CPU_IDESC_WRITE_INIT_P(cpu) ((cpu)->cgen_cpu.idesc_write_init_p) + int idesc_sem_init_p; +#define CPU_IDESC_SEM_INIT_P(cpu) ((cpu)->cgen_cpu.idesc_sem_init_p) + + /* Cpu descriptor table. + This is a CGEN created entity that contains the description file + turned into C code and tables for our use. */ + CGEN_CPU_DESC cpu_desc; +#define CPU_CPU_DESC(cpu) ((cpu)->cgen_cpu.cpu_desc) + + /* Function to fetch the insn data entry in the IDESC. */ + const CGEN_INSN * (*get_idata) (SIM_CPU *, int); +#define CPU_GET_IDATA(cpu) ((cpu)->cgen_cpu.get_idata) + + /* Disassembler. */ + CGEN_DISASSEMBLER *disassembler; +#define CPU_DISASSEMBLER(cpu) ((cpu)->cgen_cpu.disassembler) + + /* Allow slop in size calcs for case where multiple cpu types are supported + and space for the specified cpu is malloc'd at run time. */ + double slop; +} CGEN_CPU; + +/* Shorthand macro for fetching registers. + CPU_CGEN_HW is defined in cpu.h. */ +#define CPU(x) (CPU_CGEN_HW (current_cpu)->x) + +#endif /* CGEN_CPU_H */ diff --git a/sim/common/cgen-defs.h b/sim/common/cgen-defs.h new file mode 100644 index 0000000..d3c9a8a --- /dev/null +++ b/sim/common/cgen-defs.h @@ -0,0 +1,174 @@ +/* General Cpu tools GENerated simulator support. + Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef CGEN_DEFS_H +#define CGEN_DEFS_H + +/* Compute number of longs required to hold N bits. */ +#define HOST_LONGS_FOR_BITS(n) \ + (((n) + sizeof (long) * 8 - 1) / sizeof (long) * 8) + +/* Forward decls. Defined in the machine generated files. */ + +/* This holds the contents of the extracted insn. + There are a few common entries (e.g. pc address), and then one big + union with an entry for each of the instruction formats. */ +typedef struct argbuf ARGBUF; + +/* ARGBUF accessors. */ +#define ARGBUF_ADDR(abuf) ((abuf)->addr) +#define ARGBUF_IDESC(abuf) ((abuf)->idesc) +#define ARGBUF_TRACE_P(abuf) ((abuf)->trace_p) +#define ARGBUF_PROFILE_P(abuf) ((abuf)->profile_p) + +/* This is one ARGBUF plus whatever else is needed for WITH_SCACHE support. + At present there is nothing else, but it also provides a level of + abstraction. */ +typedef struct scache SCACHE; + +/* This is a union with one entry for each instruction format. + Each entry contains all of the non-constant inputs of the instruction + in the case of read-before-exec support, or all outputs of the instruction + in the case of write-after-exec support. */ +typedef struct parexec PAREXEC; + +/* An "Instruction DESCriptor". + This is the main handle on an instruction for the simulator. */ +typedef struct idesc IDESC; + +/* Engine support. + ??? This is here because it's needed before eng.h (built by genmloop.sh) + which is needed before cgen-engine.h and cpu.h. + ??? This depends on a cpu family specific type, IADDR, but no machine + generated headers will have been included yet. sim/common currently + requires the typedef of sim_cia in sim-main.h between the inclusion of + sim-basics.h and sim-base.h so this is no different. */ + +/* SEM_ARG is intended to hide whether or not the scache is in use from the + semantic routines. In reality for the with-extraction case it is always + an SCACHE * even when not using the SCACHE since there's no current win to + making it something else ("not using the SCACHE" is like having a cache + size of 1). + The without-extraction case still uses an ARGBUF: + - consistency with scache version + - still need to record which operands are written + This wouldn't be needed if modeling was done in the semantic routines + but this isn't as general as handling it outside of the semantic routines. + For example Shade allows calling user-supplied code before/after each + instruction and this is something that is being planned. + ??? There is still some clumsiness in how much of ARGBUF to use. */ +typedef SCACHE *SEM_ARG; + +/* instruction address + ??? This was intended to be a struct of two elements in the WITH_SCACHE_PBB + case. The first element is the IADDR, the second element is the SCACHE *. + Haven't found the time yet to make this work, but it seemed a nicer approach + than the current br_cache stuff. */ +typedef IADDR PCADDR; + +/* Current instruction address, used by common. */ +typedef IADDR CIA; + +/* Semantic routines' version of the PC. */ +#if WITH_SCACHE_PBB +typedef SCACHE *SEM_PC; +#else +typedef IADDR SEM_PC; +#endif + +/* Virtual insn support. */ + +/* Opcode table for virtual insns (only used by the simulator). */ +extern const CGEN_INSN cgen_virtual_insn_table[]; + +/* -ve of indices of virtual insns in cgen_virtual_insn_table. */ +typedef enum { + VIRTUAL_INSN_X_INVALID = 0, + VIRTUAL_INSN_X_BEFORE = -1, VIRTUAL_INSN_X_AFTER = -2, + VIRTUAL_INSN_X_BEGIN = -3, + VIRTUAL_INSN_X_CHAIN= -4, VIRTUAL_INSN_X_CTI_CHAIN = -5 +} CGEN_INSN_VIRTUAL_TYPE; + +/* Return non-zero if OPCODE is a virtual insn. */ +#define CGEN_INSN_VIRTUAL_P(insn) \ + CGEN_INSN_ATTR_VALUE ((insn), CGEN_INSN_VIRTUAL) + +/* GNU C's "computed goto" facility is used to speed things up where + possible. These macros provide a portable way to use them. + Nesting of these switch statements is done by providing an extra argument + that distinguishes them. `N' can be a number or symbol. + Variable `labels_##N' must be initialized with the labels of each case. */ + +#ifdef __GNUC__ +#define SWITCH(N, X) goto *X; +#define CASE(N, X) case_##N##_##X +#define BREAK(N) goto end_switch_##N +#define DEFAULT(N) default_##N +#define ENDSWITCH(N) end_switch_##N: +#else +#define SWITCH(N, X) switch (X) +#define CASE(N, X) case X /* FIXME: old sem-switch had (@arch@_,X) here */ +#define BREAK(N) break +#define DEFAULT(N) default +#define ENDSWITCH(N) +#endif + +/* Simulator state. */ + +/* Records simulator descriptor so utilities like @cpu@_dump_regs can be + called from gdb. */ +extern SIM_DESC current_state; + +/* Simulator state. */ + +/* CGEN_STATE contains additional state information not present in + sim_state_base. */ + +typedef struct cgen_state { + /* FIXME: Moved to sim_state_base. */ + /* argv, env */ + char **argv; +#define STATE_ARGV(s) ((s) -> cgen_state.argv) + /* FIXME: Move to sim_state_base. */ + char **envp; +#define STATE_ENVP(s) ((s) -> cgen_state.envp) + + /* Non-zero if no tracing or profiling is selected. */ + int run_fast_p; +#define STATE_RUN_FAST_P(sd) ((sd) -> cgen_state.run_fast_p) +} CGEN_STATE; + +/* Various utilities. */ + +/* Called after sim_post_argv_init to do any cgen initialization. */ +extern void cgen_init (SIM_DESC); + +/* Return the name of an insn. */ +extern CPU_INSN_NAME_FN cgen_insn_name; + +/* Return the maximum number of extra bytes required for a sim_cpu struct. */ +/* ??? Ok, yes, this is less pretty than it should be. Give me a better + language [or suggest a better way]. */ +extern int cgen_cpu_max_extra_bytes (void); + +/* Called to process an invalid instruction. */ +extern void sim_engine_invalid_insn (SIM_CPU *, IADDR); + +#endif /* CGEN_DEFS_H */ diff --git a/sim/common/cgen-engine.h b/sim/common/cgen-engine.h new file mode 100644 index 0000000..9421332 --- /dev/null +++ b/sim/common/cgen-engine.h @@ -0,0 +1,473 @@ +/* Engine header for Cpu tools GENerated simulators. + Copyright (C) 1998, 1999 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file must be included after eng.h and before ${cpu}.h. */ + +/* Semantic functions come in six versions on two axes: + fast/full-featured, and using one of the simple/scache/compilation engines. + A full featured simulator is always provided. --enable-sim-fast includes + support for fast execution by duplicating the semantic code but leaving + out all features like tracing and profiling. + Using the scache is selected with --enable-sim-scache. */ +/* FIXME: --enable-sim-fast not implemented yet. */ +/* FIXME: undecided how to handle WITH_SCACHE_PBB. */ + +/* There are several styles of engines, all generally supported by the + same code: + + WITH_SCACHE && WITH_SCACHE_PBB - pseudo-basic-block scaching + WITH_SCACHE && !WITH_SCACHE_PBB - scaching on an insn by insn basis + !WITH_SCACHE - simple engine: fetch an insn, execute an insn + + The !WITH_SCACHE case can also be broken up into two flavours: + extract the fields of the insn into an ARGBUF struct, or defer the + extraction to the semantic handler. The former can be viewed as the + WITH_SCACHE case with a cache size of 1 (thus there's no need for a + WITH_EXTRACTION macro). The WITH_SCACHE case always extracts the fields + into an ARGBUF struct. */ + +#ifndef CGEN_ENGINE_H +#define CGEN_ENGINE_H + +/* Instruction field support macros. */ + +#define EXTRACT_MSB0_INT(val, total, start, length) \ +(((INT) (val) << ((sizeof (INT) * 8) - (total) + (start))) \ + >> ((sizeof (INT) * 8) - (length))) +#define EXTRACT_MSB0_UINT(val, total, start, length) \ +(((UINT) (val) << ((sizeof (UINT) * 8) - (total) + (start))) \ + >> ((sizeof (UINT) * 8) - (length))) + +#define EXTRACT_LSB0_INT(val, total, start, length) \ +(((INT) (val) << ((sizeof (INT) * 8) - (start) - 1)) \ + >> ((sizeof (INT) * 8) - (length))) +#define EXTRACT_LSB0_UINT(val, total, start, length) \ +(((UINT) (val) << ((sizeof (UINT) * 8) - (start) - 1)) \ + >> ((sizeof (UINT) * 8) - (length))) + +#if CGEN_INSN_LSB0_P + +#define EXTRACT_INT(val, total, start, length) \ + EXTRACT_LSB0_INT ((val), (total), (start), (length)) +#define EXTRACT_UINT(val, total, start, length) \ + EXTRACT_LSB0_UINT ((val), (total), (start), (length)) + +#else + +#define EXTRACT_INT(val, total, start, length) \ + EXTRACT_MSB0_INT ((val), (total), (start), (length)) +#define EXTRACT_UINT(val, total, start, length) \ + EXTRACT_MSB0_UINT ((val), (total), (start), (length)) + +#endif + +/* Semantic routines. */ + +/* Type of the machine generated extraction fns. */ +/* ??? No longer used. */ +typedef void (EXTRACT_FN) (SIM_CPU *, IADDR, CGEN_INSN_INT, ARGBUF *); + +/* Type of the machine generated semantic fns. */ + +#if WITH_SCACHE + +/* Instruction fields are extracted into ARGBUF before calling the + semantic routine. */ +#if HAVE_PARALLEL_INSNS +typedef SEM_PC (SEMANTIC_FN) (SIM_CPU *, SEM_ARG, PAREXEC *); +#else +typedef SEM_PC (SEMANTIC_FN) (SIM_CPU *, SEM_ARG); +#endif + +#else + +/* Result of semantic routines is a status indicator (wip). */ +typedef unsigned int SEM_STATUS; + +/* Instruction fields are extracted by the semantic routine. + ??? TODO: multi word insns. */ +#if HAVE_PARALLEL_INSNS +typedef SEM_STATUS (SEMANTIC_FN) (SIM_CPU *, SEM_ARG, PAREXEC *, CGEN_INSN_INT); +#else +typedef SEM_STATUS (SEMANTIC_FN) (SIM_CPU *, SEM_ARG, CGEN_INSN_INT); +#endif + +#endif + +/* In the ARGBUF struct, a pointer to the semantic routine for the insn. */ + +union sem { +#if ! WITH_SEM_SWITCH_FULL + SEMANTIC_FN *sem_full; +#endif +#if ! WITH_SEM_SWITCH_FAST + SEMANTIC_FN *sem_fast; +#endif +#if WITH_SEM_SWITCH_FULL || WITH_SEM_SWITCH_FAST +#ifdef __GNUC__ + void *sem_case; +#else + int sem_case; +#endif +#endif +}; + +/* Set the appropriate semantic handler in ABUF. */ + +#if WITH_SEM_SWITCH_FULL +#ifdef __GNUC__ +#define SEM_SET_FULL_CODE(abuf, idesc) \ + do { (abuf)->semantic.sem_case = (idesc)->sem_full_lab; } while (0) +#else +#define SEM_SET_FULL_CODE(abuf, idesc) \ + do { (abuf)->semantic.sem_case = (idesc)->num; } while (0) +#endif +#else +#define SEM_SET_FULL_CODE(abuf, idesc) \ + do { (abuf)->semantic.sem_full = (idesc)->sem_full; } while (0) +#endif + +#if WITH_SEM_SWITCH_FAST +#ifdef __GNUC__ +#define SEM_SET_FAST_CODE(abuf, idesc) \ + do { (abuf)->semantic.sem_case = (idesc)->sem_fast_lab; } while (0) +#else +#define SEM_SET_FAST_CODE(abuf, idesc) \ + do { (abuf)->semantic.sem_case = (idesc)->num; } while (0) +#endif +#else +#define SEM_SET_FAST_CODE(abuf, idesc) \ + do { (abuf)->semantic.sem_fast = (idesc)->sem_fast; } while (0) +#endif + +#define SEM_SET_CODE(abuf, idesc, fast_p) \ +do { \ + if (fast_p) \ + SEM_SET_FAST_CODE ((abuf), (idesc)); \ + else \ + SEM_SET_FULL_CODE ((abuf), (idesc)); \ +} while (0) + +/* Return non-zero if IDESC is a conditional or unconditional CTI. */ + +#define IDESC_CTI_P(idesc) \ + ((CGEN_ATTR_BOOLS (CGEN_INSN_ATTRS ((idesc)->idata)) \ + & (CGEN_ATTR_MASK (CGEN_INSN_COND_CTI) \ + | CGEN_ATTR_MASK (CGEN_INSN_UNCOND_CTI))) \ + != 0) + +/* Return non-zero if IDESC is a skip insn. */ + +#define IDESC_SKIP_P(idesc) \ + ((CGEN_ATTR_BOOLS (CGEN_INSN_ATTRS ((idesc)->idata)) \ + & CGEN_ATTR_MASK (CGEN_INSN_SKIP_CTI)) \ + != 0) + +/* These are used so that we can compile two copies of the semantic code, + one with full feature support and one without that runs fast(er). */ +#define SEM_FN_NAME(cpu,fn) XCONCAT3 (cpu,_sem_,fn) +#define SEMF_FN_NAME(cpu,fn) XCONCAT3 (cpu,_semf_,fn) + +/* Return pointer to ARGBUF given ptr to SCACHE. */ +#define SEM_ARGBUF(sem_arg) (& (sem_arg) -> argbuf) + +/* There are several styles of engines, all generally supported by the + same code: + + WITH_SCACHE && WITH_SCACHE_PBB - pseudo-basic-block scaching + WITH_SCACHE && !WITH_SCACHE_PBB - scaching on an insn by insn basis + !WITH_SCACHE - simple engine: fetch an insn, execute an insn + + ??? The !WITH_SCACHE case can also be broken up into two flavours: + extract the fields of the insn into an ARGBUF struct, or defer the + extraction to the semantic handler. The WITH_SCACHE case always + extracts the fields into an ARGBUF struct. */ + +#if WITH_SCACHE + +#define CIA_ADDR(cia) (cia) + +#if WITH_SCACHE_PBB + +/* Return the scache pointer of the current insn. */ +#define SEM_SEM_ARG(vpc, sc) (vpc) + +/* Return the virtual pc of the next insn to execute + (assuming this isn't a cti or the branch isn't taken). */ +#define SEM_NEXT_VPC(sem_arg, pc, len) ((sem_arg) + 1) + +/* Update the instruction counter. */ +#define PBB_UPDATE_INSN_COUNT(cpu,sc) \ + (CPU_INSN_COUNT (cpu) += SEM_ARGBUF (sc) -> fields.chain.insn_count) + +/* Value for br_addr_ptr indicating branch wasn't taken. */ +#define SEM_BRANCH_UNTAKEN ((SEM_PC *) 0) + +/* Value for br_addr_ptr indicating branch was taken to uncacheable + address (e.g. j reg). */ +#define SEM_BRANCH_UNCACHEABLE ((SEM_PC *) 1) + +/* Initialize next-pbb link for SEM_BRANCH_VIA_CACHE. */ +#define SEM_BRANCH_INIT_EXTRACT(abuf) \ +do { (abuf)->fields.cti.addr_cache = 0; } while (0) + +/* Do not append a `;' to invocations of this. + npc,npc_ptr are for communication between the cti insn and cti-chain. */ +#define SEM_BRANCH_INIT \ + IADDR npc = 0; /* assign a value for -Wall */ \ + SEM_PC *npc_ptr = SEM_BRANCH_UNTAKEN; + +/* SEM_IN_SWITCH is defined at the top of the mainloop.c files + generated by genmloop.sh. It exists so generated semantic code needn't + care whether it's being put in a switch or in a function. */ +#ifdef SEM_IN_SWITCH +#define SEM_BRANCH_FINI(pcvar) \ +do { \ + pbb_br_npc = npc; \ + pbb_br_npc_ptr = npc_ptr; \ +} while (0) +#else /* 1 semantic function per instruction */ +#define SEM_BRANCH_FINI(pcvar) \ +do { \ + CPU_PBB_BR_NPC (current_cpu) = npc; \ + CPU_PBB_BR_NPC_PTR (current_cpu) = npc_ptr; \ +} while (0) +#endif + +/* Return address of cached branch address value. */ +#define SEM_BRANCH_ADDR_CACHE(sem_arg) \ + (& SEM_ARGBUF (sem_arg)->fields.cti.addr_cache) + +#define SEM_BRANCH_VIA_CACHE(cpu, sc, newval, pcvar, cachevarptr) \ +do { \ + npc = (newval); \ + npc_ptr = (cachevarptr); \ +} while (0) + +#define SEM_BRANCH_VIA_ADDR(cpu, sc, newval, pcvar) \ +do { \ + npc = (newval); \ + npc_ptr = SEM_BRANCH_UNCACHEABLE; \ +} while (0) + +#else /* ! WITH_SCACHE_PBB */ + +#define SEM_SEM_ARG(vpc, sc) (sc) + +#define SEM_NEXT_VPC(sem_arg, pc, len) ((pc) + (len)) + +#define SEM_BRANCH_INIT_EXTRACT(abuf) do { } while (0) + +/* ??? May wish to move taken_p out of here and make it explicit. */ +#define SEM_BRANCH_INIT \ + int taken_p = 0; + +#ifndef TARGET_SEM_BRANCH_FINI(pcvar, taken_p) +#define TARGET_SEM_BRANCH_FINI(pcvar, taken_p) +#endif +#define SEM_BRANCH_FINI(pcvar) \ + do { TARGET_SEM_BRANCH_FINI (pcvar, taken_p); } while (0) + +#define SEM_BRANCH_ADDR_CACHE(sem_arg) shouldnt_be_used + +#define SEM_BRANCH_VIA_CACHE(cpu, sc, newval, pcvar, cachevar) \ +do { \ + (pcvar) = (newval); \ + taken_p = 1; \ +} while (0) + +#define SEM_BRANCH_VIA_ADDR(cpu, sc, newval, pcvar) \ +do { \ + (pcvar) = (newval); \ + taken_p = 1; \ +} while (0) + +#endif /* ! WITH_SCACHE_PBB */ + +#else /* ! WITH_SCACHE */ + +/* This is the "simple" engine case. */ + +#define CIA_ADDR(cia) (cia) + +#define SEM_SEM_ARG(vpc, sc) (sc) + +#define SEM_NEXT_VPC(sem_arg, pc, len) ((pc) + (len)) + +#define SEM_BRANCH_INIT \ + int taken_p = 0; + +#define SEM_BRANCH_ADDR_CACHE(sem_arg) shouldnt_be_used + +#define SEM_BRANCH_VIA_CACHE(cpu, abuf, newval, pcvar, cachevar) \ +do { \ + (pcvar) = (newval); \ + taken_p = 1; \ +} while (0) + +#define SEM_BRANCH_VIA_ADDR(cpu, abuf, newval, pcvar) \ +do { \ + (pcvar) = (newval); \ + taken_p = 1; \ +} while (0) + +/* Finish off branch insns. + The target must define TARGET_SEM_BRANCH_FINI. + ??? This can probably go away when define-execute is finished. */ +#define SEM_BRANCH_FINI(pcvar, bool_attrs) \ + do { TARGET_SEM_BRANCH_FINI ((pcvar), (bool_attrs), taken_p); } while (0) + +/* Finish off non-branch insns. + The target must define TARGET_SEM_NBRANCH_FINI. + ??? This can probably go away when define-execute is finished. */ +#define SEM_NBRANCH_FINI(pcvar, bool_attrs) \ + do { TARGET_SEM_NBRANCH_FINI ((pcvar), (bool_attrs)); } while (0) + +#endif /* ! WITH_SCACHE */ + +/* Instruction information. */ + +/* Compile time computable instruction data. + + ??? May wish to move parallel execution support into its own struct. + It's a fair bit of "clutter" for the "normal" case. */ + +struct insn_sem { + /* The instruction type (a number that identifies each insn over the + entire architecture). */ + CGEN_INSN_TYPE type; + + /* Index in IDESC table. */ + int index; + + /* Sanity check, at most one of these may be true. */ +#if WITH_PARALLEL_READ && WITH_PARALLEL_WRITE +#error "Both WITH_PARALLEL_READ && WITH_PARALLEL_WRITE can't be true." +#endif + +#if WITH_PARALLEL_READ || WITH_PARALLEL_WRITE + /* Index in IDESC table of parallel handler. */ + int par_index; +#endif + +#if WITH_PARALLEL_READ +#ifndef __GNUC__ + /* Semantic format number of pre-read handler. + Only used by chips that support parallel execution of several insns. + It is always implemented as a `switch'. In the case of GNUC we use + computed gotos. When not GNUC, this is the argument to `switch'. */ + int fmt; +#endif +#endif + +#if WITH_PARALLEL_WRITE + /* Index in IDESC table of writeback handler. + Only used by chips that support parallel execution of several insns. */ + int write_index; +#endif + + /* Routines to execute the insn. + The full version has all features (profiling,tracing) compiled in. + The fast version has none of that. */ +#if ! WITH_SEM_SWITCH_FULL + SEMANTIC_FN *sem_full; +#endif +#if WITH_FAST && ! WITH_SEM_SWITCH_FAST + SEMANTIC_FN *sem_fast; +#endif +}; + +/* Run-time computed instruction descriptor. */ + +struct idesc { + /* Parallel read-before-exec support. */ +#if WITH_PARALLEL_READ + struct idesc *par_idesc; +#ifdef __GNUC__ + void *read; +#else + int fmt; +#endif +#endif + + /* Parallel write-after-exec support. */ +#if WITH_PARALLEL_WRITE + /* Pointer to parallel handler if serial insn. + Pointer to writeback handler if parallel insn. */ + struct idesc *par_idesc; +#endif + +#if WITH_SEM_SWITCH_FULL +#ifdef __GNUC__ + void *sem_full_lab; +#else + /* nothing needed, switch's on `num' member */ +#endif +#else + SEMANTIC_FN *sem_full; +#endif + +#if WITH_SEM_SWITCH_FAST +#ifdef __GNUC__ + void *sem_fast_lab; +#else + /* nothing needed, switch's on `num' member */ +#endif +#else + SEMANTIC_FN *sem_fast; +#endif + + /* Instruction number (index in IDESC table, profile table). + Also used to switch on in non-gcc semantic switches. */ + int num; + + /* instruction data (name, attributes, size, etc.) */ + const CGEN_INSN *idata; + + /* instruction attributes, copied from `idata' for speed */ + const CGEN_INSN_ATTR_TYPE *attrs; + + /* instruction length in bytes, copied from `idata' for speed */ + int length; + + /* profiling/modelling support */ + const INSN_TIMING *timing; +}; + +/* Tracing/profiling. */ + +/* Return non-zero if a before/after handler is needed. + When tracing/profiling a selected range there's no need to slow + down simulation of the other insns (except to get more accurate data!). + + ??? May wish to profile all insns if doing insn tracing, or to + get more accurate cycle data. + + First test ANY_P so we avoid a potentially expensive HIT_P call + [if there are lots of address ranges]. */ + +#define PC_IN_TRACE_RANGE_P(cpu, pc) \ + (TRACE_ANY_P (cpu) \ + && ADDR_RANGE_HIT_P (TRACE_RANGE (CPU_TRACE_DATA (cpu)), (pc))) +#define PC_IN_PROFILE_RANGE_P(cpu, pc) \ + (PROFILE_ANY_P (cpu) \ + && ADDR_RANGE_HIT_P (PROFILE_RANGE (CPU_PROFILE_DATA (cpu)), (pc))) + +#endif /* CGEN_ENGINE_H */ diff --git a/sim/common/cgen-mem.h b/sim/common/cgen-mem.h new file mode 100644 index 0000000..c91ccb3 --- /dev/null +++ b/sim/common/cgen-mem.h @@ -0,0 +1,203 @@ +/* Memory ops header for CGEN-based simulators. + Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + Contributed by Cygnus Solutions. + +This file is part of the GNU Simulators. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef CGEN_MEM_H +#define CGEN_MEM_H + +#ifdef MEMOPS_DEFINE_INLINE +#define MEMOPS_INLINE +#else +#define MEMOPS_INLINE extern inline +#endif + +/* Memory read support. */ + +#if defined (__GNUC__) || defined (MEMOPS_DEFINE_INLINE) +#define DECLARE_GETMEM(mode, size) \ +MEMOPS_INLINE mode \ +XCONCAT2 (GETMEM,mode) (SIM_CPU *cpu, IADDR pc, ADDR a) \ +{ \ + PROFILE_COUNT_READ (cpu, a, XCONCAT2 (MODE_,mode)); \ + /* Don't read anything into "unaligned" here. Bad name choice. */\ + return XCONCAT2 (sim_core_read_unaligned_,size) (cpu, pc, read_map, a); \ +} +#else +#define DECLARE_GETMEM(mode, size) \ +extern mode XCONCAT2 (GETMEM,mode) (SIM_CPU *, IADDR, ADDR); +#endif + +DECLARE_GETMEM (QI, 1) +DECLARE_GETMEM (UQI, 1) +DECLARE_GETMEM (HI, 2) +DECLARE_GETMEM (UHI, 2) +DECLARE_GETMEM (SI, 4) +DECLARE_GETMEM (USI, 4) +DECLARE_GETMEM (DI, 8) +DECLARE_GETMEM (UDI, 8) + +#undef DECLARE_GETMEM + +#if defined (__GNUC__) || defined (MEMOPS_DEFINE_INLINE) +#define DECLARE_GETMEM(mode, size) \ +MEMOPS_INLINE mode \ +XCONCAT2 (GETMEM,mode) (SIM_CPU *cpu, IADDR pc, ADDR a) \ +{ \ + PROFILE_COUNT_READ (cpu, a, XCONCAT2 (MODE_,mode)); \ + /* Don't read anything into "unaligned" here. Bad name choice. */\ + return XCONCAT2 (sim_core_read_unaligned_,size) (cpu, pc, read_map, a); \ +} +#else +#define DECLARE_GETMEM(mode, size) \ +extern mode XCONCAT2 (GETMEM,mode) (SIM_CPU *, IADDR, ADDR); +#endif + +DECLARE_GETMEM (SF, 4) +DECLARE_GETMEM (DF, 8) +/*DECLARE_GETMEM (TF, 16)*/ + +#undef DECLARE_GETMEM + +/* Memory write support. */ + +#if defined (__GNUC__) || defined (MEMOPS_DEFINE_INLINE) +#define DECLARE_SETMEM(mode, size) \ +MEMOPS_INLINE void \ +XCONCAT2 (SETMEM,mode) (SIM_CPU *cpu, IADDR pc, ADDR a, mode val) \ +{ \ + PROFILE_COUNT_WRITE (cpu, a, XCONCAT2 (MODE_,mode)); \ + /* Don't read anything into "unaligned" here. Bad name choice. */ \ + XCONCAT2 (sim_core_write_unaligned_,size) (cpu, pc, write_map, a, val); \ +} +#else +#define DECLARE_SETMEM(mode, size) \ +extern void XCONCAT2 (SETMEM,mode) (SIM_CPU *, IADDR, ADDR, mode); +#endif + +DECLARE_SETMEM (QI, 1) +DECLARE_SETMEM (UQI, 1) +DECLARE_SETMEM (HI, 2) +DECLARE_SETMEM (UHI, 2) +DECLARE_SETMEM (SI, 4) +DECLARE_SETMEM (USI, 4) +DECLARE_SETMEM (DI, 8) +DECLARE_SETMEM (UDI, 8) + +/* +DECLARE_SETMEM (SF, 4) +DECLARE_SETMEM (DF, 8) +DECLARE_SETMEM (TF, 16) +*/ + +#undef DECLARE_SETMEM + +/* Instruction read support. */ + +#if defined (__GNUC__) || defined (MEMOPS_DEFINE_INLINE) +#define DECLARE_GETIMEM(mode, size) \ +MEMOPS_INLINE mode \ +XCONCAT2 (GETIMEM,mode) (SIM_CPU *cpu, IADDR a) \ +{ \ + /*PROFILE_COUNT_READ (cpu, a, XCONCAT2 (MODE_,mode));*/ \ + /* Don't read anything into "unaligned" here. Bad name choice. */\ + return XCONCAT2 (sim_core_read_unaligned_,size) (cpu, a, exec_map, a); \ +} +#else +#define DECLARE_GETIMEM(mode, size) \ +extern mode XCONCAT2 (GETIMEM,mode) (SIM_CPU *, ADDR); +#endif + +DECLARE_GETIMEM (UQI, 1) +DECLARE_GETIMEM (UHI, 2) +DECLARE_GETIMEM (USI, 4) +DECLARE_GETIMEM (UDI, 8) + +#undef DECLARE_GETIMEM + +/* GETT<mode>: translate target value at P to host value. + This needn't be very efficient (i.e. can call memcpy) as this is + only used when interfacing with the outside world (e.g. gdb). */ + +#if defined (__GNUC__) || defined (MEMOPS_DEFINE_INLINE) +#define DECLARE_GETT(mode, size) \ +MEMOPS_INLINE mode \ +XCONCAT2 (GETT,mode) (unsigned char *p) \ +{ \ + mode tmp; \ + memcpy (&tmp, p, sizeof (mode)); \ + return XCONCAT2 (T2H_,size) (tmp); \ +} +#else +#define DECLARE_GETT(mode, size) \ +extern mode XCONCAT2 (GETT,mode) (unsigned char *); +#endif + +DECLARE_GETT (QI, 1) +DECLARE_GETT (UQI, 1) +DECLARE_GETT (HI, 2) +DECLARE_GETT (UHI, 2) +DECLARE_GETT (SI, 4) +DECLARE_GETT (USI, 4) +DECLARE_GETT (DI, 8) +DECLARE_GETT (UDI, 8) + +/* +DECLARE_GETT (SF, 4) +DECLARE_GETT (DF, 8) +DECLARE_GETT (TF, 16) +*/ + +#undef DECLARE_GETT + +/* SETT<mode>: translate host value to target value and store at P. + This needn't be very efficient (i.e. can call memcpy) as this is + only used when interfacing with the outside world (e.g. gdb). */ + +#if defined (__GNUC__) || defined (MEMOPS_DEFINE_INLINE) +#define DECLARE_SETT(mode, size) \ +MEMOPS_INLINE void \ +XCONCAT2 (SETT,mode) (unsigned char *buf, mode val) \ +{ \ + mode tmp; \ + tmp = XCONCAT2 (H2T_,size) (val); \ + memcpy (buf, &tmp, sizeof (mode)); \ +} +#else +#define DECLARE_SETT(mode, size) \ +extern mode XCONCAT2 (GETT,mode) (unsigned char *, mode); +#endif + +DECLARE_SETT (QI, 1) +DECLARE_SETT (UQI, 1) +DECLARE_SETT (HI, 2) +DECLARE_SETT (UHI, 2) +DECLARE_SETT (SI, 4) +DECLARE_SETT (USI, 4) +DECLARE_SETT (DI, 8) +DECLARE_SETT (UDI, 8) + +/* +DECLARE_SETT (SF, 4) +DECLARE_SETT (DF, 8) +DECLARE_SETT (TF, 16) +*/ + +#undef DECLARE_SETT + +#endif /* CGEN_MEM_H */ diff --git a/sim/common/cgen-ops.h b/sim/common/cgen-ops.h new file mode 100644 index 0000000..1ec0e6c --- /dev/null +++ b/sim/common/cgen-ops.h @@ -0,0 +1,897 @@ +/* Semantics ops support for CGEN-based simulators. + Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + Contributed by Cygnus Solutions. + +This file is part of the GNU Simulators. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef CGEN_SEM_OPS_H +#define CGEN_SEM_OPS_H + +/* Semantic operations. + At one point this file was machine generated. Maybe it will be again. */ + +/* These don't really have a mode. */ +#define ANDIF(x, y) ((x) && (y)) +#define ORIF(x, y) ((x) || (y)) + +#define ANDBI(x, y) ((x) & (y)) +#define ORBI(x, y) ((x) | (y)) +#define XORBI(x, y) ((x) ^ (y)) +#define NEGBI(x) (- (x)) +#define NOTBI(x) (! (BI) (x)) +#define INVBI(x) (~ (x)) +#define EQBI(x, y) ((BI) (x) == (BI) (y)) +#define NEBI(x, y) ((BI) (x) != (BI) (y)) +#define LTBI(x, y) ((BI) (x) < (BI) (y)) +#define LEBI(x, y) ((BI) (x) <= (BI) (y)) +#define GTBI(x, y) ((BI) (x) > (BI) (y)) +#define GEBI(x, y) ((BI) (x) >= (BI) (y)) +#define LTUBI(x, y) ((BI) (x) < (BI) (y)) +#define LEUBI(x, y) ((BI) (x) <= (BI) (y)) +#define GTUBI(x, y) ((BI) (x) > (BI) (y)) +#define GEUBI(x, y) ((BI) (x) >= (BI) (y)) + +#define ADDQI(x, y) ((x) + (y)) +#define SUBQI(x, y) ((x) - (y)) +#define MULQI(x, y) ((x) * (y)) +#define DIVQI(x, y) ((QI) (x) / (QI) (y)) +#define UDIVQI(x, y) ((UQI) (x) / (UQI) (y)) +#define MODQI(x, y) ((QI) (x) % (QI) (y)) +#define UMODQI(x, y) ((UQI) (x) % (UQI) (y)) +#define SRAQI(x, y) ((QI) (x) >> (y)) +#define SRLQI(x, y) ((UQI) (x) >> (y)) +#define SLLQI(x, y) ((UQI) (x) << (y)) +extern QI RORQI PARAMS ((QI, int)); +extern QI ROLQI PARAMS ((QI, int)); +#define ANDQI(x, y) ((x) & (y)) +#define ORQI(x, y) ((x) | (y)) +#define XORQI(x, y) ((x) ^ (y)) +#define NEGQI(x) (- (x)) +#define NOTQI(x) (! (QI) (x)) +#define INVQI(x) (~ (x)) +#define EQQI(x, y) ((QI) (x) == (QI) (y)) +#define NEQI(x, y) ((QI) (x) != (QI) (y)) +#define LTQI(x, y) ((QI) (x) < (QI) (y)) +#define LEQI(x, y) ((QI) (x) <= (QI) (y)) +#define GTQI(x, y) ((QI) (x) > (QI) (y)) +#define GEQI(x, y) ((QI) (x) >= (QI) (y)) +#define LTUQI(x, y) ((UQI) (x) < (UQI) (y)) +#define LEUQI(x, y) ((UQI) (x) <= (UQI) (y)) +#define GTUQI(x, y) ((UQI) (x) > (UQI) (y)) +#define GEUQI(x, y) ((UQI) (x) >= (UQI) (y)) + +#define ADDHI(x, y) ((x) + (y)) +#define SUBHI(x, y) ((x) - (y)) +#define MULHI(x, y) ((x) * (y)) +#define DIVHI(x, y) ((HI) (x) / (HI) (y)) +#define UDIVHI(x, y) ((UHI) (x) / (UHI) (y)) +#define MODHI(x, y) ((HI) (x) % (HI) (y)) +#define UMODHI(x, y) ((UHI) (x) % (UHI) (y)) +#define SRAHI(x, y) ((HI) (x) >> (y)) +#define SRLHI(x, y) ((UHI) (x) >> (y)) +#define SLLHI(x, y) ((UHI) (x) << (y)) +extern HI RORHI PARAMS ((HI, int)); +extern HI ROLHI PARAMS ((HI, int)); +#define ANDHI(x, y) ((x) & (y)) +#define ORHI(x, y) ((x) | (y)) +#define XORHI(x, y) ((x) ^ (y)) +#define NEGHI(x) (- (x)) +#define NOTHI(x) (! (HI) (x)) +#define INVHI(x) (~ (x)) +#define EQHI(x, y) ((HI) (x) == (HI) (y)) +#define NEHI(x, y) ((HI) (x) != (HI) (y)) +#define LTHI(x, y) ((HI) (x) < (HI) (y)) +#define LEHI(x, y) ((HI) (x) <= (HI) (y)) +#define GTHI(x, y) ((HI) (x) > (HI) (y)) +#define GEHI(x, y) ((HI) (x) >= (HI) (y)) +#define LTUHI(x, y) ((UHI) (x) < (UHI) (y)) +#define LEUHI(x, y) ((UHI) (x) <= (UHI) (y)) +#define GTUHI(x, y) ((UHI) (x) > (UHI) (y)) +#define GEUHI(x, y) ((UHI) (x) >= (UHI) (y)) + +#define ADDSI(x, y) ((x) + (y)) +#define SUBSI(x, y) ((x) - (y)) +#define MULSI(x, y) ((x) * (y)) +#define DIVSI(x, y) ((SI) (x) / (SI) (y)) +#define UDIVSI(x, y) ((USI) (x) / (USI) (y)) +#define MODSI(x, y) ((SI) (x) % (SI) (y)) +#define UMODSI(x, y) ((USI) (x) % (USI) (y)) +#define SRASI(x, y) ((SI) (x) >> (y)) +#define SRLSI(x, y) ((USI) (x) >> (y)) +#define SLLSI(x, y) ((USI) (x) << (y)) +extern SI RORSI PARAMS ((SI, int)); +extern SI ROLSI PARAMS ((SI, int)); +#define ANDSI(x, y) ((x) & (y)) +#define ORSI(x, y) ((x) | (y)) +#define XORSI(x, y) ((x) ^ (y)) +#define NEGSI(x) (- (x)) +#define NOTSI(x) (! (SI) (x)) +#define INVSI(x) (~ (x)) +#define EQSI(x, y) ((SI) (x) == (SI) (y)) +#define NESI(x, y) ((SI) (x) != (SI) (y)) +#define LTSI(x, y) ((SI) (x) < (SI) (y)) +#define LESI(x, y) ((SI) (x) <= (SI) (y)) +#define GTSI(x, y) ((SI) (x) > (SI) (y)) +#define GESI(x, y) ((SI) (x) >= (SI) (y)) +#define LTUSI(x, y) ((USI) (x) < (USI) (y)) +#define LEUSI(x, y) ((USI) (x) <= (USI) (y)) +#define GTUSI(x, y) ((USI) (x) > (USI) (y)) +#define GEUSI(x, y) ((USI) (x) >= (USI) (y)) + +#ifdef DI_FN_SUPPORT +extern DI ADDDI PARAMS ((DI, DI)); +extern DI SUBDI PARAMS ((DI, DI)); +extern DI MULDI PARAMS ((DI, DI)); +extern DI DIVDI PARAMS ((DI, DI)); +extern DI UDIVDI PARAMS ((DI, DI)); +extern DI MODDI PARAMS ((DI, DI)); +extern DI UMODDI PARAMS ((DI, DI)); +extern DI SRADI PARAMS ((DI, int)); +extern UDI SRLDI PARAMS ((UDI, int)); +extern UDI SLLDI PARAMS ((UDI, int)); +extern DI RORDI PARAMS ((DI, int)); +extern DI ROLDI PARAMS ((DI, int)); +extern DI ANDDI PARAMS ((DI, DI)); +extern DI ORDI PARAMS ((DI, DI)); +extern DI XORDI PARAMS ((DI, DI)); +extern DI NEGDI PARAMS ((DI)); +extern int NOTDI PARAMS ((DI)); +extern DI INVDI PARAMS ((DI)); +extern int EQDI PARAMS ((DI, DI)); +extern int NEDI PARAMS ((DI, DI)); +extern int LTDI PARAMS ((DI, DI)); +extern int LEDI PARAMS ((DI, DI)); +extern int GTDI PARAMS ((DI, DI)); +extern int GEDI PARAMS ((DI, DI)); +extern int LTUDI PARAMS ((UDI, UDI)); +extern int LEUDI PARAMS ((UDI, UDI)); +extern int GTUDI PARAMS ((UDI, UDI)); +extern int GEUDI PARAMS ((UDI, UDI)); +#else /* ! DI_FN_SUPPORT */ +#define ADDDI(x, y) ((x) + (y)) +#define SUBDI(x, y) ((x) - (y)) +#define MULDI(x, y) ((x) * (y)) +#define DIVDI(x, y) ((DI) (x) / (DI) (y)) +#define UDIVDI(x, y) ((UDI) (x) / (UDI) (y)) +#define MODDI(x, y) ((DI) (x) % (DI) (y)) +#define UMODDI(x, y) ((UDI) (x) % (UDI) (y)) +#define SRADI(x, y) ((DI) (x) >> (y)) +#define SRLDI(x, y) ((UDI) (x) >> (y)) +#define SLLDI(x, y) ((UDI) (x) << (y)) +extern DI RORDI PARAMS ((DI, int)); +extern DI ROLDI PARAMS ((DI, int)); +#define ANDDI(x, y) ((x) & (y)) +#define ORDI(x, y) ((x) | (y)) +#define XORDI(x, y) ((x) ^ (y)) +#define NEGDI(x) (- (x)) +#define NOTDI(x) (! (DI) (x)) +#define INVDI(x) (~ (x)) +#define EQDI(x, y) ((DI) (x) == (DI) (y)) +#define NEDI(x, y) ((DI) (x) != (DI) (y)) +#define LTDI(x, y) ((DI) (x) < (DI) (y)) +#define LEDI(x, y) ((DI) (x) <= (DI) (y)) +#define GTDI(x, y) ((DI) (x) > (DI) (y)) +#define GEDI(x, y) ((DI) (x) >= (DI) (y)) +#define LTUDI(x, y) ((UDI) (x) < (UDI) (y)) +#define LEUDI(x, y) ((UDI) (x) <= (UDI) (y)) +#define GTUDI(x, y) ((UDI) (x) > (UDI) (y)) +#define GEUDI(x, y) ((UDI) (x) >= (UDI) (y)) +#endif /* DI_FN_SUPPORT */ + +#ifdef SF_FN_SUPPORT +extern SF ADDSF PARAMS ((SF, SF)); +extern SF SUBSF PARAMS ((SF, SF)); +extern SF NEGSF PARAMS ((SF)); +extern SF MULSF PARAMS ((SF, SF)); +extern SF DIVSF PARAMS ((SF, SF)); +extern int EQSF PARAMS ((SF, SF)); +extern int NESF PARAMS ((SF, SF)); +extern int LTSF PARAMS ((SF, SF)); +extern int LESF PARAMS ((SF, SF)); +extern int GTSF PARAMS ((SF, SF)); +extern int GESF PARAMS ((SF, SF)); +extern SF ABSSF PARAMS ((SF)); +extern SF SQRTSF PARAMS ((SF)); +extern SF COSSF PARAMS ((SF)); +extern SF SINSF PARAMS ((SF)); +#else /* ! SF_FN_SUPPORT */ +#define ADDSF(x, y) ((x) + (y)) +#define SUBSF(x, y) ((x) - (y)) +#define NEGSF(x) (- (x)) +#define MULSF(x, y) ((x) * (y)) +#define DIVSF(x, y) ((x) / (y)) +#define EQSF(x, y) ((SF) (x) == (SF) (y)) +#define NESF(x, y) ((SF) (x) != (SF) (y)) +#define LTSF(x, y) ((SF) (x) < (SF) (y)) +#define LESF(x, y) ((SF) (x) <= (SF) (y)) +#define GTSF(x, y) ((SF) (x) > (SF) (y)) +#define GESF(x, y) ((SF) (x) >= (SF) (y)) +extern SF ABSSF PARAMS ((SF)); +extern SF SQRTSF PARAMS ((SF)); +extern SF COSSF PARAMS ((SF)); +extern SF SINSF PARAMS ((SF)); +#endif /* SF_FN_SUPPORT */ + +#ifdef DF_FN_SUPPORT +extern DF ADDDF PARAMS ((DF, DF)); +extern DF SUBDF PARAMS ((DF, DF)); +extern DF NEGDF PARAMS ((DF)); +extern DF MULDF PARAMS ((DF, DF)); +extern DF DIVDF PARAMS ((DF, DF)); +extern int EQDF PARAMS ((DF, DF)); +extern int NEDF PARAMS ((DF, DF)); +extern int LTDF PARAMS ((DF, DF)); +extern int LEDF PARAMS ((DF, DF)); +extern int GTDF PARAMS ((DF, DF)); +extern int GEDF PARAMS ((DF, DF)); +extern DF ABSDF PARAMS ((DF)); +extern DF SQRTDF PARAMS ((DF)); +extern DF COSDF PARAMS ((DF)); +extern DF SINDF PARAMS ((DF)); +#else /* ! DF_FN_SUPPORT */ +#define ADDDF(x, y) ((x) + (y)) +#define SUBDF(x, y) ((x) - (y)) +#define NEGDF(x) (- (x)) +#define MULDF(x, y) ((x) * (y)) +#define DIVDF(x, y) ((x) / (y)) +#define EQDF(x, y) ((DF) (x) == (DF) (y)) +#define NEDF(x, y) ((DF) (x) != (DF) (y)) +#define LTDF(x, y) ((DF) (x) < (DF) (y)) +#define LEDF(x, y) ((DF) (x) <= (DF) (y)) +#define GTDF(x, y) ((DF) (x) > (DF) (y)) +#define GEDF(x, y) ((DF) (x) >= (DF) (y)) +extern DF ABSDF PARAMS ((DF)); +extern DF SQRTDF PARAMS ((DF)); +extern DF COSDF PARAMS ((DF)); +extern DF SINDF PARAMS ((DF)); +#endif /* DF_FN_SUPPORT */ + +#ifdef XF_FN_SUPPORT +extern XF ADDXF PARAMS ((XF, XF)); +extern XF SUBXF PARAMS ((XF, XF)); +extern XF NEGXF PARAMS ((XF)); +extern XF MULXF PARAMS ((XF, XF)); +extern XF DIVXF PARAMS ((XF, XF)); +extern int EQXF PARAMS ((XF, XF)); +extern int NEXF PARAMS ((XF, XF)); +extern int LTXF PARAMS ((XF, XF)); +extern int LEXF PARAMS ((XF, XF)); +extern int GTXF PARAMS ((XF, XF)); +extern int GEXF PARAMS ((XF, XF)); +extern XF ABSXF PARAMS ((XF)); +extern XF SQRTXF PARAMS ((XF)); +extern XF COSXF PARAMS ((XF)); +extern XF SINXF PARAMS ((XF)); +#else /* ! XF_FN_SUPPORT */ +#define ADDXF(x, y) ((x) + (y)) +#define SUBXF(x, y) ((x) - (y)) +#define NEGXF(x) (- (x)) +#define MULXF(x, y) ((x) * (y)) +#define DIVXF(x, y) ((x) / (y)) +#define EQXF(x, y) ((XF) (x) == (XF) (y)) +#define NEXF(x, y) ((XF) (x) != (XF) (y)) +#define LTXF(x, y) ((XF) (x) < (XF) (y)) +#define LEXF(x, y) ((XF) (x) <= (XF) (y)) +#define GTXF(x, y) ((XF) (x) > (XF) (y)) +#define GEXF(x, y) ((XF) (x) >= (XF) (y)) +extern XF ABSXF PARAMS ((XF)); +extern XF SQRTXF PARAMS ((XF)); +extern XF COSXF PARAMS ((XF)); +extern XF SINXF PARAMS ((XF)); +#endif /* XF_FN_SUPPORT */ + +#ifdef TF_FN_SUPPORT +extern TF ADDTF PARAMS ((TF, TF)); +extern TF SUBTF PARAMS ((TF, TF)); +extern TF NEGTF PARAMS ((TF)); +extern TF MULTF PARAMS ((TF, TF)); +extern TF DIVTF PARAMS ((TF, TF)); +extern int EQTF PARAMS ((TF, TF)); +extern int NETF PARAMS ((TF, TF)); +extern int LTTF PARAMS ((TF, TF)); +extern int LETF PARAMS ((TF, TF)); +extern int GTTF PARAMS ((TF, TF)); +extern int GETF PARAMS ((TF, TF)); +extern TF ABSTF PARAMS ((TF)); +extern TF SQRTTF PARAMS ((TF)); +extern TF COSTF PARAMS ((TF)); +extern TF SINTF PARAMS ((TF)); +#else /* ! TF_FN_SUPPORT */ +#define ADDTF(x, y) ((x) + (y)) +#define SUBTF(x, y) ((x) - (y)) +#define NEGTF(x) (- (x)) +#define MULTF(x, y) ((x) * (y)) +#define DIVTF(x, y) ((x) / (y)) +#define EQTF(x, y) ((TF) (x) == (TF) (y)) +#define NETF(x, y) ((TF) (x) != (TF) (y)) +#define LTTF(x, y) ((TF) (x) < (TF) (y)) +#define LETF(x, y) ((TF) (x) <= (TF) (y)) +#define GTTF(x, y) ((TF) (x) > (TF) (y)) +#define GETF(x, y) ((TF) (x) >= (TF) (y)) +extern TF ABSTF PARAMS ((TF)); +extern TF SQRTTF PARAMS ((TF)); +extern TF COSTF PARAMS ((TF)); +extern TF SINTF PARAMS ((TF)); +#endif /* TF_FN_SUPPORT */ + + +#define EXTBIQI(x) ((QI) (BI) (x)) +#define EXTBIHI(x) ((HI) (BI) (x)) +#define EXTBISI(x) ((SI) (BI) (x)) +#if defined (DI_FN_SUPPORT) +extern DI EXTBIDI PARAMS ((BI)); +#else +#define EXTBIDI(x) ((DI) (BI) (x)) +#endif +#define EXTQIHI(x) ((HI) (QI) (x)) +#define EXTQISI(x) ((SI) (QI) (x)) +#if defined (DI_FN_SUPPORT) +extern DI EXTQIDI PARAMS ((QI)); +#else +#define EXTQIDI(x) ((DI) (QI) (x)) +#endif +#define EXTHISI(x) ((SI) (HI) (x)) +#if defined (DI_FN_SUPPORT) +extern DI EXTHIDI PARAMS ((HI)); +#else +#define EXTHIDI(x) ((DI) (HI) (x)) +#endif +#if defined (DI_FN_SUPPORT) +extern DI EXTSIDI PARAMS ((SI)); +#else +#define EXTSIDI(x) ((DI) (SI) (x)) +#endif +#if defined (SF_FN_SUPPORT) || defined (DF_FN_SUPPORT) +extern DF EXTSFDF PARAMS ((SF)); +#else +#define EXTSFDF(x) ((DF) (SF) (x)) +#endif +#if defined (SF_FN_SUPPORT) || defined (XF_FN_SUPPORT) +extern XF EXTSFXF PARAMS ((SF)); +#else +#define EXTSFXF(x) ((XF) (SF) (x)) +#endif +#if defined (SF_FN_SUPPORT) || defined (TF_FN_SUPPORT) +extern TF EXTSFTF PARAMS ((SF)); +#else +#define EXTSFTF(x) ((TF) (SF) (x)) +#endif +#if defined (DF_FN_SUPPORT) || defined (XF_FN_SUPPORT) +extern XF EXTDFXF PARAMS ((DF)); +#else +#define EXTDFXF(x) ((XF) (DF) (x)) +#endif +#if defined (DF_FN_SUPPORT) || defined (TF_FN_SUPPORT) +extern TF EXTDFTF PARAMS ((DF)); +#else +#define EXTDFTF(x) ((TF) (DF) (x)) +#endif +#if defined (XF_FN_SUPPORT) || defined (TF_FN_SUPPORT) +extern TF EXTXFTF PARAMS ((XF)); +#else +#define EXTXFTF(x) ((TF) (XF) (x)) +#endif +#define ZEXTBIQI(x) ((QI) (BI) (x)) +#define ZEXTBIHI(x) ((HI) (BI) (x)) +#define ZEXTBISI(x) ((SI) (BI) (x)) +#if defined (DI_FN_SUPPORT) +extern DI ZEXTBIDI PARAMS ((BI)); +#else +#define ZEXTBIDI(x) ((DI) (BI) (x)) +#endif +#define ZEXTQIHI(x) ((HI) (UQI) (x)) +#define ZEXTQISI(x) ((SI) (UQI) (x)) +#if defined (DI_FN_SUPPORT) +extern DI ZEXTQIDI PARAMS ((QI)); +#else +#define ZEXTQIDI(x) ((DI) (UQI) (x)) +#endif +#define ZEXTHISI(x) ((SI) (UHI) (x)) +#if defined (DI_FN_SUPPORT) +extern DI ZEXTHIDI PARAMS ((HI)); +#else +#define ZEXTHIDI(x) ((DI) (UHI) (x)) +#endif +#if defined (DI_FN_SUPPORT) +extern DI ZEXTSIDI PARAMS ((SI)); +#else +#define ZEXTSIDI(x) ((DI) (USI) (x)) +#endif +#define TRUNCQIBI(x) ((BI) (QI) (x)) +#define TRUNCHIBI(x) ((BI) (HI) (x)) +#define TRUNCHIQI(x) ((QI) (HI) (x)) +#define TRUNCSIBI(x) ((BI) (SI) (x)) +#define TRUNCSIQI(x) ((QI) (SI) (x)) +#define TRUNCSIHI(x) ((HI) (SI) (x)) +#if defined (DI_FN_SUPPORT) +extern BI TRUNCDIBI PARAMS ((DI)); +#else +#define TRUNCDIBI(x) ((BI) (DI) (x)) +#endif +#if defined (DI_FN_SUPPORT) +extern QI TRUNCDIQI PARAMS ((DI)); +#else +#define TRUNCDIQI(x) ((QI) (DI) (x)) +#endif +#if defined (DI_FN_SUPPORT) +extern HI TRUNCDIHI PARAMS ((DI)); +#else +#define TRUNCDIHI(x) ((HI) (DI) (x)) +#endif +#if defined (DI_FN_SUPPORT) +extern SI TRUNCDISI PARAMS ((DI)); +#else +#define TRUNCDISI(x) ((SI) (DI) (x)) +#endif +#if defined (DF_FN_SUPPORT) || defined (SF_FN_SUPPORT) +extern SF TRUNCDFSF PARAMS ((DF)); +#else +#define TRUNCDFSF(x) ((SF) (DF) (x)) +#endif +#if defined (XF_FN_SUPPORT) || defined (SF_FN_SUPPORT) +extern SF TRUNCXFSF PARAMS ((XF)); +#else +#define TRUNCXFSF(x) ((SF) (XF) (x)) +#endif +#if defined (XF_FN_SUPPORT) || defined (DF_FN_SUPPORT) +extern DF TRUNCXFDF PARAMS ((XF)); +#else +#define TRUNCXFDF(x) ((DF) (XF) (x)) +#endif +#if defined (TF_FN_SUPPORT) || defined (SF_FN_SUPPORT) +extern SF TRUNCTFSF PARAMS ((TF)); +#else +#define TRUNCTFSF(x) ((SF) (TF) (x)) +#endif +#if defined (TF_FN_SUPPORT) || defined (DF_FN_SUPPORT) +extern DF TRUNCTFDF PARAMS ((TF)); +#else +#define TRUNCTFDF(x) ((DF) (TF) (x)) +#endif +#if defined (TF_FN_SUPPORT) || defined (XF_FN_SUPPORT) +extern XF TRUNCTFXF PARAMS ((TF)); +#else +#define TRUNCTFXF(x) ((XF) (TF) (x)) +#endif +#if defined (SF_FN_SUPPORT) +extern SF FLOATQISF PARAMS ((QI)); +#else +#define FLOATQISF(x) ((SF) (QI) (x)) +#endif +#if defined (DF_FN_SUPPORT) +extern DF FLOATQIDF PARAMS ((QI)); +#else +#define FLOATQIDF(x) ((DF) (QI) (x)) +#endif +#if defined (XF_FN_SUPPORT) +extern XF FLOATQIXF PARAMS ((QI)); +#else +#define FLOATQIXF(x) ((XF) (QI) (x)) +#endif +#if defined (TF_FN_SUPPORT) +extern TF FLOATQITF PARAMS ((QI)); +#else +#define FLOATQITF(x) ((TF) (QI) (x)) +#endif +#if defined (SF_FN_SUPPORT) +extern SF FLOATHISF PARAMS ((HI)); +#else +#define FLOATHISF(x) ((SF) (HI) (x)) +#endif +#if defined (DF_FN_SUPPORT) +extern DF FLOATHIDF PARAMS ((HI)); +#else +#define FLOATHIDF(x) ((DF) (HI) (x)) +#endif +#if defined (XF_FN_SUPPORT) +extern XF FLOATHIXF PARAMS ((HI)); +#else +#define FLOATHIXF(x) ((XF) (HI) (x)) +#endif +#if defined (TF_FN_SUPPORT) +extern TF FLOATHITF PARAMS ((HI)); +#else +#define FLOATHITF(x) ((TF) (HI) (x)) +#endif +#if defined (SF_FN_SUPPORT) +extern SF FLOATSISF PARAMS ((SI)); +#else +#define FLOATSISF(x) ((SF) (SI) (x)) +#endif +#if defined (DF_FN_SUPPORT) +extern DF FLOATSIDF PARAMS ((SI)); +#else +#define FLOATSIDF(x) ((DF) (SI) (x)) +#endif +#if defined (XF_FN_SUPPORT) +extern XF FLOATSIXF PARAMS ((SI)); +#else +#define FLOATSIXF(x) ((XF) (SI) (x)) +#endif +#if defined (TF_FN_SUPPORT) +extern TF FLOATSITF PARAMS ((SI)); +#else +#define FLOATSITF(x) ((TF) (SI) (x)) +#endif +#if defined (DI_FN_SUPPORT) || defined (SF_FN_SUPPORT) +extern SF FLOATDISF PARAMS ((DI)); +#else +#define FLOATDISF(x) ((SF) (DI) (x)) +#endif +#if defined (DI_FN_SUPPORT) || defined (DF_FN_SUPPORT) +extern DF FLOATDIDF PARAMS ((DI)); +#else +#define FLOATDIDF(x) ((DF) (DI) (x)) +#endif +#if defined (DI_FN_SUPPORT) || defined (XF_FN_SUPPORT) +extern XF FLOATDIXF PARAMS ((DI)); +#else +#define FLOATDIXF(x) ((XF) (DI) (x)) +#endif +#if defined (DI_FN_SUPPORT) || defined (TF_FN_SUPPORT) +extern TF FLOATDITF PARAMS ((DI)); +#else +#define FLOATDITF(x) ((TF) (DI) (x)) +#endif +#if defined (SF_FN_SUPPORT) +extern SF UFLOATQISF PARAMS ((QI)); +#else +#define UFLOATQISF(x) ((SF) (UQI) (x)) +#endif +#if defined (DF_FN_SUPPORT) +extern DF UFLOATQIDF PARAMS ((QI)); +#else +#define UFLOATQIDF(x) ((DF) (UQI) (x)) +#endif +#if defined (XF_FN_SUPPORT) +extern XF UFLOATQIXF PARAMS ((QI)); +#else +#define UFLOATQIXF(x) ((XF) (UQI) (x)) +#endif +#if defined (TF_FN_SUPPORT) +extern TF UFLOATQITF PARAMS ((QI)); +#else +#define UFLOATQITF(x) ((TF) (UQI) (x)) +#endif +#if defined (SF_FN_SUPPORT) +extern SF UFLOATHISF PARAMS ((HI)); +#else +#define UFLOATHISF(x) ((SF) (UHI) (x)) +#endif +#if defined (DF_FN_SUPPORT) +extern DF UFLOATHIDF PARAMS ((HI)); +#else +#define UFLOATHIDF(x) ((DF) (UHI) (x)) +#endif +#if defined (XF_FN_SUPPORT) +extern XF UFLOATHIXF PARAMS ((HI)); +#else +#define UFLOATHIXF(x) ((XF) (UHI) (x)) +#endif +#if defined (TF_FN_SUPPORT) +extern TF UFLOATHITF PARAMS ((HI)); +#else +#define UFLOATHITF(x) ((TF) (UHI) (x)) +#endif +#if defined (SF_FN_SUPPORT) +extern SF UFLOATSISF PARAMS ((SI)); +#else +#define UFLOATSISF(x) ((SF) (USI) (x)) +#endif +#if defined (DF_FN_SUPPORT) +extern DF UFLOATSIDF PARAMS ((SI)); +#else +#define UFLOATSIDF(x) ((DF) (USI) (x)) +#endif +#if defined (XF_FN_SUPPORT) +extern XF UFLOATSIXF PARAMS ((SI)); +#else +#define UFLOATSIXF(x) ((XF) (USI) (x)) +#endif +#if defined (TF_FN_SUPPORT) +extern TF UFLOATSITF PARAMS ((SI)); +#else +#define UFLOATSITF(x) ((TF) (USI) (x)) +#endif +#if defined (DI_FN_SUPPORT) || defined (SF_FN_SUPPORT) +extern SF UFLOATDISF PARAMS ((DI)); +#else +#define UFLOATDISF(x) ((SF) (UDI) (x)) +#endif +#if defined (DI_FN_SUPPORT) || defined (DF_FN_SUPPORT) +extern DF UFLOATDIDF PARAMS ((DI)); +#else +#define UFLOATDIDF(x) ((DF) (UDI) (x)) +#endif +#if defined (DI_FN_SUPPORT) || defined (XF_FN_SUPPORT) +extern XF UFLOATDIXF PARAMS ((DI)); +#else +#define UFLOATDIXF(x) ((XF) (UDI) (x)) +#endif +#if defined (DI_FN_SUPPORT) || defined (TF_FN_SUPPORT) +extern TF UFLOATDITF PARAMS ((DI)); +#else +#define UFLOATDITF(x) ((TF) (UDI) (x)) +#endif +#if defined (SF_FN_SUPPORT) +extern BI FIXSFBI PARAMS ((SF)); +#else +#define FIXSFBI(x) ((BI) (SF) (x)) +#endif +#if defined (SF_FN_SUPPORT) +extern QI FIXSFQI PARAMS ((SF)); +#else +#define FIXSFQI(x) ((QI) (SF) (x)) +#endif +#if defined (SF_FN_SUPPORT) +extern HI FIXSFHI PARAMS ((SF)); +#else +#define FIXSFHI(x) ((HI) (SF) (x)) +#endif +#if defined (SF_FN_SUPPORT) +extern SI FIXSFSI PARAMS ((SF)); +#else +#define FIXSFSI(x) ((SI) (SF) (x)) +#endif +#if defined (SF_FN_SUPPORT) || defined (DI_FN_SUPPORT) +extern DI FIXSFDI PARAMS ((SF)); +#else +#define FIXSFDI(x) ((DI) (SF) (x)) +#endif +#if defined (DF_FN_SUPPORT) +extern BI FIXDFBI PARAMS ((DF)); +#else +#define FIXDFBI(x) ((BI) (DF) (x)) +#endif +#if defined (DF_FN_SUPPORT) +extern QI FIXDFQI PARAMS ((DF)); +#else +#define FIXDFQI(x) ((QI) (DF) (x)) +#endif +#if defined (DF_FN_SUPPORT) +extern HI FIXDFHI PARAMS ((DF)); +#else +#define FIXDFHI(x) ((HI) (DF) (x)) +#endif +#if defined (DF_FN_SUPPORT) +extern SI FIXDFSI PARAMS ((DF)); +#else +#define FIXDFSI(x) ((SI) (DF) (x)) +#endif +#if defined (DF_FN_SUPPORT) || defined (DI_FN_SUPPORT) +extern DI FIXDFDI PARAMS ((DF)); +#else +#define FIXDFDI(x) ((DI) (DF) (x)) +#endif +#if defined (XF_FN_SUPPORT) +extern BI FIXXFBI PARAMS ((XF)); +#else +#define FIXXFBI(x) ((BI) (XF) (x)) +#endif +#if defined (XF_FN_SUPPORT) +extern QI FIXXFQI PARAMS ((XF)); +#else +#define FIXXFQI(x) ((QI) (XF) (x)) +#endif +#if defined (XF_FN_SUPPORT) +extern HI FIXXFHI PARAMS ((XF)); +#else +#define FIXXFHI(x) ((HI) (XF) (x)) +#endif +#if defined (XF_FN_SUPPORT) +extern SI FIXXFSI PARAMS ((XF)); +#else +#define FIXXFSI(x) ((SI) (XF) (x)) +#endif +#if defined (XF_FN_SUPPORT) || defined (DI_FN_SUPPORT) +extern DI FIXXFDI PARAMS ((XF)); +#else +#define FIXXFDI(x) ((DI) (XF) (x)) +#endif +#if defined (TF_FN_SUPPORT) +extern BI FIXTFBI PARAMS ((TF)); +#else +#define FIXTFBI(x) ((BI) (TF) (x)) +#endif +#if defined (TF_FN_SUPPORT) +extern QI FIXTFQI PARAMS ((TF)); +#else +#define FIXTFQI(x) ((QI) (TF) (x)) +#endif +#if defined (TF_FN_SUPPORT) +extern HI FIXTFHI PARAMS ((TF)); +#else +#define FIXTFHI(x) ((HI) (TF) (x)) +#endif +#if defined (TF_FN_SUPPORT) +extern SI FIXTFSI PARAMS ((TF)); +#else +#define FIXTFSI(x) ((SI) (TF) (x)) +#endif +#if defined (TF_FN_SUPPORT) || defined (DI_FN_SUPPORT) +extern DI FIXTFDI PARAMS ((TF)); +#else +#define FIXTFDI(x) ((DI) (TF) (x)) +#endif +#if defined (SF_FN_SUPPORT) +extern QI UFIXSFQI PARAMS ((SF)); +#else +#define UFIXSFQI(x) ((UQI) (SF) (x)) +#endif +#if defined (SF_FN_SUPPORT) +extern HI UFIXSFHI PARAMS ((SF)); +#else +#define UFIXSFHI(x) ((UHI) (SF) (x)) +#endif +#if defined (SF_FN_SUPPORT) +extern SI UFIXSFSI PARAMS ((SF)); +#else +#define UFIXSFSI(x) ((USI) (SF) (x)) +#endif +#if defined (SF_FN_SUPPORT) || defined (DI_FN_SUPPORT) +extern DI UFIXSFDI PARAMS ((SF)); +#else +#define UFIXSFDI(x) ((UDI) (SF) (x)) +#endif +#if defined (DF_FN_SUPPORT) +extern QI UFIXDFQI PARAMS ((DF)); +#else +#define UFIXDFQI(x) ((UQI) (DF) (x)) +#endif +#if defined (DF_FN_SUPPORT) +extern HI UFIXDFHI PARAMS ((DF)); +#else +#define UFIXDFHI(x) ((UHI) (DF) (x)) +#endif +#if defined (DF_FN_SUPPORT) +extern SI UFIXDFSI PARAMS ((DF)); +#else +#define UFIXDFSI(x) ((USI) (DF) (x)) +#endif +#if defined (DF_FN_SUPPORT) || defined (DI_FN_SUPPORT) +extern DI UFIXDFDI PARAMS ((DF)); +#else +#define UFIXDFDI(x) ((UDI) (DF) (x)) +#endif +#if defined (XF_FN_SUPPORT) +extern QI UFIXXFQI PARAMS ((XF)); +#else +#define UFIXXFQI(x) ((UQI) (XF) (x)) +#endif +#if defined (XF_FN_SUPPORT) +extern HI UFIXXFHI PARAMS ((XF)); +#else +#define UFIXXFHI(x) ((UHI) (XF) (x)) +#endif +#if defined (XF_FN_SUPPORT) +extern SI UFIXXFSI PARAMS ((XF)); +#else +#define UFIXXFSI(x) ((USI) (XF) (x)) +#endif +#if defined (XF_FN_SUPPORT) || defined (DI_FN_SUPPORT) +extern DI UFIXXFDI PARAMS ((XF)); +#else +#define UFIXXFDI(x) ((UDI) (XF) (x)) +#endif +#if defined (TF_FN_SUPPORT) +extern QI UFIXTFQI PARAMS ((TF)); +#else +#define UFIXTFQI(x) ((UQI) (TF) (x)) +#endif +#if defined (TF_FN_SUPPORT) +extern HI UFIXTFHI PARAMS ((TF)); +#else +#define UFIXTFHI(x) ((UHI) (TF) (x)) +#endif +#if defined (TF_FN_SUPPORT) +extern SI UFIXTFSI PARAMS ((TF)); +#else +#define UFIXTFSI(x) ((USI) (TF) (x)) +#endif +#if defined (TF_FN_SUPPORT) || defined (DI_FN_SUPPORT) +extern DI UFIXTFDI PARAMS ((TF)); +#else +#define UFIXTFDI(x) ((UDI) (TF) (x)) +#endif + +/* Semantic support utilities. */ + +#ifdef __GNUC__ + +#ifdef SEMOPS_DEFINE_INLINE +#define SEMOPS_INLINE +#else +#define SEMOPS_INLINE extern inline +#endif + +SEMOPS_INLINE SI +ADDCSI (SI a, SI b, BI c) +{ + SI res = ADDSI (a, ADDSI (b, c)); + return res; +} + +SEMOPS_INLINE BI +ADDCFSI (SI a, SI b, BI c) +{ + SI tmp = ADDSI (a, ADDSI (b, c)); + BI res = ((USI) tmp < (USI) a) || (c && tmp == a); + return res; +} + +SEMOPS_INLINE BI +ADDOFSI (SI a, SI b, BI c) +{ + SI tmp = ADDSI (a, ADDSI (b, c)); + BI res = (((a < 0) == (b < 0)) + && ((a < 0) != (tmp < 0))); + return res; +} + +SEMOPS_INLINE SI +SUBCSI (SI a, SI b, BI c) +{ + SI res = SUBSI (a, ADDSI (b, c)); + return res; +} + +SEMOPS_INLINE BI +SUBCFSI (SI a, SI b, BI c) +{ + BI res = ((USI) a < (USI) b) || (c && a == b); + return res; +} + +SEMOPS_INLINE BI +SUBOFSI (SI a, SI b, BI c) +{ + SI tmp = SUBSI (a, ADDSI (b, c)); + BI res = (((a < 0) != (b < 0)) + && ((a < 0) != (tmp < 0))); + return res; +} + +#else + +SI ADDCSI (SI, SI, BI); +UBI ADDCFSI (SI, SI, BI); +UBI ADDOFSI (SI, SI, BI); +SI SUBCSI (SI, SI, BI); +UBI SUBCFSI (SI, SI, BI); +UBI SUBOFSI (SI, SI, BI); + +#endif + +/* DI mode support if "long long" doesn't exist. + At one point CGEN supported K&R C compilers, and ANSI C compilers without + "long long". One can argue the various merits of keeping this in or + throwing it out. I went to the trouble of adding it so for the time being + I'm leaving it in. */ + +#ifdef DI_FN_SUPPORT + +DI make_struct_di (SI, SI); +/* FIXME: needed? */ +DI CONVHIDI (HI); +DI CONVSIDI (SI); +SI CONVDISI (DI); + +#endif /* DI_FN_SUPPORT */ + +#endif /* CGEN_SEM_OPS_H */ diff --git a/sim/common/cgen-run.c b/sim/common/cgen-run.c new file mode 100644 index 0000000..07ee191 --- /dev/null +++ b/sim/common/cgen-run.c @@ -0,0 +1,233 @@ +/* Main simulator loop for CGEN-based simulators. + Copyright (C) 1998 Free Software Foundation, Inc. + Contributed by Cygnus Solutions. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* ??? These are old notes, kept around for now. + Collecting profile data and tracing slow us down so we don't do them in + "fast mode". + There are 6 possibilities on 2 axes: + - no-scaching, insn-scaching, basic-block-scaching + - run with full features or run fast + Supporting all six possibilities in one executable is a bit much but + supporting full/fast seems reasonable. + If the scache is configured in it is always used. + If pbb-scaching is configured in it is always used. + ??? Sometimes supporting more than one set of semantic functions will make + the simulator too large - this should be configurable. Blah blah blah. + ??? Supporting full/fast can be more modular, blah blah blah. + When the framework is more modular, this can be. +*/ + +#include "sim-main.h" +#include "sim-assert.h" + +#ifndef SIM_ENGINE_PREFIX_HOOK +#define SIM_ENGINE_PREFIX_HOOK(sd) +#endif +#ifndef SIM_ENGINE_POSTFIX_HOOK +#define SIM_ENGINE_POSTFIX_HOOK(sd) +#endif + +static sim_event_handler has_stepped; +static void prime_cpu (SIM_CPU *, int); +static void engine_run_1 (SIM_DESC, int, int); +static void engine_run_n (SIM_DESC, int, int, int, int); + +/* sim_resume for cgen */ + +void +sim_resume (SIM_DESC sd, int step, int siggnal) +{ + sim_engine *engine = STATE_ENGINE (sd); + jmp_buf buf; + int jmpval; + + ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + + /* we only want to be single stepping the simulator once */ + if (engine->stepper != NULL) + { + sim_events_deschedule (sd, engine->stepper); + engine->stepper = NULL; + } + if (step) + engine->stepper = sim_events_schedule (sd, 1, has_stepped, sd); + + sim_module_resume (sd); + +#if WITH_SCACHE + if (USING_SCACHE_P (sd)) + scache_flush (sd); +#endif + + /* run/resume the simulator */ + + sim_engine_set_run_state (sd, sim_running, 0); + + engine->jmpbuf = &buf; + jmpval = setjmp (buf); + if (jmpval == sim_engine_start_jmpval + || jmpval == sim_engine_restart_jmpval) + { + int last_cpu_nr = sim_engine_last_cpu_nr (sd); + int next_cpu_nr = sim_engine_next_cpu_nr (sd); + int nr_cpus = sim_engine_nr_cpus (sd); + /* ??? Setting max_insns to 0 allows pbb/jit code to run wild and is + useful if all one wants to do is run a benchmark. Need some better + way to identify this case. */ + int max_insns = (step + ? 1 + : (nr_cpus == 1 /*&& wip:no-events*/) + ? 0 + : 4); /*FIXME: magic number*/ + int fast_p = STATE_RUN_FAST_P (sd); + + sim_events_preprocess (sd, last_cpu_nr >= nr_cpus, next_cpu_nr >= nr_cpus); + if (next_cpu_nr >= nr_cpus) + next_cpu_nr = 0; + if (nr_cpus == 1) + engine_run_1 (sd, max_insns, fast_p); + else + engine_run_n (sd, next_cpu_nr, nr_cpus, max_insns, fast_p); + } +#if 1 /*wip*/ + else + { + /* Account for the last insn executed. */ + SIM_CPU *cpu = STATE_CPU (sd, sim_engine_last_cpu_nr (sd)); + ++ CPU_INSN_COUNT (cpu); + TRACE_INSN_FINI (cpu, NULL, 1); + } +#endif + + engine->jmpbuf = NULL; + + { + int i; + int nr_cpus = sim_engine_nr_cpus (sd); + +#if 0 /*wip,ignore*/ + /* If the loop exits, either we single-stepped or @cpu@_engine_stop + was called. */ + if (step) + sim_engine_set_run_state (sd, sim_stopped, SIM_SIGTRAP); + else + sim_engine_set_run_state (sd, pending_reason, pending_sigrc); +#endif + + for (i = 0; i < nr_cpus; ++i) + { + SIM_CPU *cpu = STATE_CPU (sd, i); + + PROFILE_TOTAL_INSN_COUNT (CPU_PROFILE_DATA (cpu)) += CPU_INSN_COUNT (cpu); + } + } + + sim_module_suspend (sd); +} + +/* Halt the simulator after just one instruction. */ + +static void +has_stepped (SIM_DESC sd, void *data) +{ + ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_stopped, SIM_SIGTRAP); +} + +/* Prepare a cpu for running. + MAX_INSNS is the number of insns to execute per time slice. + If 0 it means the cpu can run as long as it wants (e.g. until the + program completes). + ??? Perhaps this should be an argument to the engine_fn. */ + +static void +prime_cpu (SIM_CPU *cpu, int max_insns) +{ + CPU_MAX_SLICE_INSNS (cpu) = max_insns; + CPU_INSN_COUNT (cpu) = 0; + + /* Initialize the insn descriptor table. + This has to be done after all initialization so we just defer it to + here. */ + + if (MACH_PREPARE_RUN (CPU_MACH (cpu))) + (* MACH_PREPARE_RUN (CPU_MACH (cpu))) (cpu); +} + +/* Main loop, for 1 cpu. */ + +static void +engine_run_1 (SIM_DESC sd, int max_insns, int fast_p) +{ + sim_cpu *cpu = STATE_CPU (sd, 0); + ENGINE_FN *fn = fast_p ? CPU_FAST_ENGINE_FN (cpu) : CPU_FULL_ENGINE_FN (cpu); + + prime_cpu (cpu, max_insns); + + while (1) + { + SIM_ENGINE_PREFIX_HOOK (sd); + + (*fn) (cpu); + + SIM_ENGINE_POSTFIX_HOOK (sd); + + /* process any events */ + if (sim_events_tick (sd)) + sim_events_process (sd); + } +} + +/* Main loop, for multiple cpus. */ + +static void +engine_run_n (SIM_DESC sd, int next_cpu_nr, int nr_cpus, int max_insns, int fast_p) +{ + int i; + ENGINE_FN *engine_fns[MAX_NR_PROCESSORS]; + + for (i = 0; i < nr_cpus; ++i) + { + SIM_CPU *cpu = STATE_CPU (sd, i); + + engine_fns[i] = fast_p ? CPU_FAST_ENGINE_FN (cpu) : CPU_FULL_ENGINE_FN (cpu); + prime_cpu (cpu, max_insns); + } + + while (1) + { + SIM_ENGINE_PREFIX_HOOK (sd); + + /* FIXME: proper cycling of all of them, blah blah blah. */ + while (next_cpu_nr != nr_cpus) + { + SIM_CPU *cpu = STATE_CPU (sd, next_cpu_nr); + + (* engine_fns[next_cpu_nr]) (cpu); + ++next_cpu_nr; + } + + SIM_ENGINE_POSTFIX_HOOK (sd); + + /* process any events */ + if (sim_events_tick (sd)) + sim_events_process (sd); + } +} diff --git a/sim/common/cgen-scache.c b/sim/common/cgen-scache.c new file mode 100644 index 0000000..c5ea075 --- /dev/null +++ b/sim/common/cgen-scache.c @@ -0,0 +1,471 @@ +/* Simulator cache routines for CGEN simulators (and maybe others). + Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define SCACHE_DEFINE_INLINE + +#include "sim-main.h" +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#include "libiberty.h" +#include "sim-options.h" +#include "sim-io.h" + +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + +/* Unused address. */ +#define UNUSED_ADDR 0xffffffff + +/* Scache configuration parameters. + ??? Experiments to determine reasonable values is wip. + These are just guesses. */ + +/* Default number of scache elements. + The size of an element is typically 32-64 bytes, so the size of the + default scache will be between 512K and 1M bytes. */ +#ifdef CONFIG_SIM_CACHE_SIZE +#define SCACHE_DEFAULT_CACHE_SIZE CONFIG_SIM_CACHE_SIZE +#else +#define SCACHE_DEFAULT_CACHE_SIZE 16384 +#endif + +/* Minimum cache size. + The m32r port assumes a cache size of at least 2 so it can decode both 16 + bit insns. When compiling we need an extra for the chain entry. And this + must be a multiple of 2. Hence 4 is the minimum (though, for those with + featuritis or itchy pedantic bits, we could make this conditional on + WITH_SCACHE_PBB). */ +#define MIN_SCACHE_SIZE 4 + +/* Ratio of size of text section to size of scache. + When compiling, we don't want to flush the scache more than we have to + but we also don't want it to be exorbitantly(sp?) large. So we pick a high + default value, then reduce it by the size of the program being simulated, + but we don't override any value specified on the command line. + If not specified on the command line, the size to use is computed as + max (MIN_SCACHE_SIZE, + min (DEFAULT_SCACHE_SIZE, + text_size / (base_insn_size * INSN_SCACHE_RATIO))). */ +/* ??? Interesting idea but not currently used. */ +#define INSN_SCACHE_RATIO 4 + +/* Default maximum insn chain length. + The only reason for a maximum is so we can place a maximum size on the + profiling table. Chain lengths are determined by cti's. + 32 is a more reasonable number, but when profiling, the before/after + handlers take up that much more space. The scache is filled from front to + back so all this determines is when the scache needs to be flushed. */ +#define MAX_CHAIN_LENGTH 64 + +/* Default maximum hash list length. */ +#define MAX_HASH_CHAIN_LENGTH 4 + +/* Minimum hash table size. */ +#define MIN_HASH_CHAINS 32 + +/* Ratio of number of scache elements to number of hash lists. + Since the user can only specify the size of the scache, we compute the + size of the hash table as + max (MIN_HASH_CHAINS, scache_size / SCACHE_HASH_RATIO). */ +#define SCACHE_HASH_RATIO 8 + +/* Hash a PC value. + FIXME: May wish to make the hashing architecture specific. + FIXME: revisit */ +#define HASH_PC(pc) (((pc) >> 2) + ((pc) >> 5)) + +static MODULE_INIT_FN scache_init; +static MODULE_UNINSTALL_FN scache_uninstall; + +static DECLARE_OPTION_HANDLER (scache_option_handler); + +#define OPTION_PROFILE_SCACHE (OPTION_START + 0) + +static const OPTION scache_options[] = { + { {"scache-size", optional_argument, NULL, 'c'}, + 'c', "[SIZE]", "Specify size of simulator execution cache", + scache_option_handler }, +#if WITH_SCACHE_PBB + /* ??? It might be nice to allow the user to specify the size of the hash + table, the maximum hash list length, and the maximum chain length, but + for now that might be more akin to featuritis. */ +#endif + { {"profile-scache", optional_argument, NULL, OPTION_PROFILE_SCACHE}, + '\0', "on|off", "Perform simulator execution cache profiling", + scache_option_handler }, + { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL } +}; + +static SIM_RC +scache_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt, + char *arg, int is_command) +{ + int n; + + switch (opt) + { + case 'c' : + if (WITH_SCACHE) + { + if (arg != NULL) + { + int n = strtol (arg, NULL, 0); + if (n < MIN_SCACHE_SIZE) + { + sim_io_eprintf (sd, "invalid scache size `%d', must be at least 4", n); + return SIM_RC_FAIL; + } + /* Ensure it's a multiple of 2. */ + if ((n & (n - 1)) != 0) + { + sim_io_eprintf (sd, "scache size `%d' not a multiple of 2\n", n); + { + /* round up to nearest multiple of 2 */ + int i; + for (i = 1; i < n; i <<= 1) + continue; + n = i; + } + sim_io_eprintf (sd, "rounding scache size up to %d\n", n); + } + if (cpu == NULL) + STATE_SCACHE_SIZE (sd) = n; + else + CPU_SCACHE_SIZE (cpu) = n; + } + else + { + if (cpu == NULL) + STATE_SCACHE_SIZE (sd) = SCACHE_DEFAULT_CACHE_SIZE; + else + CPU_SCACHE_SIZE (cpu) = SCACHE_DEFAULT_CACHE_SIZE; + } + } + else + sim_io_eprintf (sd, "Simulator execution cache not enabled, `--scache-size' ignored\n"); + break; + + case OPTION_PROFILE_SCACHE : + if (WITH_SCACHE && WITH_PROFILE_SCACHE_P) + { + /* FIXME: handle cpu != NULL. */ + return sim_profile_set_option (sd, "-scache", PROFILE_SCACHE_IDX, + arg); + } + else + sim_io_eprintf (sd, "Simulator cache profiling not compiled in, `--profile-scache' ignored\n"); + break; + } + + return SIM_RC_OK; +} + +SIM_RC +scache_install (SIM_DESC sd) +{ + sim_add_option_table (sd, NULL, scache_options); + sim_module_add_init_fn (sd, scache_init); + sim_module_add_uninstall_fn (sd, scache_uninstall); + + /* This is the default, it may be overridden on the command line. */ + STATE_SCACHE_SIZE (sd) = WITH_SCACHE; + + return SIM_RC_OK; +} + +static SIM_RC +scache_init (SIM_DESC sd) +{ + int c; + + for (c = 0; c < MAX_NR_PROCESSORS; ++c) + { + SIM_CPU *cpu = STATE_CPU (sd, c); + int elm_size = IMP_PROPS_SCACHE_ELM_SIZE (MACH_IMP_PROPS (CPU_MACH (cpu))); + + /* elm_size is 0 if the cpu doesn't not have scache support */ + if (elm_size == 0) + { + CPU_SCACHE_SIZE (cpu) = 0; + CPU_SCACHE_CACHE (cpu) = NULL; + } + else + { + if (CPU_SCACHE_SIZE (cpu) == 0) + CPU_SCACHE_SIZE (cpu) = STATE_SCACHE_SIZE (sd); + CPU_SCACHE_CACHE (cpu) = + (SCACHE *) xmalloc (CPU_SCACHE_SIZE (cpu) * elm_size); +#if WITH_SCACHE_PBB + CPU_SCACHE_MAX_CHAIN_LENGTH (cpu) = MAX_CHAIN_LENGTH; + CPU_SCACHE_NUM_HASH_CHAIN_ENTRIES (cpu) = MAX_HASH_CHAIN_LENGTH; + CPU_SCACHE_NUM_HASH_CHAINS (cpu) = MAX (MIN_HASH_CHAINS, + CPU_SCACHE_SIZE (cpu) + / SCACHE_HASH_RATIO); + CPU_SCACHE_HASH_TABLE (cpu) = + (SCACHE_MAP *) xmalloc (CPU_SCACHE_NUM_HASH_CHAINS (cpu) + * CPU_SCACHE_NUM_HASH_CHAIN_ENTRIES (cpu) + * sizeof (SCACHE_MAP)); + CPU_SCACHE_PBB_BEGIN (cpu) = (SCACHE *) zalloc (elm_size); + CPU_SCACHE_CHAIN_LENGTHS (cpu) = + (unsigned long *) zalloc ((CPU_SCACHE_MAX_CHAIN_LENGTH (cpu) + 1) + * sizeof (long)); +#endif + } + } + + scache_flush (sd); + + return SIM_RC_OK; +} + +static void +scache_uninstall (SIM_DESC sd) +{ + int c; + + for (c = 0; c < MAX_NR_PROCESSORS; ++c) + { + SIM_CPU *cpu = STATE_CPU (sd, c); + + if (CPU_SCACHE_CACHE (cpu) != NULL) + free (CPU_SCACHE_CACHE (cpu)); +#if WITH_SCACHE_PBB + if (CPU_SCACHE_HASH_TABLE (cpu) != NULL) + free (CPU_SCACHE_HASH_TABLE (cpu)); + if (CPU_SCACHE_PBB_BEGIN (cpu) != NULL) + free (CPU_SCACHE_PBB_BEGIN (cpu)); + if (CPU_SCACHE_CHAIN_LENGTHS (cpu) != NULL) + free (CPU_SCACHE_CHAIN_LENGTHS (cpu)); +#endif + } +} + +void +scache_flush (SIM_DESC sd) +{ + int c; + + for (c = 0; c < MAX_NR_PROCESSORS; ++c) + { + SIM_CPU *cpu = STATE_CPU (sd, c); + scache_flush_cpu (cpu); + } +} + +void +scache_flush_cpu (SIM_CPU *cpu) +{ + int i,n; + + /* Don't bother if cache not in use. */ + if (CPU_SCACHE_SIZE (cpu) == 0) + return; + +#if WITH_SCACHE_PBB + /* It's important that this be reasonably fast as this can be done when + the simulation is running. */ + CPU_SCACHE_NEXT_FREE (cpu) = CPU_SCACHE_CACHE (cpu); + n = CPU_SCACHE_NUM_HASH_CHAINS (cpu) * CPU_SCACHE_NUM_HASH_CHAIN_ENTRIES (cpu); + /* ??? Might be faster to just set the first entry, then update the + "last entry" marker during allocation. */ + for (i = 0; i < n; ++i) + CPU_SCACHE_HASH_TABLE (cpu) [i] . pc = UNUSED_ADDR; +#else + { + int elm_size = IMP_PROPS_SCACHE_ELM_SIZE (MACH_IMP_PROPS (CPU_MACH (cpu))); + SCACHE *sc; + + /* Technically, this may not be necessary, but it helps debugging. */ + memset (CPU_SCACHE_CACHE (cpu), 0, + CPU_SCACHE_SIZE (cpu) * elm_size); + + for (i = 0, sc = CPU_SCACHE_CACHE (cpu); i < CPU_SCACHE_SIZE (cpu); + ++i, sc = (SCACHE *) ((char *) sc + elm_size)) + { + sc->argbuf.addr = UNUSED_ADDR; + } + } +#endif +} + +#if WITH_SCACHE_PBB + +/* Look up PC in the hash table of scache entry points. + Returns the entry or NULL if not found. */ + +SCACHE * +scache_lookup (SIM_CPU *cpu, IADDR pc) +{ + unsigned int slot = HASH_PC (pc) & (CPU_SCACHE_NUM_HASH_CHAINS (cpu) - 1); + int i, max_i = CPU_SCACHE_NUM_HASH_CHAIN_ENTRIES (cpu); + SCACHE_MAP *scm; + + /* We don't update hit/miss statistics as this is only used when recording + branch target addresses. */ + + scm = & CPU_SCACHE_HASH_TABLE (cpu) [slot]; + for (i = 0; i < max_i && scm->pc != UNUSED_ADDR; ++i, ++scm) + { + if (scm->pc == pc) + return scm->sc; + } + return 0; +} + +/* Look up PC and if not found create an entry for it. + If found the result is a pointer to the SCACHE entry. + If not found the result is NULL, and the address of a buffer of at least + N entries is stored in BUFP. + It's done this way so the caller can still distinguish found/not-found. + If the table is full, it is emptied to make room. + If the maximum length of a hash list is reached a random entry is thrown out + to make room. + ??? One might want to try to make this smarter, but let's see some + measurable benefit first. */ + +SCACHE * +scache_lookup_or_alloc (SIM_CPU *cpu, IADDR pc, int n, SCACHE **bufp) +{ + unsigned int slot = HASH_PC (pc) & (CPU_SCACHE_NUM_HASH_CHAINS (cpu) - 1); + int i, max_i = CPU_SCACHE_NUM_HASH_CHAIN_ENTRIES (cpu); + SCACHE_MAP *scm; + SCACHE *sc; + + scm = & CPU_SCACHE_HASH_TABLE (cpu) [slot]; + for (i = 0; i < max_i && scm->pc != UNUSED_ADDR; ++i, ++scm) + { + if (scm->pc == pc) + { + PROFILE_COUNT_SCACHE_HIT (cpu); + return scm->sc; + } + } + PROFILE_COUNT_SCACHE_MISS (cpu); + + /* The address we want isn't cached. Bummer. + If the hash chain we have for this address is full, throw out an entry + to make room. */ + + if (i == max_i) + { + /* Rather than do something sophisticated like LRU, we just throw out + a semi-random entry. Let someone else have the joy of saying how + wrong this is. NEXT_FREE is the entry to throw out and cycles + through all possibilities. */ + static int next_free = 0; + + scm = & CPU_SCACHE_HASH_TABLE (cpu) [slot]; + for (i = 0; i < next_free; ++i, ++scm) + continue; + ++next_free; + if (next_free == CPU_SCACHE_NUM_HASH_CHAIN_ENTRIES (cpu)) + next_free = 0; + } + + /* At this point SCM points to the hash table entry to use. + Now make sure there's room in the cache. */ + + { + int elm_size = IMP_PROPS_SCACHE_ELM_SIZE (MACH_IMP_PROPS (CPU_MACH (cpu))); + int elms_used = (((char *) CPU_SCACHE_NEXT_FREE (cpu) + - (char *) CPU_SCACHE_CACHE (cpu)) + / elm_size); + int elms_left = CPU_SCACHE_SIZE (cpu) - elms_used; + + if (elms_left < n) + { + PROFILE_COUNT_SCACHE_FULL_FLUSH (cpu); + scache_flush_cpu (cpu); + } + } + + sc = CPU_SCACHE_NEXT_FREE (cpu); + scm->pc = pc; + scm->sc = sc; + + *bufp = sc; + return NULL; +} + +#endif /* WITH_SCACHE_PBB */ + +/* Print cache access statics for CPU. */ + +void +scache_print_profile (SIM_CPU *cpu, int verbose) +{ + SIM_DESC sd = CPU_STATE (cpu); + unsigned long hits = CPU_SCACHE_HITS (cpu); + unsigned long misses = CPU_SCACHE_MISSES (cpu); + char buf[20]; + unsigned long max_val; + unsigned long *lengths; + int i; + + if (CPU_SCACHE_SIZE (cpu) == 0) + return; + + sim_io_printf (sd, "Simulator Cache Statistics\n\n"); + + /* One could use PROFILE_LABEL_WIDTH here. I chose not to. */ + sim_io_printf (sd, " Cache size: %s\n", + sim_add_commas (buf, sizeof (buf), CPU_SCACHE_SIZE (cpu))); + sim_io_printf (sd, " Hits: %s\n", + sim_add_commas (buf, sizeof (buf), hits)); + sim_io_printf (sd, " Misses: %s\n", + sim_add_commas (buf, sizeof (buf), misses)); + if (hits + misses != 0) + sim_io_printf (sd, " Hit rate: %.2f%%\n", + ((double) hits / ((double) hits + (double) misses)) * 100); + +#if WITH_SCACHE_PBB + sim_io_printf (sd, "\n"); + sim_io_printf (sd, " Hash table size: %s\n", + sim_add_commas (buf, sizeof (buf), CPU_SCACHE_NUM_HASH_CHAINS (cpu))); + sim_io_printf (sd, " Max hash list length: %s\n", + sim_add_commas (buf, sizeof (buf), CPU_SCACHE_NUM_HASH_CHAIN_ENTRIES (cpu))); + sim_io_printf (sd, " Max insn chain length: %s\n", + sim_add_commas (buf, sizeof (buf), CPU_SCACHE_MAX_CHAIN_LENGTH (cpu))); + sim_io_printf (sd, " Cache full flushes: %s\n", + sim_add_commas (buf, sizeof (buf), CPU_SCACHE_FULL_FLUSHES (cpu))); + sim_io_printf (sd, "\n"); + + if (verbose) + { + sim_io_printf (sd, " Insn chain lengths:\n\n"); + max_val = 0; + lengths = CPU_SCACHE_CHAIN_LENGTHS (cpu); + for (i = 1; i < CPU_SCACHE_MAX_CHAIN_LENGTH (cpu); ++i) + if (lengths[i] > max_val) + max_val = lengths[i]; + for (i = 1; i < CPU_SCACHE_MAX_CHAIN_LENGTH (cpu); ++i) + { + sim_io_printf (sd, " %2d: %*s: ", + i, + max_val < 10000 ? 5 : 10, + sim_add_commas (buf, sizeof (buf), lengths[i])); + sim_profile_print_bar (sd, PROFILE_HISTOGRAM_WIDTH, + lengths[i], max_val); + sim_io_printf (sd, "\n"); + } + sim_io_printf (sd, "\n"); + } +#endif /* WITH_SCACHE_PBB */ +} diff --git a/sim/common/cgen-scache.h b/sim/common/cgen-scache.h new file mode 100644 index 0000000..7ca4e65 --- /dev/null +++ b/sim/common/cgen-scache.h @@ -0,0 +1,162 @@ +/* Simulator header for cgen scache support. + Copyright (C) 1998 Free Software Foundation, Inc. + Contributed by Cygnus Solutions. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef CGEN_SCACHE_H +#define CGEN_SCACHE_H + +#ifndef WITH_SCACHE +#define WITH_SCACHE 0 +#endif + +/* When caching bb's, instructions are extracted into "chains". + SCACHE_MAP is a hash table into these chains. */ + +typedef struct { + IADDR pc; + SCACHE *sc; +} SCACHE_MAP; + +typedef struct cpu_scache { + /* Simulator cache size. Must be a power of 2. + This is the number of elements in the `cache' member. */ + unsigned int size; +#define CPU_SCACHE_SIZE(cpu) ((cpu) -> cgen_cpu.scache.size) + /* The cache. */ + SCACHE *cache; +#define CPU_SCACHE_CACHE(cpu) ((cpu) -> cgen_cpu.scache.cache) + +#if WITH_SCACHE_PBB + /* Number of hash chains. Must be a power of 2. */ + unsigned int num_hash_chains; +#define CPU_SCACHE_NUM_HASH_CHAINS(cpu) ((cpu) -> cgen_cpu.scache.num_hash_chains) + /* Number of entries in each hash chain. + The hash table is a statically allocated NxM array where + N = num_hash_chains + M = num_hash_chain_entries. */ + unsigned int num_hash_chain_entries; +#define CPU_SCACHE_NUM_HASH_CHAIN_ENTRIES(cpu) ((cpu) -> cgen_cpu.scache.num_hash_chain_entries) + /* Maximum number of instructions in a chain. + ??? This just let's us set a static size of chain_lengths table. + In a simulation that handles more than just the cpu, this might also be + used to keep too many instructions from being executed before checking + for events (or some such). */ + unsigned int max_chain_length; +#define CPU_SCACHE_MAX_CHAIN_LENGTH(cpu) ((cpu) -> cgen_cpu.scache.max_chain_length) + /* Special scache entry for (re)starting bb extraction. */ + SCACHE *pbb_begin; +#define CPU_SCACHE_PBB_BEGIN(cpu) ((cpu) -> cgen_cpu.scache.pbb_begin) + /* Hash table into cached chains. */ + SCACHE_MAP *hash_table; +#define CPU_SCACHE_HASH_TABLE(cpu) ((cpu) -> cgen_cpu.scache.hash_table) + /* Next free entry in cache. */ + SCACHE *next_free; +#define CPU_SCACHE_NEXT_FREE(cpu) ((cpu) -> cgen_cpu.scache.next_free) + + /* Address of cti-chain insn, only used by functional semantics, + not switch form. */ + SCACHE **pbb_br_npc_ptr; +#define CPU_PBB_BR_NPC_PTR(cpu) ((cpu) -> cgen_cpu.scache.pbb_br_npc_ptr) + /* Target's branch address. */ + IADDR pbb_br_npc; +#define CPU_PBB_BR_NPC(cpu) ((cpu) -> cgen_cpu.scache.pbb_br_npc) +#endif /* WITH_SCACHE_PBB */ + +#if WITH_PROFILE_SCACHE_P + /* Cache hits, misses. */ + unsigned long hits, misses; +#define CPU_SCACHE_HITS(cpu) ((cpu) -> cgen_cpu.scache.hits) +#define CPU_SCACHE_MISSES(cpu) ((cpu) -> cgen_cpu.scache.misses) + +#if WITH_SCACHE_PBB + /* Chain length counts. + Each element is a count of the number of chains created with that + length. */ + unsigned long *chain_lengths; +#define CPU_SCACHE_CHAIN_LENGTHS(cpu) ((cpu) -> cgen_cpu.scache.chain_lengths) + /* Number of times cache was flushed due to its being full. */ + unsigned long full_flushes; +#define CPU_SCACHE_FULL_FLUSHES(cpu) ((cpu) -> cgen_cpu.scache.full_flushes) +#endif +#endif +} CPU_SCACHE; + +/* Hash a PC value. + This is split into two parts to help with moving as much of the + computation out of the main loop. */ +#define CPU_SCACHE_HASH_MASK(cpu) (CPU_SCACHE_SIZE (cpu) - 1) +#define SCACHE_HASH_PC(pc, mask) \ +((CGEN_MIN_INSN_SIZE == 2 ? ((pc) >> 1) \ + : CGEN_MIN_INSN_SIZE == 4 ? ((pc) >> 2) \ + : (pc)) \ + & (mask)) + +/* Non-zero if cache is in use. */ +#define USING_SCACHE_P(sd) (STATE_SCACHE_SIZE (sd) > 0) + +/* Install the simulator cache into the simulator. */ +MODULE_INSTALL_FN scache_install; + +/* Lookup a PC value in the scache [compilation only]. */ +extern SCACHE * scache_lookup (SIM_CPU *, IADDR); +/* Return a pointer to at least N buffers. */ +extern SCACHE *scache_lookup_or_alloc (SIM_CPU *, IADDR, int, SCACHE **); +/* Flush all cpu's scaches. */ +extern void scache_flush (SIM_DESC); +/* Flush a cpu's scache. */ +extern void scache_flush_cpu (SIM_CPU *); + +/* Scache profiling support. */ + +/* Print summary scache usage information. */ +extern void scache_print_profile (SIM_CPU *cpu, int verbose); + +#if WITH_PROFILE_SCACHE_P + +#define PROFILE_COUNT_SCACHE_HIT(cpu) \ +do { \ + if (CPU_PROFILE_FLAGS (cpu) [PROFILE_SCACHE_IDX]) \ + ++ CPU_SCACHE_HITS (cpu); \ +} while (0) +#define PROFILE_COUNT_SCACHE_MISS(cpu) \ +do { \ + if (CPU_PROFILE_FLAGS (cpu) [PROFILE_SCACHE_IDX]) \ + ++ CPU_SCACHE_MISSES (cpu); \ +} while (0) +#define PROFILE_COUNT_SCACHE_CHAIN_LENGTH(cpu,length) \ +do { \ + if (CPU_PROFILE_FLAGS (cpu) [PROFILE_SCACHE_IDX]) \ + ++ CPU_SCACHE_CHAIN_LENGTHS (cpu) [length]; \ +} while (0) +#define PROFILE_COUNT_SCACHE_FULL_FLUSH(cpu) \ +do { \ + if (CPU_PROFILE_FLAGS (cpu) [PROFILE_SCACHE_IDX]) \ + ++ CPU_SCACHE_FULL_FLUSHES (cpu); \ +} while (0) + +#else + +#define PROFILE_COUNT_SCACHE_HIT(cpu) +#define PROFILE_COUNT_SCACHE_MISS(cpu) +#define PROFILE_COUNT_SCACHE_CHAIN_LENGTH(cpu,length) +#define PROFILE_COUNT_SCACHE_FULL_FLUSH(cpu) + +#endif + +#endif /* CGEN_SCACHE_H */ diff --git a/sim/common/cgen-sim.h b/sim/common/cgen-sim.h new file mode 100644 index 0000000..748015f --- /dev/null +++ b/sim/common/cgen-sim.h @@ -0,0 +1,34 @@ +/* Main header file for Cpu tools GENerated simulators. + Copyright (C) 1998 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file must be included after sim-base.h. */ + +#ifndef CGEN_SIM_H +#define CGEN_SIM_H + +#include "cgen-defs.h" +#include "cgen-scache.h" +#include "cgen-cpu.h" +#include "cgen-trace.h" + +/* This is a machine generated file. */ +#include "cpuall.h" + +#endif /* CGEN_SIM_H */ diff --git a/sim/common/cgen-trace.c b/sim/common/cgen-trace.c new file mode 100644 index 0000000..9b7d1fa --- /dev/null +++ b/sim/common/cgen-trace.c @@ -0,0 +1,414 @@ +/* Tracing support for CGEN-based simulators. + Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include "dis-asm.h" +#include "bfd.h" +#include "sim-main.h" + +#undef min +#define min(a,b) ((a) < (b) ? (a) : (b)) + +#ifndef SIZE_INSTRUCTION +#define SIZE_INSTRUCTION 16 +#endif + +#ifndef SIZE_LOCATION +#define SIZE_LOCATION 20 +#endif + +#ifndef SIZE_PC +#define SIZE_PC 6 +#endif + +#ifndef SIZE_LINE_NUMBER +#define SIZE_LINE_NUMBER 4 +#endif + +#ifndef SIZE_CYCLE_COUNT +#define SIZE_CYCLE_COUNT 2 +#endif + +#ifndef SIZE_TOTAL_CYCLE_COUNT +#define SIZE_TOTAL_CYCLE_COUNT 9 +#endif + +#ifndef SIZE_TRACE_BUF +#define SIZE_TRACE_BUF 256 +#endif + +static void +disassemble_insn (SIM_CPU *, const CGEN_INSN *, + const struct argbuf *, IADDR, char *); + +/* Text is queued in TRACE_BUF because we want to output the insn's cycle + count first but that isn't known until after the insn has executed. + This also handles the queueing of trace results, TRACE_RESULT may be + called multiple times for one insn. */ +static char trace_buf[SIZE_TRACE_BUF]; +/* If NULL, output to stdout directly. */ +static char *bufptr; + +/* Non-zero if this is the first insn in a set of parallel insns. */ +static int first_insn_p; + +/* For communication between trace_insn and trace_result. */ +static int printed_result_p; + +/* Insn and its extracted fields. + Set by trace_insn, used by trace_insn_fini. + ??? Move to SIM_CPU to support heterogeneous multi-cpu case. */ +static const struct cgen_insn *current_insn; +static const struct argbuf *current_abuf; + +void +trace_insn_init (SIM_CPU *cpu, int first_p) +{ + bufptr = trace_buf; + *bufptr = 0; + first_insn_p = first_p; + + /* Set to NULL so trace_insn_fini can know if trace_insn was called. */ + current_insn = NULL; + current_abuf = NULL; +} + +void +trace_insn_fini (SIM_CPU *cpu, const struct argbuf *abuf, int last_p) +{ + SIM_DESC sd = CPU_STATE (cpu); + + /* Was insn traced? It might not be if trace ranges are in effect. */ + if (current_insn == NULL) + return; + + /* The first thing printed is current and total cycle counts. */ + + if (PROFILE_MODEL_P (cpu) + && ARGBUF_PROFILE_P (current_abuf)) + { + unsigned long total = PROFILE_MODEL_TOTAL_CYCLES (CPU_PROFILE_DATA (cpu)); + unsigned long this_insn = PROFILE_MODEL_CUR_INSN_CYCLES (CPU_PROFILE_DATA (cpu)); + + if (last_p) + { + trace_printf (sd, cpu, "%-*ld %-*ld ", + SIZE_CYCLE_COUNT, this_insn, + SIZE_TOTAL_CYCLE_COUNT, total); + } + else + { + trace_printf (sd, cpu, "%-*ld %-*s ", + SIZE_CYCLE_COUNT, this_insn, + SIZE_TOTAL_CYCLE_COUNT, "---"); + } + } + + /* Print the disassembled insn. */ + + trace_printf (sd, cpu, "%s", TRACE_PREFIX (CPU_TRACE_DATA (cpu))); + +#if 0 + /* Print insn results. */ + { + const CGEN_OPINST *opinst = CGEN_INSN_OPERANDS (current_insn); + + if (opinst) + { + int i; + int indices[MAX_OPERAND_INSTANCES]; + + /* Fetch the operands used by the insn. */ + /* FIXME: Add fn ptr to CGEN_CPU_DESC. */ + CGEN_SYM (get_insn_operands) (CPU_CPU_DESC (cpu), current_insn, + 0, CGEN_FIELDS_BITSIZE (&insn_fields), + indices); + + for (i = 0; + CGEN_OPINST_TYPE (opinst) != CGEN_OPINST_END; + ++i, ++opinst) + { + if (CGEN_OPINST_TYPE (opinst) == CGEN_OPINST_OUTPUT) + trace_result (cpu, current_insn, opinst, indices[i]); + } + } + } +#endif + + /* Print anything else requested. */ + + if (*trace_buf) + trace_printf (sd, cpu, " %s\n", trace_buf); + else + trace_printf (sd, cpu, "\n"); +} + +void +trace_insn (SIM_CPU *cpu, const struct cgen_insn *opcode, + const struct argbuf *abuf, IADDR pc) +{ + char disasm_buf[50]; + + printed_result_p = 0; + current_insn = opcode; + current_abuf = abuf; + + if (CGEN_INSN_VIRTUAL_P (opcode)) + { + trace_prefix (CPU_STATE (cpu), cpu, NULL_CIA, pc, 0, + NULL, 0, CGEN_INSN_NAME (opcode)); + return; + } + + CPU_DISASSEMBLER (cpu) (cpu, opcode, abuf, pc, disasm_buf); + trace_prefix (CPU_STATE (cpu), cpu, NULL_CIA, pc, TRACE_LINENUM_P (cpu), + NULL, 0, + "%s%-*s", + first_insn_p ? " " : "|", + SIZE_INSTRUCTION, disasm_buf); +} + +void +trace_extract (SIM_CPU *cpu, IADDR pc, char *name, ...) +{ + va_list args; + int printed_one_p = 0; + char *fmt; + + va_start (args, name); + + trace_printf (CPU_STATE (cpu), cpu, "Extract: 0x%.*lx: %s ", + SIZE_PC, pc, name); + + do { + int type,ival; + + fmt = va_arg (args, char *); + + if (fmt) + { + if (printed_one_p) + trace_printf (CPU_STATE (cpu), cpu, ", "); + printed_one_p = 1; + type = va_arg (args, int); + switch (type) + { + case 'x' : + ival = va_arg (args, int); + trace_printf (CPU_STATE (cpu), cpu, fmt, ival); + break; + default : + abort (); + } + } + } while (fmt); + + va_end (args); + trace_printf (CPU_STATE (cpu), cpu, "\n"); +} + +void +trace_result (SIM_CPU *cpu, char *name, int type, ...) +{ + va_list args; + + va_start (args, type); + if (printed_result_p) + cgen_trace_printf (cpu, ", "); + + switch (type) + { + case 'x' : + default : + cgen_trace_printf (cpu, "%s <- 0x%x", name, va_arg (args, int)); + break; + case 'D' : + { + DI di; + /* this is separated from previous line for sunos cc */ + di = va_arg (args, DI); + cgen_trace_printf (cpu, "%s <- 0x%x%08x", name, + GETHIDI(di), GETLODI (di)); + break; + } + } + + printed_result_p = 1; + va_end (args); +} + +/* Print trace output to BUFPTR if active, otherwise print normally. + This is only for tracing semantic code. */ + +void +cgen_trace_printf (SIM_CPU *cpu, char *fmt, ...) +{ + va_list args; + + va_start (args, fmt); + + if (bufptr == NULL) + { + if (TRACE_FILE (CPU_TRACE_DATA (cpu)) == NULL) + (* STATE_CALLBACK (CPU_STATE (cpu))->evprintf_filtered) + (STATE_CALLBACK (CPU_STATE (cpu)), fmt, args); + else + vfprintf (TRACE_FILE (CPU_TRACE_DATA (cpu)), fmt, args); + } + else + { + vsprintf (bufptr, fmt, args); + bufptr += strlen (bufptr); + /* ??? Need version of SIM_ASSERT that is always enabled. */ + if (bufptr - trace_buf > SIZE_TRACE_BUF) + abort (); + } + + va_end (args); +} + +/* Disassembly support. */ + +/* sprintf to a "stream" */ + +int +sim_disasm_sprintf VPARAMS ((SFILE *f, const char *format, ...)) +{ +#ifndef __STDC__ + SFILE *f; + const char *format; +#endif + int n; + va_list args; + + VA_START (args, format); +#ifndef __STDC__ + f = va_arg (args, SFILE *); + format = va_arg (args, char *); +#endif + vsprintf (f->current, format, args); + f->current += n = strlen (f->current); + va_end (args); + return n; +} + +/* Memory read support for an opcodes disassembler. */ + +int +sim_disasm_read_memory (bfd_vma memaddr, bfd_byte *myaddr, int length, + struct disassemble_info *info) +{ + SIM_CPU *cpu = (SIM_CPU *) info->application_data; + SIM_DESC sd = CPU_STATE (cpu); + int length_read; + + length_read = sim_core_read_buffer (sd, cpu, read_map, myaddr, memaddr, + length); + if (length_read != length) + return EIO; + return 0; +} + +/* Memory error support for an opcodes disassembler. */ + +void +sim_disasm_perror_memory (int status, bfd_vma memaddr, + struct disassemble_info *info) +{ + if (status != EIO) + /* Can't happen. */ + info->fprintf_func (info->stream, "Unknown error %d.", status); + else + /* Actually, address between memaddr and memaddr + len was + out of bounds. */ + info->fprintf_func (info->stream, + "Address 0x%x is out of bounds.", + (int) memaddr); +} + +/* Disassemble using the CGEN opcode table. + ??? While executing an instruction, the insn has been decoded and all its + fields have been extracted. It is certainly possible to do the disassembly + with that data. This seems simpler, but maybe in the future the already + extracted fields will be used. */ + +void +sim_cgen_disassemble_insn (SIM_CPU *cpu, const CGEN_INSN *insn, + const ARGBUF *abuf, IADDR pc, char *buf) +{ + unsigned int length; + unsigned long insn_value; + struct disassemble_info disasm_info; + SFILE sfile; + union { + unsigned8 bytes[CGEN_MAX_INSN_SIZE]; + unsigned16 shorts[8]; + unsigned32 words[4]; + } insn_buf; + SIM_DESC sd = CPU_STATE (cpu); + CGEN_CPU_DESC cd = CPU_CPU_DESC (cpu); + CGEN_EXTRACT_INFO ex_info; + CGEN_FIELDS *fields = alloca (CGEN_CPU_SIZEOF_FIELDS (cd)); + int insn_bit_length = CGEN_INSN_BITSIZE (insn); + int insn_length = insn_bit_length / 8; + + sfile.buffer = sfile.current = buf; + INIT_DISASSEMBLE_INFO (disasm_info, (FILE *) &sfile, + (fprintf_ftype) sim_disasm_sprintf); + disasm_info.endian = + (bfd_big_endian (STATE_PROG_BFD (sd)) ? BFD_ENDIAN_BIG + : bfd_little_endian (STATE_PROG_BFD (sd)) ? BFD_ENDIAN_LITTLE + : BFD_ENDIAN_UNKNOWN); + + length = sim_core_read_buffer (sd, cpu, read_map, &insn_buf, pc, + insn_length); + + switch (min (CGEN_BASE_INSN_SIZE, insn_length)) + { + case 0 : return; /* fake insn, typically "compile" (aka "invalid") */ + case 1 : insn_value = insn_buf.bytes[0]; break; + case 2 : insn_value = T2H_2 (insn_buf.shorts[0]); break; + case 4 : insn_value = T2H_4 (insn_buf.words[0]); break; + default: abort (); + } + + disasm_info.buffer_vma = pc; + disasm_info.buffer = insn_buf.bytes; + disasm_info.buffer_length = length; + + ex_info.dis_info = (PTR) &disasm_info; + ex_info.valid = (1 << length) - 1; + ex_info.insn_bytes = insn_buf.bytes; + + length = (*CGEN_EXTRACT_FN (cd, insn)) (cd, insn, &ex_info, insn_value, fields, pc); + /* Result of extract fn is in bits. */ + /* ??? This assumes that each instruction has a fixed length (and thus + for insns with multiple versions of variable lengths they would each + have their own table entry). */ + if (length == insn_bit_length) + { + (*CGEN_PRINT_FN (cd, insn)) (cd, &disasm_info, insn, fields, pc, length); + } + else + { + /* This shouldn't happen, but aborting is too drastic. */ + strcpy (buf, "***unknown***"); + } +} diff --git a/sim/common/cgen-trace.h b/sim/common/cgen-trace.h new file mode 100644 index 0000000..5e796fb --- /dev/null +++ b/sim/common/cgen-trace.h @@ -0,0 +1,91 @@ +/* Simulator tracing support for Cpu tools GENerated simulators. + Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef CGEN_TRACE_H +#define CGEN_TRACE_H + +void trace_insn_init (SIM_CPU *, int); +void trace_insn_fini (SIM_CPU *, const struct argbuf *, int); +void trace_insn (SIM_CPU *, const struct cgen_insn *, + const struct argbuf *, IADDR); +void trace_extract (SIM_CPU *, IADDR, char *, ...); +void trace_result (SIM_CPU *, char *, int, ...); +void cgen_trace_printf (SIM_CPU *, char *fmt, ...); + +/* Trace instruction results. */ +#define TRACE_RESULT_P(cpu, abuf) (TRACE_INSN_P (cpu) && ARGBUF_TRACE_P (abuf)) + +#define TRACE_INSN_INIT(cpu, abuf, first_p) \ +do { \ + if (TRACE_INSN_P (cpu)) \ + trace_insn_init ((cpu), (first_p)); \ +} while (0) +#define TRACE_INSN_FINI(cpu, abuf, last_p) \ +do { \ + if (TRACE_INSN_P (cpu)) \ + trace_insn_fini ((cpu), (abuf), (last_p)); \ +} while (0) +#define TRACE_PRINTF(cpu, what, args) \ +do { \ + if (TRACE_P ((cpu), (what))) \ + cgen_trace_printf args ; \ +} while (0) +#define TRACE_INSN(cpu, insn, abuf, pc) \ +do { \ + if (TRACE_INSN_P (cpu) && ARGBUF_TRACE_P (abuf)) \ + trace_insn ((cpu), (insn), (abuf), (pc)) ; \ +} while (0) +#define TRACE_EXTRACT(cpu, abuf, args) \ +do { \ + if (TRACE_EXTRACT_P (cpu)) \ + trace_extract args ; \ +} while (0) +#define TRACE_RESULT(cpu, abuf, name, type, val) \ +do { \ + if (TRACE_RESULT_P ((cpu), (abuf))) \ + trace_result ((cpu), (name), (type), (val)) ; \ +} while (0) + +/* Disassembly support. */ + +/* Function to use for cgen-based disassemblers. */ +extern CGEN_DISASSEMBLER sim_cgen_disassemble_insn; + +/* Pseudo FILE object for strings. */ +typedef struct { + char *buffer; + char *current; +} SFILE; + +/* String printer for the disassembler. */ +extern int sim_disasm_sprintf (SFILE *, const char *, ...); + +/* For opcodes based disassemblers. */ +#ifdef BFD_VERSION +struct disassemble_info; +extern int +sim_disasm_read_memory (bfd_vma memaddr_, bfd_byte *myaddr_, int length_, + struct disassemble_info *info_); +extern void +sim_disasm_perror_memory (int status_, bfd_vma memaddr_, + struct disassemble_info *info_); +#endif + +#endif /* CGEN_TRACE_H */ diff --git a/sim/common/cgen-types.h b/sim/common/cgen-types.h new file mode 100644 index 0000000..e57e601 --- /dev/null +++ b/sim/common/cgen-types.h @@ -0,0 +1,116 @@ +/* Types for Cpu tools GENerated simulators. + Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file is not included with cgen-sim.h as it defines types + needed by sim-base.h. */ + +#ifndef CGEN_TYPES_H +#define CGEN_TYPES_H + +/* Miscellaneous cgen configury defined here as this file gets + included soon enough. */ + +/* Indicate we support --profile-model. */ +#undef SIM_HAVE_MODEL +#define SIM_HAVE_MODEL + +/* Indicate we support --{profile,trace}-{range,function}. */ +#undef SIM_HAVE_ADDR_RANGE +#define SIM_HAVE_ADDR_RANGE + +#ifdef __GNUC__ +#define HAVE_LONGLONG +#undef DI_FN_SUPPORT +#else +#undef HAVE_LONGLONG +#define DI_FN_SUPPORT +#endif + +/* Mode support. */ + +/* Common mode types. */ +/* ??? Target specific modes. */ +typedef enum mode_type { + MODE_VM, MODE_BI, + MODE_QI, MODE_HI, MODE_SI, MODE_DI, + MODE_UQI, MODE_UHI, MODE_USI, MODE_UDI, + MODE_SF, MODE_DF, MODE_XF, MODE_TF, + MODE_TARGET_MAX /* = MODE_TF? */, + /* These are host modes. */ + MODE_INT, MODE_UINT, MODE_PTR, /*??? MODE_ADDR, MODE_IADDR,*/ + MODE_MAX +} MODE_TYPE; + +#define MAX_TARGET_MODES ((int) MODE_TARGET_MAX) +#define MAX_MODES ((int) MODE_MAX) + +extern const char *mode_names[]; +#define MODE_NAME(m) (mode_names[m]) + +typedef unsigned char BI; +typedef signed8 QI; +typedef signed16 HI; +typedef signed32 SI; +typedef unsigned8 UQI; +typedef unsigned16 UHI; +typedef unsigned32 USI; + +#ifdef HAVE_LONGLONG +typedef signed64 DI; +typedef unsigned64 UDI; +#define GETLODI(di) ((SI) (di)) +#define GETHIDI(di) ((SI) ((UDI) (di) >> 32)) +#define SETLODI(di, val) ((di) = (((di) & 0xffffffff00000000LL) | (val))) +#define SETHIDI(di, val) ((di) = (((di) & 0xffffffffLL) | (((DI) (val)) << 32))) +#define SETDI(di, hi, lo) ((di) = MAKEDI (hi, lo)) +#define MAKEDI(hi, lo) ((((DI) (SI) (hi)) << 32) | ((UDI) (USI) (lo))) +#else +/* DI mode support if "long long" doesn't exist. + At one point CGEN supported K&R C compilers, and ANSI C compilers without + "long long". One can argue the various merits of keeping this in or + throwing it out. I went to the trouble of adding it so for the time being + I'm leaving it in. */ +typedef struct { SI hi,lo; } DI; +typedef DI UDI; +#define GETLODI(di) ((di).lo) +#define GETHIDI(di) ((di).hi) +#define SETLODI(di, val) ((di).lo = (val)) +#define SETHIDI(di, val) ((di).hi = (val)) +#define SETDI(di, hi, lo) ((di) = MAKEDI (hi, lo)) +extern DI make_struct_di (SI, SI); +#define MAKEDI(hi, lo) (make_struct_di ((hi), (lo))) +#endif + +/* FIXME: Need to provide libraries if these aren't appropriate for target, + or user's needs. */ +typedef float SF; +typedef double DF; +typedef double XF; /* FIXME: configure, provide library */ +typedef double TF; /* FIXME: configure, provide library */ + +/* These are used to record extracted raw data from an instruction, among other + things. It must be a host data type, and not a target one. */ +typedef int INT; +typedef unsigned int UINT; + +typedef unsigned_address ADDR; /* FIXME: wip*/ +typedef unsigned_address IADDR; /* FIXME: wip*/ + +#endif /* CGEN_TYPES_H */ diff --git a/sim/common/cgen-utils.c b/sim/common/cgen-utils.c new file mode 100644 index 0000000..2faff5c --- /dev/null +++ b/sim/common/cgen-utils.c @@ -0,0 +1,328 @@ +/* Support code for various pieces of CGEN simulators. + Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sim-main.h" +#include "dis-asm.h" + +#define MEMOPS_DEFINE_INLINE +#include "cgen-mem.h" + +#define SEMOPS_DEFINE_INLINE +#include "cgen-ops.h" + +#undef min +#define min(a,b) ((a) < (b) ? (a) : (b)) + +const char *mode_names[] = { + "VM", + "BI", + "QI", + "HI", + "SI", + "DI", + "UQI", + "UHI", + "USI", + "UDI", + "SF", + "DF", + "XF", + "TF", + 0, /* MODE_TARGET_MAX */ + "INT", + "UINT", + "PTR" +}; + +/* Opcode table for virtual insns used by the simulator. */ + +#define V CGEN_ATTR_MASK (CGEN_INSN_VIRTUAL) + +static const CGEN_IBASE virtual_insn_entries[] = +{ + { + VIRTUAL_INSN_X_INVALID, "--invalid--", NULL, 0, + { CGEN_INSN_NBOOL_ATTRS, V, { 0 } } + }, + { + VIRTUAL_INSN_X_BEFORE, "--before--", NULL, 0, + { CGEN_INSN_NBOOL_ATTRS, V, { 0 } } + }, + { + VIRTUAL_INSN_X_AFTER, "--after--", NULL, 0, + { CGEN_INSN_NBOOL_ATTRS, V, { 0 } } + }, + { + VIRTUAL_INSN_X_BEGIN, "--begin--", NULL, 0, + { CGEN_INSN_NBOOL_ATTRS, V, { 0 } } + }, + { + VIRTUAL_INSN_X_CHAIN, "--chain--", NULL, 0, + { CGEN_INSN_NBOOL_ATTRS, V, { 0 } } + }, + { + VIRTUAL_INSN_X_CTI_CHAIN, "--cti-chain--", NULL, 0, + { CGEN_INSN_NBOOL_ATTRS, V, { 0 } } + } +}; + +#undef V + +const CGEN_INSN cgen_virtual_insn_table[] = +{ + { & virtual_insn_entries[0] }, + { & virtual_insn_entries[1] }, + { & virtual_insn_entries[2] }, + { & virtual_insn_entries[3] }, + { & virtual_insn_entries[4] }, + { & virtual_insn_entries[5] } +}; + +/* Initialize cgen things. + This is called after sim_post_argv_init. */ + +void +cgen_init (SIM_DESC sd) +{ + int i, c; + + /* If no profiling or tracing has been enabled, run in fast mode. */ + { + int run_fast_p = 1; + + for (c = 0; c < MAX_NR_PROCESSORS; ++c) + { + SIM_CPU *cpu = STATE_CPU (sd, c); + + for (i = 0; i < MAX_PROFILE_VALUES; ++i) + if (CPU_PROFILE_FLAGS (cpu) [i]) + { + run_fast_p = 0; + break; + } + for (i = 0; i < MAX_TRACE_VALUES; ++i) + if (CPU_TRACE_FLAGS (cpu) [i]) + { + run_fast_p = 0; + break; + } + if (! run_fast_p) + break; + } + STATE_RUN_FAST_P (sd) = run_fast_p; + } +} + +/* Return the name of insn number I. */ + +const char * +cgen_insn_name (SIM_CPU *cpu, int i) +{ + return CGEN_INSN_NAME ((* CPU_GET_IDATA (cpu)) ((cpu), (i))); +} + +/* Return the maximum number of extra bytes required for a SIM_CPU struct. */ + +int +cgen_cpu_max_extra_bytes (void) +{ + int i; + int extra = 0; + + for (i = 0; sim_machs[i] != 0; ++i) + { + int size = IMP_PROPS_SIM_CPU_SIZE (MACH_IMP_PROPS (sim_machs[i])); + if (size > extra) + extra = size; + } + return extra; +} + +#ifdef DI_FN_SUPPORT + +DI +make_struct_di (hi, lo) + SI hi, lo; +{ + DI result; + + result.hi = hi; + result.lo = lo; + return result; +} + +DI +ANDDI (a, b) + DI a, b; +{ + SI ahi = GETHIDI (a); + SI alo = GETLODI (a); + SI bhi = GETHIDI (b); + SI blo = GETLODI (b); + return MAKEDI (ahi & bhi, alo & blo); +} + +DI +ORDI (a, b) + DI a, b; +{ + SI ahi = GETHIDI (a); + SI alo = GETLODI (a); + SI bhi = GETHIDI (b); + SI blo = GETLODI (b); + return MAKEDI (ahi | bhi, alo | blo); +} + +DI +ADDDI (a, b) + DI a, b; +{ + USI ahi = GETHIDI (a); + USI alo = GETLODI (a); + USI bhi = GETHIDI (b); + USI blo = GETLODI (b); + USI x = alo + blo; + return MAKEDI (ahi + bhi + (x < alo), x); +} + +DI +MULDI (a, b) + DI a, b; +{ + USI ahi = GETHIDI (a); + USI alo = GETLODI (a); + USI bhi = GETHIDI (b); + USI blo = GETLODI (b); + USI rhi,rlo; + USI x0, x1, x2, x3; + + x0 = alo * blo; + x1 = alo * bhi; + x2 = ahi * blo; + x3 = ahi * bhi; + +#define SI_TYPE_SIZE 32 +#define BITS4 (SI_TYPE_SIZE / 4) +#define ll_B (1L << (SI_TYPE_SIZE / 2)) +#define ll_lowpart(t) ((USI) (t) % ll_B) +#define ll_highpart(t) ((USI) (t) / ll_B) + x1 += ll_highpart (x0); /* this can't give carry */ + x1 += x2; /* but this indeed can */ + if (x1 < x2) /* did we get it? */ + x3 += ll_B; /* yes, add it in the proper pos. */ + + rhi = x3 + ll_highpart (x1); + rlo = ll_lowpart (x1) * ll_B + ll_lowpart (x0); + return MAKEDI (rhi + (alo * bhi) + (ahi * blo), rlo); +} + +DI +SHLDI (val, shift) + DI val; + SI shift; +{ + USI hi = GETHIDI (val); + USI lo = GETLODI (val); + /* FIXME: Need to worry about shift < 0 || shift >= 32. */ + return MAKEDI ((hi << shift) | (lo >> (32 - shift)), lo << shift); +} + +DI +SLADI (val, shift) + DI val; + SI shift; +{ + SI hi = GETHIDI (val); + USI lo = GETLODI (val); + /* FIXME: Need to worry about shift < 0 || shift >= 32. */ + return MAKEDI ((hi << shift) | (lo >> (32 - shift)), lo << shift); +} + +DI +SRADI (val, shift) + DI val; + SI shift; +{ + SI hi = GETHIDI (val); + USI lo = GETLODI (val); + /* We use SRASI because the result is implementation defined if hi < 0. */ + /* FIXME: Need to worry about shift < 0 || shift >= 32. */ + return MAKEDI (SRASI (hi, shift), (hi << (32 - shift)) | (lo >> shift)); +} + +int +GEDI (a, b) + DI a, b; +{ + SI ahi = GETHIDI (a); + USI alo = GETLODI (a); + SI bhi = GETHIDI (b); + USI blo = GETLODI (b); + if (ahi > bhi) + return 1; + if (ahi == bhi) + return alo >= blo; + return 0; +} + +int +LEDI (a, b) + DI a, b; +{ + SI ahi = GETHIDI (a); + USI alo = GETLODI (a); + SI bhi = GETHIDI (b); + USI blo = GETLODI (b); + if (ahi < bhi) + return 1; + if (ahi == bhi) + return alo <= blo; + return 0; +} + +DI +CONVHIDI (val) + HI val; +{ + if (val < 0) + return MAKEDI (-1, val); + else + return MAKEDI (0, val); +} + +DI +CONVSIDI (val) + SI val; +{ + if (val < 0) + return MAKEDI (-1, val); + else + return MAKEDI (0, val); +} + +SI +CONVDISI (val) + DI val; +{ + return GETLODI (val); +} + +#endif /* DI_FN_SUPPORT */ diff --git a/sim/common/config.in b/sim/common/config.in new file mode 100644 index 0000000..4df9560 --- /dev/null +++ b/sim/common/config.in @@ -0,0 +1,167 @@ +/* config.in. Generated automatically from configure.in by autoheader. */ + +/* Define if using alloca.c. */ +#undef C_ALLOCA + +/* Define to empty if the keyword does not work. */ +#undef const + +/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems. + This function is required for alloca.c support on those systems. */ +#undef CRAY_STACKSEG_END + +/* Define if you have alloca, as a function or macro. */ +#undef HAVE_ALLOCA + +/* Define if you have <alloca.h> and it should be used (not on Ultrix). */ +#undef HAVE_ALLOCA_H + +/* Define if you have a working `mmap' system call. */ +#undef HAVE_MMAP + +/* Define as __inline if that's what the C compiler calls it. */ +#undef inline + +/* Define to `long' if <sys/types.h> doesn't define. */ +#undef off_t + +/* Define if you need to in order for stat and other things to work. */ +#undef _POSIX_SOURCE + +/* Define as the return type of signal handlers (int or void). */ +#undef RETSIGTYPE + +/* Define to `unsigned' if <sys/types.h> doesn't define. */ +#undef size_t + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at run-time. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown + */ +#undef STACK_DIRECTION + +/* Define if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define to 1 if NLS is requested. */ +#undef ENABLE_NLS + +/* Define as 1 if you have gettext and don't want to use GNU gettext. */ +#undef HAVE_GETTEXT + +/* Define as 1 if you have the stpcpy function. */ +#undef HAVE_STPCPY + +/* Define if your locale.h file contains LC_MESSAGES. */ +#undef HAVE_LC_MESSAGES + +/* Define if you have the __argz_count function. */ +#undef HAVE___ARGZ_COUNT + +/* Define if you have the __argz_next function. */ +#undef HAVE___ARGZ_NEXT + +/* Define if you have the __argz_stringify function. */ +#undef HAVE___ARGZ_STRINGIFY + +/* Define if you have the __setfpucw function. */ +#undef HAVE___SETFPUCW + +/* Define if you have the dcgettext function. */ +#undef HAVE_DCGETTEXT + +/* Define if you have the getcwd function. */ +#undef HAVE_GETCWD + +/* Define if you have the getpagesize function. */ +#undef HAVE_GETPAGESIZE + +/* Define if you have the getrusage function. */ +#undef HAVE_GETRUSAGE + +/* Define if you have the munmap function. */ +#undef HAVE_MUNMAP + +/* Define if you have the putenv function. */ +#undef HAVE_PUTENV + +/* Define if you have the setenv function. */ +#undef HAVE_SETENV + +/* Define if you have the setlocale function. */ +#undef HAVE_SETLOCALE + +/* Define if you have the sigaction function. */ +#undef HAVE_SIGACTION + +/* Define if you have the stpcpy function. */ +#undef HAVE_STPCPY + +/* Define if you have the strcasecmp function. */ +#undef HAVE_STRCASECMP + +/* Define if you have the strchr function. */ +#undef HAVE_STRCHR + +/* Define if you have the time function. */ +#undef HAVE_TIME + +/* Define if you have the <argz.h> header file. */ +#undef HAVE_ARGZ_H + +/* Define if you have the <dlfcn.h> header file. */ +#undef HAVE_DLFCN_H + +/* Define if you have the <errno.h> header file. */ +#undef HAVE_ERRNO_H + +/* Define if you have the <fcntl.h> header file. */ +#undef HAVE_FCNTL_H + +/* Define if you have the <fpu_control.h> header file. */ +#undef HAVE_FPU_CONTROL_H + +/* Define if you have the <limits.h> header file. */ +#undef HAVE_LIMITS_H + +/* Define if you have the <locale.h> header file. */ +#undef HAVE_LOCALE_H + +/* Define if you have the <malloc.h> header file. */ +#undef HAVE_MALLOC_H + +/* Define if you have the <nl_types.h> header file. */ +#undef HAVE_NL_TYPES_H + +/* Define if you have the <stdlib.h> header file. */ +#undef HAVE_STDLIB_H + +/* Define if you have the <string.h> header file. */ +#undef HAVE_STRING_H + +/* Define if you have the <strings.h> header file. */ +#undef HAVE_STRINGS_H + +/* Define if you have the <sys/param.h> header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define if you have the <sys/resource.h> header file. */ +#undef HAVE_SYS_RESOURCE_H + +/* Define if you have the <sys/time.h> header file. */ +#undef HAVE_SYS_TIME_H + +/* Define if you have the <sys/times.h> header file. */ +#undef HAVE_SYS_TIMES_H + +/* Define if you have the <time.h> header file. */ +#undef HAVE_TIME_H + +/* Define if you have the <unistd.h> header file. */ +#undef HAVE_UNISTD_H + +/* Define if you have the <values.h> header file. */ +#undef HAVE_VALUES_H diff --git a/sim/common/configure b/sim/common/configure new file mode 100755 index 0000000..4dc7670 --- /dev/null +++ b/sim/common/configure @@ -0,0 +1,3902 @@ +#! /bin/sh + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +sim_inline="-DDEFAULT_INLINE=0" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# This file is derived from `gettext.m4'. The difference is that the +# included macros assume Cygnus-style source and build trees. + +# Macro to add for using GNU gettext. +# Ulrich Drepper <drepper@cygnus.com>, 1995. +# +# This file file be copied and used freely without restrictions. It can +# be used in projects which are not available under the GNU Public License +# but which still want to provide support for the GNU gettext functionality. +# Please note that the actual code is *not* freely available. + +# serial 3 + + + + + +# Search path for a program which passes the given test. +# Ulrich Drepper <drepper@cygnus.com>, 1996. +# +# This file file be copied and used freely without restrictions. It can +# be used in projects which are not available under the GNU Public License +# but which still want to provide support for the GNU gettext functionality. +# Please note that the actual code is *not* freely available. + +# serial 1 + + + +# Check whether LC_MESSAGES is available in <locale.h>. +# Ulrich Drepper <drepper@cygnus.com>, 1995. +# +# This file file be copied and used freely without restrictions. It can +# be used in projects which are not available under the GNU Public License +# but which still want to provide support for the GNU gettext functionality. +# Please note that the actual code is *not* freely available. + +# serial 1 + + + +# Check to see if we're running under Cygwin32, without using +# AC_CANONICAL_*. If so, set output variable CYGWIN32 to "yes". +# Otherwise set it to "no". + + + +# Check to see if we're running under Win32, without using +# AC_CANONICAL_*. If so, set output variable EXEEXT to ".exe". +# Otherwise set it to "". + + + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.12.2 +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: +ac_help="$ac_help + --disable-nls do not use Native Language Support" +ac_help="$ac_help + --with-included-gettext use the GNU gettext library included here" +ac_help="$ac_help + --enable-maintainer-mode Enable developer functionality." +ac_help="$ac_help + --enable-sim-bswap Use Host specific BSWAP instruction." +ac_help="$ac_help + --enable-sim-cflags=opts Extra CFLAGS for use in building simulator" +ac_help="$ac_help + --enable-sim-debug=opts Enable debugging flags" +ac_help="$ac_help + --enable-sim-stdio Specify whether to use stdio for console input/output." +ac_help="$ac_help + --enable-sim-trace=opts Enable tracing flags" +ac_help="$ac_help + --enable-sim-profile=opts Enable profiling flags" + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.12.2" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=Makefile.in + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +ac_exeext= +ac_objext=o +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + + +# This is intended for use by the target specific directories, and by us. +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:677: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext <<EOF +#line 692 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:698: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext <<EOF +#line 709 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:715: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -nologo -E" + cat > conftest.$ac_ext <<EOF +#line 726 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:732: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + +echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 +echo "configure:757: checking whether ${MAKE-make} sets \${MAKE}" >&5 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftestmake <<\EOF +all: + @echo 'ac_maketemp="${MAKE}"' +EOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftestmake +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$ac_t""yes" 1>&6 + SET_MAKE= +else + echo "$ac_t""no" 1>&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + +echo $ac_n "checking for POSIXized ISC""... $ac_c" 1>&6 +echo "configure:784: checking for POSIXized ISC" >&5 +if test -d /etc/conf/kconfig.d && + grep _POSIX_VERSION /usr/include/sys/unistd.h >/dev/null 2>&1 +then + echo "$ac_t""yes" 1>&6 + ISC=yes # If later tests want to check for ISC. + cat >> confdefs.h <<\EOF +#define _POSIX_SOURCE 1 +EOF + + if test "$GCC" = yes; then + CC="$CC -posix" + else + CC="$CC -Xp" + fi +else + echo "$ac_t""no" 1>&6 + ISC= +fi + +echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 +echo "configure:805: checking for ANSI C header files" >&5 +if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 810 "configure" +#include "confdefs.h" +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:818: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + ac_cv_header_stdc=yes +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. +cat > conftest.$ac_ext <<EOF +#line 835 "configure" +#include "confdefs.h" +#include <string.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "memchr" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. +cat > conftest.$ac_ext <<EOF +#line 853 "configure" +#include "confdefs.h" +#include <stdlib.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "free" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. +if test "$cross_compiling" = yes; then + : +else + cat > conftest.$ac_ext <<EOF +#line 874 "configure" +#include "confdefs.h" +#include <ctype.h> +#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int main () { int i; for (i = 0; i < 256; i++) +if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); +exit (0); } + +EOF +if { (eval echo configure:885: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_header_stdc=no +fi +rm -fr conftest* +fi + +fi +fi + +echo "$ac_t""$ac_cv_header_stdc" 1>&6 +if test $ac_cv_header_stdc = yes; then + cat >> confdefs.h <<\EOF +#define STDC_HEADERS 1 +EOF + +fi + +echo $ac_n "checking for working const""... $ac_c" 1>&6 +echo "configure:909: checking for working const" >&5 +if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 914 "configure" +#include "confdefs.h" + +int main() { + +/* Ultrix mips cc rejects this. */ +typedef int charset[2]; const charset x; +/* SunOS 4.1.1 cc rejects this. */ +char const *const *ccp; +char **p; +/* NEC SVR4.0.2 mips cc rejects this. */ +struct point {int x, y;}; +static struct point const zero = {0,0}; +/* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in an arm + of an if-expression whose if-part is not a constant expression */ +const char *g = "string"; +ccp = &g + (g ? g-g : 0); +/* HPUX 7.0 cc rejects these. */ +++ccp; +p = (char**) ccp; +ccp = (char const *const *) p; +{ /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; +} +{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; +} +{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; +} +{ /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; +} +{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; +} + +; return 0; } +EOF +if { (eval echo configure:963: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_c_const=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_c_const=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_c_const" 1>&6 +if test $ac_cv_c_const = no; then + cat >> confdefs.h <<\EOF +#define const +EOF + +fi + +echo $ac_n "checking for inline""... $ac_c" 1>&6 +echo "configure:984: checking for inline" >&5 +if eval "test \"`echo '$''{'ac_cv_c_inline'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_cv_c_inline=no +for ac_kw in inline __inline__ __inline; do + cat > conftest.$ac_ext <<EOF +#line 991 "configure" +#include "confdefs.h" + +int main() { +} $ac_kw foo() { +; return 0; } +EOF +if { (eval echo configure:998: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_c_inline=$ac_kw; break +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* +done + +fi + +echo "$ac_t""$ac_cv_c_inline" 1>&6 +case "$ac_cv_c_inline" in + inline | yes) ;; + no) cat >> confdefs.h <<\EOF +#define inline +EOF + ;; + *) cat >> confdefs.h <<EOF +#define inline $ac_cv_c_inline +EOF + ;; +esac + +echo $ac_n "checking for off_t""... $ac_c" 1>&6 +echo "configure:1024: checking for off_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1029 "configure" +#include "confdefs.h" +#include <sys/types.h> +#if STDC_HEADERS +#include <stdlib.h> +#include <stddef.h> +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "off_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_off_t=yes +else + rm -rf conftest* + ac_cv_type_off_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_off_t" 1>&6 +if test $ac_cv_type_off_t = no; then + cat >> confdefs.h <<\EOF +#define off_t long +EOF + +fi + +echo $ac_n "checking for size_t""... $ac_c" 1>&6 +echo "configure:1057: checking for size_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1062 "configure" +#include "confdefs.h" +#include <sys/types.h> +#if STDC_HEADERS +#include <stdlib.h> +#include <stddef.h> +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_size_t=yes +else + rm -rf conftest* + ac_cv_type_size_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_size_t" 1>&6 +if test $ac_cv_type_size_t = no; then + cat >> confdefs.h <<\EOF +#define size_t unsigned +EOF + +fi + +# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works +# for constant arguments. Useless! +echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6 +echo "configure:1092: checking for working alloca.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1097 "configure" +#include "confdefs.h" +#include <alloca.h> +int main() { +char *p = alloca(2 * sizeof(int)); +; return 0; } +EOF +if { (eval echo configure:1104: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_cv_header_alloca_h=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_alloca_h=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_header_alloca_h" 1>&6 +if test $ac_cv_header_alloca_h = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_ALLOCA_H 1 +EOF + +fi + +echo $ac_n "checking for alloca""... $ac_c" 1>&6 +echo "configure:1125: checking for alloca" >&5 +if eval "test \"`echo '$''{'ac_cv_func_alloca_works'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1130 "configure" +#include "confdefs.h" + +#ifdef __GNUC__ +# define alloca __builtin_alloca +#else +# ifdef _MSC_VER +# include <malloc.h> +# define alloca _alloca +# else +# if HAVE_ALLOCA_H +# include <alloca.h> +# else +# ifdef _AIX + #pragma alloca +# else +# ifndef alloca /* predefined by HP cc +Olibcalls */ +char *alloca (); +# endif +# endif +# endif +# endif +#endif + +int main() { +char *p = (char *) alloca(1); +; return 0; } +EOF +if { (eval echo configure:1158: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_cv_func_alloca_works=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_func_alloca_works=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_func_alloca_works" 1>&6 +if test $ac_cv_func_alloca_works = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_ALLOCA 1 +EOF + +fi + +if test $ac_cv_func_alloca_works = no; then + # The SVR3 libPW and SVR4 libucb both contain incompatible functions + # that cause trouble. Some versions do not even contain alloca or + # contain a buggy version. If you still want to use their alloca, + # use ar to extract alloca.o from them instead of compiling alloca.c. + ALLOCA=alloca.${ac_objext} + cat >> confdefs.h <<\EOF +#define C_ALLOCA 1 +EOF + + +echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6 +echo "configure:1190: checking whether alloca needs Cray hooks" >&5 +if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1195 "configure" +#include "confdefs.h" +#if defined(CRAY) && ! defined(CRAY2) +webecray +#else +wenotbecray +#endif + +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "webecray" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_os_cray=yes +else + rm -rf conftest* + ac_cv_os_cray=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_os_cray" 1>&6 +if test $ac_cv_os_cray = yes; then +for ac_func in _getb67 GETB67 getb67; do + echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:1220: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1225 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func(); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1248: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<EOF +#define CRAY_STACKSEG_END $ac_func +EOF + + break +else + echo "$ac_t""no" 1>&6 +fi + +done +fi + +echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6 +echo "configure:1275: checking stack direction for C alloca" >&5 +if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_c_stack_direction=0 +else + cat > conftest.$ac_ext <<EOF +#line 1283 "configure" +#include "confdefs.h" +find_stack_direction () +{ + static char *addr = 0; + auto char dummy; + if (addr == 0) + { + addr = &dummy; + return find_stack_direction (); + } + else + return (&dummy > addr) ? 1 : -1; +} +main () +{ + exit (find_stack_direction() < 0); +} +EOF +if { (eval echo configure:1302: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_c_stack_direction=1 +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_c_stack_direction=-1 +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$ac_cv_c_stack_direction" 1>&6 +cat >> confdefs.h <<EOF +#define STACK_DIRECTION $ac_cv_c_stack_direction +EOF + +fi + +for ac_hdr in unistd.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:1327: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1332 "configure" +#include "confdefs.h" +#include <$ac_hdr> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1337: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <<EOF +#define $ac_tr_hdr 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + +for ac_func in getpagesize +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:1366: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1371 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func(); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1394: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <<EOF +#define $ac_tr_func 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + +echo $ac_n "checking for working mmap""... $ac_c" 1>&6 +echo "configure:1419: checking for working mmap" >&5 +if eval "test \"`echo '$''{'ac_cv_func_mmap_fixed_mapped'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_mmap_fixed_mapped=no +else + cat > conftest.$ac_ext <<EOF +#line 1427 "configure" +#include "confdefs.h" + +/* Thanks to Mike Haertel and Jim Avera for this test. + Here is a matrix of mmap possibilities: + mmap private not fixed + mmap private fixed at somewhere currently unmapped + mmap private fixed at somewhere already mapped + mmap shared not fixed + mmap shared fixed at somewhere currently unmapped + mmap shared fixed at somewhere already mapped + For private mappings, we should verify that changes cannot be read() + back from the file, nor mmap's back from the file at a different + address. (There have been systems where private was not correctly + implemented like the infamous i386 svr4.0, and systems where the + VM page cache was not coherent with the filesystem buffer cache + like early versions of FreeBSD and possibly contemporary NetBSD.) + For shared mappings, we should conversely verify that changes get + propogated back to all the places they're supposed to be. + + Grep wants private fixed already mapped. + The main things grep needs to know about mmap are: + * does it exist and is it safe to write into the mmap'd area + * how to use it (BSD variants) */ +#include <sys/types.h> +#include <fcntl.h> +#include <sys/mman.h> + +/* This mess was copied from the GNU getpagesize.h. */ +#ifndef HAVE_GETPAGESIZE +# ifdef HAVE_UNISTD_H +# include <unistd.h> +# endif + +/* Assume that all systems that can run configure have sys/param.h. */ +# ifndef HAVE_SYS_PARAM_H +# define HAVE_SYS_PARAM_H 1 +# endif + +# ifdef _SC_PAGESIZE +# define getpagesize() sysconf(_SC_PAGESIZE) +# else /* no _SC_PAGESIZE */ +# ifdef HAVE_SYS_PARAM_H +# include <sys/param.h> +# ifdef EXEC_PAGESIZE +# define getpagesize() EXEC_PAGESIZE +# else /* no EXEC_PAGESIZE */ +# ifdef NBPG +# define getpagesize() NBPG * CLSIZE +# ifndef CLSIZE +# define CLSIZE 1 +# endif /* no CLSIZE */ +# else /* no NBPG */ +# ifdef NBPC +# define getpagesize() NBPC +# else /* no NBPC */ +# ifdef PAGESIZE +# define getpagesize() PAGESIZE +# endif /* PAGESIZE */ +# endif /* no NBPC */ +# endif /* no NBPG */ +# endif /* no EXEC_PAGESIZE */ +# else /* no HAVE_SYS_PARAM_H */ +# define getpagesize() 8192 /* punt totally */ +# endif /* no HAVE_SYS_PARAM_H */ +# endif /* no _SC_PAGESIZE */ + +#endif /* no HAVE_GETPAGESIZE */ + +#ifdef __cplusplus +extern "C" { void *malloc(unsigned); } +#else +char *malloc(); +#endif + +int +main() +{ + char *data, *data2, *data3; + int i, pagesize; + int fd; + + pagesize = getpagesize(); + + /* + * First, make a file with some known garbage in it. + */ + data = malloc(pagesize); + if (!data) + exit(1); + for (i = 0; i < pagesize; ++i) + *(data + i) = rand(); + umask(0); + fd = creat("conftestmmap", 0600); + if (fd < 0) + exit(1); + if (write(fd, data, pagesize) != pagesize) + exit(1); + close(fd); + + /* + * Next, try to mmap the file at a fixed address which + * already has something else allocated at it. If we can, + * also make sure that we see the same garbage. + */ + fd = open("conftestmmap", O_RDWR); + if (fd < 0) + exit(1); + data2 = malloc(2 * pagesize); + if (!data2) + exit(1); + data2 += (pagesize - ((int) data2 & (pagesize - 1))) & (pagesize - 1); + if (data2 != mmap(data2, pagesize, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_FIXED, fd, 0L)) + exit(1); + for (i = 0; i < pagesize; ++i) + if (*(data + i) != *(data2 + i)) + exit(1); + + /* + * Finally, make sure that changes to the mapped area + * do not percolate back to the file as seen by read(). + * (This is a bug on some variants of i386 svr4.0.) + */ + for (i = 0; i < pagesize; ++i) + *(data2 + i) = *(data2 + i) + 1; + data3 = malloc(pagesize); + if (!data3) + exit(1); + if (read(fd, data3, pagesize) != pagesize) + exit(1); + for (i = 0; i < pagesize; ++i) + if (*(data + i) != *(data3 + i)) + exit(1); + close(fd); + unlink("conftestmmap"); + exit(0); +} + +EOF +if { (eval echo configure:1567: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_func_mmap_fixed_mapped=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_func_mmap_fixed_mapped=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$ac_cv_func_mmap_fixed_mapped" 1>&6 +if test $ac_cv_func_mmap_fixed_mapped = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_MMAP 1 +EOF + +fi + + +# autoconf.info says this should be called right after AC_INIT. + + +ac_aux_dir= +for ac_dir in `cd $srcdir;pwd`/../.. $srcdir/`cd $srcdir;pwd`/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in `cd $srcdir;pwd`/../.. $srcdir/`cd $srcdir;pwd`/../.." 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + + +# Do some error checking and defaulting for the host and target type. +# The inputs are: +# configure --host=HOST --target=TARGET --build=BUILD NONOPT +# +# The rules are: +# 1. You are not allowed to specify --host, --target, and nonopt at the +# same time. +# 2. Host defaults to nonopt. +# 3. If nonopt is not specified, then host defaults to the current host, +# as determined by config.guess. +# 4. Target and build default to nonopt. +# 5. If nonopt is not specified, then target and build default to host. + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +case $host---$target---$nonopt in +NONE---*---* | *---NONE---* | *---*---NONE) ;; +*) { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } ;; +esac + + +# Make sure we can run config.sub. +if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then : +else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } +fi + +echo $ac_n "checking host system type""... $ac_c" 1>&6 +echo "configure:1640: checking host system type" >&5 + +host_alias=$host +case "$host_alias" in +NONE) + case $nonopt in + NONE) + if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then : + else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; } + fi ;; + *) host_alias=$nonopt ;; + esac ;; +esac + +host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias` +host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$host" 1>&6 + +echo $ac_n "checking target system type""... $ac_c" 1>&6 +echo "configure:1661: checking target system type" >&5 + +target_alias=$target +case "$target_alias" in +NONE) + case $nonopt in + NONE) target_alias=$host_alias ;; + *) target_alias=$nonopt ;; + esac ;; +esac + +target=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $target_alias` +target_cpu=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +target_vendor=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$target" 1>&6 + +echo $ac_n "checking build system type""... $ac_c" 1>&6 +echo "configure:1679: checking build system type" >&5 + +build_alias=$build +case "$build_alias" in +NONE) + case $nonopt in + NONE) build_alias=$host_alias ;; + *) build_alias=$nonopt ;; + esac ;; +esac + +build=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $build_alias` +build_cpu=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +build_vendor=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +build_os=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$build" 1>&6 + +test "$host_alias" != "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + +if test "$program_transform_name" = s,x,x,; then + program_transform_name= +else + # Double any \ or $. echo might interpret backslashes. + cat <<\EOF_SED > conftestsed +s,\\,\\\\,g; s,\$,$$,g +EOF_SED + program_transform_name="`echo $program_transform_name|sed -f conftestsed`" + rm -f conftestsed +fi +test "$program_prefix" != NONE && + program_transform_name="s,^,${program_prefix},; $program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$\$,${program_suffix},; $program_transform_name" + +# sed with no file args requires a program. +test "$program_transform_name" = "" && program_transform_name="s,x,x," + +# Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1723: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1752: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_prog_rejected=no + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test -z "$CC"; then + case "`uname -s`" in + *win32* | *WIN32*) + # Extract the first word of "cl", so it can be a program name with args. +set dummy cl; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1802: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="cl" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + ;; + esac + fi + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:1833: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext <<EOF +#line 1843 "configure" +#include "confdefs.h" +main(){return(0);} +EOF +if { (eval echo configure:1847: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + ac_cv_prog_cc_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cc_cross=no + else + ac_cv_prog_cc_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cc_works=no +fi +rm -fr conftest* + +echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 +if test $ac_cv_prog_cc_works = no; then + { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:1867: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:1872: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <<EOF +#ifdef __GNUC__ + yes; +#endif +EOF +if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1881: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 + +if test $ac_cv_prog_gcc = yes; then + GCC=yes +else + GCC= +fi + +ac_test_CFLAGS="${CFLAGS+set}" +ac_save_CFLAGS="$CFLAGS" +CFLAGS= +echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:1900: checking whether ${CC-cc} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:1943: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + + +# Put a plausible default for CC_FOR_BUILD in Makefile. +if test "x$cross_compiling" = "xno"; then + CC_FOR_BUILD='$(CC)' +else + CC_FOR_BUILD=gcc +fi + + + + +AR=${AR-ar} + +# Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2009: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_RANLIB="ranlib" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":" +fi +fi +RANLIB="$ac_cv_prog_RANLIB" +if test -n "$RANLIB"; then + echo "$ac_t""$RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + +ALL_LINGUAS= + + for ac_hdr in argz.h limits.h locale.h nl_types.h malloc.h string.h \ +unistd.h values.h sys/param.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:2043: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2048 "configure" +#include "confdefs.h" +#include <$ac_hdr> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2053: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <<EOF +#define $ac_tr_hdr 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + + for ac_func in getcwd munmap putenv setenv setlocale strchr strcasecmp \ +__argz_count __argz_stringify __argz_next +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:2083: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2088 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func(); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2111: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <<EOF +#define $ac_tr_func 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + + + if test "${ac_cv_func_stpcpy+set}" != "set"; then + for ac_func in stpcpy +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:2140: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2145 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func(); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2168: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <<EOF +#define $ac_tr_func 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + + fi + if test "${ac_cv_func_stpcpy}" = "yes"; then + cat >> confdefs.h <<\EOF +#define HAVE_STPCPY 1 +EOF + + fi + + if test $ac_cv_header_locale_h = yes; then + echo $ac_n "checking for LC_MESSAGES""... $ac_c" 1>&6 +echo "configure:2202: checking for LC_MESSAGES" >&5 +if eval "test \"`echo '$''{'am_cv_val_LC_MESSAGES'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2207 "configure" +#include "confdefs.h" +#include <locale.h> +int main() { +return LC_MESSAGES +; return 0; } +EOF +if { (eval echo configure:2214: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + am_cv_val_LC_MESSAGES=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + am_cv_val_LC_MESSAGES=no +fi +rm -f conftest* +fi + +echo "$ac_t""$am_cv_val_LC_MESSAGES" 1>&6 + if test $am_cv_val_LC_MESSAGES = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_LC_MESSAGES 1 +EOF + + fi + fi + echo $ac_n "checking whether NLS is requested""... $ac_c" 1>&6 +echo "configure:2235: checking whether NLS is requested" >&5 + # Check whether --enable-nls or --disable-nls was given. +if test "${enable_nls+set}" = set; then + enableval="$enable_nls" + USE_NLS=$enableval +else + USE_NLS=yes +fi + + echo "$ac_t""$USE_NLS" 1>&6 + + + USE_INCLUDED_LIBINTL=no + + if test "$USE_NLS" = "yes"; then + cat >> confdefs.h <<\EOF +#define ENABLE_NLS 1 +EOF + + echo $ac_n "checking whether included gettext is requested""... $ac_c" 1>&6 +echo "configure:2255: checking whether included gettext is requested" >&5 + # Check whether --with-included-gettext or --without-included-gettext was given. +if test "${with_included_gettext+set}" = set; then + withval="$with_included_gettext" + nls_cv_force_use_gnu_gettext=$withval +else + nls_cv_force_use_gnu_gettext=no +fi + + echo "$ac_t""$nls_cv_force_use_gnu_gettext" 1>&6 + + nls_cv_use_gnu_gettext="$nls_cv_force_use_gnu_gettext" + if test "$nls_cv_force_use_gnu_gettext" != "yes"; then + nls_cv_header_intl= + nls_cv_header_libgt= + CATOBJEXT=NONE + + ac_safe=`echo "libintl.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for libintl.h""... $ac_c" 1>&6 +echo "configure:2274: checking for libintl.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2279 "configure" +#include "confdefs.h" +#include <libintl.h> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2284: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + echo $ac_n "checking for gettext in libc""... $ac_c" 1>&6 +echo "configure:2301: checking for gettext in libc" >&5 +if eval "test \"`echo '$''{'gt_cv_func_gettext_libc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2306 "configure" +#include "confdefs.h" +#include <libintl.h> +int main() { +return (int) gettext ("") +; return 0; } +EOF +if { (eval echo configure:2313: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + gt_cv_func_gettext_libc=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + gt_cv_func_gettext_libc=no +fi +rm -f conftest* +fi + +echo "$ac_t""$gt_cv_func_gettext_libc" 1>&6 + + if test "$gt_cv_func_gettext_libc" != "yes"; then + echo $ac_n "checking for bindtextdomain in -lintl""... $ac_c" 1>&6 +echo "configure:2329: checking for bindtextdomain in -lintl" >&5 +ac_lib_var=`echo intl'_'bindtextdomain | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lintl $LIBS" +cat > conftest.$ac_ext <<EOF +#line 2337 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char bindtextdomain(); + +int main() { +bindtextdomain() +; return 0; } +EOF +if { (eval echo configure:2348: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + echo $ac_n "checking for gettext in libintl""... $ac_c" 1>&6 +echo "configure:2364: checking for gettext in libintl" >&5 +if eval "test \"`echo '$''{'gt_cv_func_gettext_libintl'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2369 "configure" +#include "confdefs.h" + +int main() { +return (int) gettext ("") +; return 0; } +EOF +if { (eval echo configure:2376: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + gt_cv_func_gettext_libintl=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + gt_cv_func_gettext_libintl=no +fi +rm -f conftest* +fi + +echo "$ac_t""$gt_cv_func_gettext_libintl" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + fi + + if test "$gt_cv_func_gettext_libc" = "yes" \ + || test "$gt_cv_func_gettext_libintl" = "yes"; then + cat >> confdefs.h <<\EOF +#define HAVE_GETTEXT 1 +EOF + + # Extract the first word of "msgfmt", so it can be a program name with args. +set dummy msgfmt; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2404: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_MSGFMT'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$MSGFMT" in + /*) + ac_cv_path_MSGFMT="$MSGFMT" # Let the user override the test with a path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"; then + ac_cv_path_MSGFMT="$ac_dir/$ac_word" + break + fi + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_MSGFMT" && ac_cv_path_MSGFMT="no" + ;; +esac +fi +MSGFMT="$ac_cv_path_MSGFMT" +if test -n "$MSGFMT"; then + echo "$ac_t""$MSGFMT" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + if test "$MSGFMT" != "no"; then + for ac_func in dcgettext +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:2438: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2443 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func(); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2466: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <<EOF +#define $ac_tr_func 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + + # Extract the first word of "gmsgfmt", so it can be a program name with args. +set dummy gmsgfmt; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2493: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_GMSGFMT'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$GMSGFMT" in + /*) + ac_cv_path_GMSGFMT="$GMSGFMT" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_GMSGFMT="$GMSGFMT" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_GMSGFMT="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_GMSGFMT" && ac_cv_path_GMSGFMT="$MSGFMT" + ;; +esac +fi +GMSGFMT="$ac_cv_path_GMSGFMT" +if test -n "$GMSGFMT"; then + echo "$ac_t""$GMSGFMT" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + # Extract the first word of "xgettext", so it can be a program name with args. +set dummy xgettext; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2528: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_XGETTEXT'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$XGETTEXT" in + /*) + ac_cv_path_XGETTEXT="$XGETTEXT" # Let the user override the test with a path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"; then + ac_cv_path_XGETTEXT="$ac_dir/$ac_word" + break + fi + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_XGETTEXT" && ac_cv_path_XGETTEXT=":" + ;; +esac +fi +XGETTEXT="$ac_cv_path_XGETTEXT" +if test -n "$XGETTEXT"; then + echo "$ac_t""$XGETTEXT" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + cat > conftest.$ac_ext <<EOF +#line 2560 "configure" +#include "confdefs.h" + +int main() { +extern int _nl_msg_cat_cntr; + return _nl_msg_cat_cntr +; return 0; } +EOF +if { (eval echo configure:2568: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + CATOBJEXT=.gmo + DATADIRNAME=share +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CATOBJEXT=.mo + DATADIRNAME=lib +fi +rm -f conftest* + INSTOBJEXT=.mo + fi + fi + +else + echo "$ac_t""no" 1>&6 +fi + + + + if test "$CATOBJEXT" = "NONE"; then + nls_cv_use_gnu_gettext=yes + fi + fi + + if test "$nls_cv_use_gnu_gettext" = "yes"; then + INTLOBJS="\$(GETTOBJS)" + # Extract the first word of "msgfmt", so it can be a program name with args. +set dummy msgfmt; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2600: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_MSGFMT'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$MSGFMT" in + /*) + ac_cv_path_MSGFMT="$MSGFMT" # Let the user override the test with a path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"; then + ac_cv_path_MSGFMT="$ac_dir/$ac_word" + break + fi + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_MSGFMT" && ac_cv_path_MSGFMT="msgfmt" + ;; +esac +fi +MSGFMT="$ac_cv_path_MSGFMT" +if test -n "$MSGFMT"; then + echo "$ac_t""$MSGFMT" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + # Extract the first word of "gmsgfmt", so it can be a program name with args. +set dummy gmsgfmt; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2634: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_GMSGFMT'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$GMSGFMT" in + /*) + ac_cv_path_GMSGFMT="$GMSGFMT" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_GMSGFMT="$GMSGFMT" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_GMSGFMT="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_GMSGFMT" && ac_cv_path_GMSGFMT="$MSGFMT" + ;; +esac +fi +GMSGFMT="$ac_cv_path_GMSGFMT" +if test -n "$GMSGFMT"; then + echo "$ac_t""$GMSGFMT" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + # Extract the first word of "xgettext", so it can be a program name with args. +set dummy xgettext; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2669: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_XGETTEXT'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$XGETTEXT" in + /*) + ac_cv_path_XGETTEXT="$XGETTEXT" # Let the user override the test with a path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"; then + ac_cv_path_XGETTEXT="$ac_dir/$ac_word" + break + fi + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_XGETTEXT" && ac_cv_path_XGETTEXT=":" + ;; +esac +fi +XGETTEXT="$ac_cv_path_XGETTEXT" +if test -n "$XGETTEXT"; then + echo "$ac_t""$XGETTEXT" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + + USE_INCLUDED_LIBINTL=yes + CATOBJEXT=.gmo + INSTOBJEXT=.mo + DATADIRNAME=share + INTLDEPS='$(top_builddir)/../intl/libintl.a' + INTLLIBS=$INTLDEPS + LIBS=`echo $LIBS | sed -e 's/-lintl//'` + nls_cv_header_intl=libintl.h + nls_cv_header_libgt=libgettext.h + fi + + if test "$XGETTEXT" != ":"; then + if $XGETTEXT --omit-header /dev/null 2> /dev/null; then + : ; + else + echo "$ac_t""found xgettext programs is not GNU xgettext; ignore it" 1>&6 + XGETTEXT=":" + fi + fi + + # We need to process the po/ directory. + POSUB=po + else + DATADIRNAME=share + nls_cv_header_intl=libintl.h + nls_cv_header_libgt=libgettext.h + fi + + # If this is used in GNU gettext we have to set USE_NLS to `yes' + # because some of the sources are only built for this goal. + if test "$PACKAGE" = gettext; then + USE_NLS=yes + USE_INCLUDED_LIBINTL=yes + fi + + for lang in $ALL_LINGUAS; do + GMOFILES="$GMOFILES $lang.gmo" + POFILES="$POFILES $lang.po" + done + + + + + + + + + + + + + + + if test "x$CATOBJEXT" != "x"; then + if test "x$ALL_LINGUAS" = "x"; then + LINGUAS= + else + echo $ac_n "checking for catalogs to be installed""... $ac_c" 1>&6 +echo "configure:2759: checking for catalogs to be installed" >&5 + NEW_LINGUAS= + for lang in ${LINGUAS=$ALL_LINGUAS}; do + case "$ALL_LINGUAS" in + *$lang*) NEW_LINGUAS="$NEW_LINGUAS $lang" ;; + esac + done + LINGUAS=$NEW_LINGUAS + echo "$ac_t""$LINGUAS" 1>&6 + fi + + if test -n "$LINGUAS"; then + for lang in $LINGUAS; do CATALOGS="$CATALOGS $lang$CATOBJEXT"; done + fi + fi + + if test $ac_cv_header_locale_h = yes; then + INCLUDE_LOCALE_H="#include <locale.h>" + else + INCLUDE_LOCALE_H="\ +/* The system does not provide the header <locale.h>. Take care yourself. */" + fi + + + if test -f $srcdir/po2tbl.sed.in; then + if test "$CATOBJEXT" = ".cat"; then + ac_safe=`echo "linux/version.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for linux/version.h""... $ac_c" 1>&6 +echo "configure:2787: checking for linux/version.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2792 "configure" +#include "confdefs.h" +#include <linux/version.h> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2797: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + msgformat=linux +else + echo "$ac_t""no" 1>&6 +msgformat=xopen +fi + + + sed -e '/^#/d' $srcdir/$msgformat-msg.sed > po2msg.sed + fi + sed -e '/^#.*[^\\]$/d' -e '/^#$/d' \ + $srcdir/po2tbl.sed.in > po2tbl.sed + fi + + if test "$PACKAGE" = "gettext"; then + GT_NO="#NO#" + GT_YES= + else + GT_NO= + GT_YES="#YES#" + fi + + + + MKINSTALLDIRS="\$(srcdir)/../../mkinstalldirs" + + + l= + + + if test -d $srcdir/po; then + test -d po || mkdir po + if test "x$srcdir" != "x."; then + if test "x`echo $srcdir | sed 's@/.*@@'`" = "x"; then + posrcprefix="$srcdir/" + else + posrcprefix="../$srcdir/" + fi + else + posrcprefix="../" + fi + rm -f po/POTFILES + sed -e "/^#/d" -e "/^\$/d" -e "s,.*, $posrcprefix& \\\\," -e "\$s/\(.*\) \\\\/\1/" \ + < $srcdir/po/POTFILES.in > po/POTFILES + fi + + +# Check for common headers. +# FIXME: Seems to me this can cause problems for i386-windows hosts. +# At one point there were hardcoded AC_DEFINE's if ${host} = i386-*-windows*. +for ac_hdr in stdlib.h string.h strings.h unistd.h time.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:2866: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2871 "configure" +#include "confdefs.h" +#include <$ac_hdr> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2876: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <<EOF +#define $ac_tr_hdr 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + +for ac_hdr in sys/time.h sys/resource.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:2906: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2911 "configure" +#include "confdefs.h" +#include <$ac_hdr> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2916: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <<EOF +#define $ac_tr_hdr 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + +for ac_hdr in fcntl.h fpu_control.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:2946: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2951 "configure" +#include "confdefs.h" +#include <$ac_hdr> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2956: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <<EOF +#define $ac_tr_hdr 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + +for ac_hdr in dlfcn.h errno.h sys/stat.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:2986: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2991 "configure" +#include "confdefs.h" +#include <$ac_hdr> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2996: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <<EOF +#define $ac_tr_hdr 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + +for ac_func in getrusage time sigaction __setfpucw +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:3025: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 3030 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func(); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:3053: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <<EOF +#define $ac_tr_func 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + + +# Check for socket libraries +echo $ac_n "checking for bind in -lsocket""... $ac_c" 1>&6 +echo "configure:3080: checking for bind in -lsocket" >&5 +ac_lib_var=`echo socket'_'bind | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lsocket $LIBS" +cat > conftest.$ac_ext <<EOF +#line 3088 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char bind(); + +int main() { +bind() +; return 0; } +EOF +if { (eval echo configure:3099: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo socket | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <<EOF +#define $ac_tr_lib 1 +EOF + + LIBS="-lsocket $LIBS" + +else + echo "$ac_t""no" 1>&6 +fi + +echo $ac_n "checking for gethostbyname in -lnsl""... $ac_c" 1>&6 +echo "configure:3127: checking for gethostbyname in -lnsl" >&5 +ac_lib_var=`echo nsl'_'gethostbyname | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lnsl $LIBS" +cat > conftest.$ac_ext <<EOF +#line 3135 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char gethostbyname(); + +int main() { +gethostbyname() +; return 0; } +EOF +if { (eval echo configure:3146: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo nsl | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <<EOF +#define $ac_tr_lib 1 +EOF + + LIBS="-lnsl $LIBS" + +else + echo "$ac_t""no" 1>&6 +fi + + +. ${srcdir}/../../bfd/configure.host + + + +USE_MAINTAINER_MODE=no +# Check whether --enable-maintainer-mode or --disable-maintainer-mode was given. +if test "${enable_maintainer_mode+set}" = set; then + enableval="$enable_maintainer_mode" + case "${enableval}" in + yes) MAINT="" USE_MAINTAINER_MODE=yes ;; + no) MAINT="#" ;; + *) { echo "configure: error: "--enable-maintainer-mode does not take a value"" 1>&2; exit 1; }; MAINT="#" ;; +esac +if test x"$silent" != x"yes" && test x"$MAINT" = x""; then + echo "Setting maintainer mode" 6>&1 +fi +else + MAINT="#" +fi + + + +# Check whether --enable-sim-bswap or --disable-sim-bswap was given. +if test "${enable_sim_bswap+set}" = set; then + enableval="$enable_sim_bswap" + case "${enableval}" in + yes) sim_bswap="-DWITH_BSWAP=1 -DUSE_BSWAP=1";; + no) sim_bswap="-DWITH_BSWAP=0";; + *) { echo "configure: error: "--enable-sim-bswap does not take a value"" 1>&2; exit 1; }; sim_bswap="";; +esac +if test x"$silent" != x"yes" && test x"$sim_bswap" != x""; then + echo "Setting bswap flags = $sim_bswap" 6>&1 +fi +else + sim_bswap="" +fi + + + +# Check whether --enable-sim-cflags or --disable-sim-cflags was given. +if test "${enable_sim_cflags+set}" = set; then + enableval="$enable_sim_cflags" + case "${enableval}" in + yes) sim_cflags="-O2 -fomit-frame-pointer";; + trace) { echo "configure: error: "Please use --enable-sim-debug instead."" 1>&2; exit 1; }; sim_cflags="";; + no) sim_cflags="";; + *) sim_cflags=`echo "${enableval}" | sed -e "s/,/ /g"`;; +esac +if test x"$silent" != x"yes" && test x"$sim_cflags" != x""; then + echo "Setting sim cflags = $sim_cflags" 6>&1 +fi +else + sim_cflags="" +fi + + + +# Check whether --enable-sim-debug or --disable-sim-debug was given. +if test "${enable_sim_debug+set}" = set; then + enableval="$enable_sim_debug" + case "${enableval}" in + yes) sim_debug="-DDEBUG=7 -DWITH_DEBUG=7";; + no) sim_debug="-DDEBUG=0 -DWITH_DEBUG=0";; + *) sim_debug="-DDEBUG='(${enableval})' -DWITH_DEBUG='(${enableval})'";; +esac +if test x"$silent" != x"yes" && test x"$sim_debug" != x""; then + echo "Setting sim debug = $sim_debug" 6>&1 +fi +else + sim_debug="" +fi + + + +# Check whether --enable-sim-stdio or --disable-sim-stdio was given. +if test "${enable_sim_stdio+set}" = set; then + enableval="$enable_sim_stdio" + case "${enableval}" in + yes) sim_stdio="-DWITH_STDIO=DO_USE_STDIO";; + no) sim_stdio="-DWITH_STDIO=DONT_USE_STDIO";; + *) { echo "configure: error: "Unknown value $enableval passed to --enable-sim-stdio"" 1>&2; exit 1; }; sim_stdio="";; +esac +if test x"$silent" != x"yes" && test x"$sim_stdio" != x""; then + echo "Setting stdio flags = $sim_stdio" 6>&1 +fi +else + sim_stdio="" +fi + + + +# Check whether --enable-sim-trace or --disable-sim-trace was given. +if test "${enable_sim_trace+set}" = set; then + enableval="$enable_sim_trace" + case "${enableval}" in + yes) sim_trace="-DTRACE=1 -DWITH_TRACE=-1";; + no) sim_trace="-DTRACE=0 -DWITH_TRACE=0";; + [-0-9]*) + sim_trace="-DTRACE='(${enableval})' -DWITH_TRACE='(${enableval})'";; + [a-z]*) + sim_trace="" + for x in `echo "$enableval" | sed -e "s/,/ /g"`; do + if test x"$sim_trace" = x; then + sim_trace="-DWITH_TRACE='(TRACE_$x" + else + sim_trace="${sim_trace}|TRACE_$x" + fi + done + sim_trace="$sim_trace)'" ;; +esac +if test x"$silent" != x"yes" && test x"$sim_trace" != x""; then + echo "Setting sim trace = $sim_trace" 6>&1 +fi +else + sim_trace="" +fi + + + +# Check whether --enable-sim-profile or --disable-sim-profile was given. +if test "${enable_sim_profile+set}" = set; then + enableval="$enable_sim_profile" + case "${enableval}" in + yes) sim_profile="-DPROFILE=1 -DWITH_PROFILE=-1";; + no) sim_profile="-DPROFILE=0 -DWITH_PROFILE=0";; + [-0-9]*) + sim_profile="-DPROFILE='(${enableval})' -DWITH_PROFILE='(${enableval})'";; + [a-z]*) + sim_profile="" + for x in `echo "$enableval" | sed -e "s/,/ /g"`; do + if test x"$sim_profile" = x; then + sim_profile="-DWITH_PROFILE='(PROFILE_$x" + else + sim_profile="${sim_profile}|PROFILE_$x" + fi + done + sim_profile="$sim_profile)'" ;; +esac +if test x"$silent" != x"yes" && test x"$sim_profile" != x""; then + echo "Setting sim profile = $sim_profile" 6>&1 +fi +else + sim_profile="" +fi + + + +echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6 +echo "configure:3322: checking return type of signal handlers" >&5 +if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 3327 "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <signal.h> +#ifdef signal +#undef signal +#endif +#ifdef __cplusplus +extern "C" void (*signal (int, void (*)(int)))(int); +#else +void (*signal ()) (); +#endif + +int main() { +int i; +; return 0; } +EOF +if { (eval echo configure:3344: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_type_signal=void +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_type_signal=int +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_type_signal" 1>&6 +cat >> confdefs.h <<EOF +#define RETSIGTYPE $ac_cv_type_signal +EOF + + + +echo $ac_n "checking for executable suffix""... $ac_c" 1>&6 +echo "configure:3364: checking for executable suffix" >&5 +if eval "test \"`echo '$''{'am_cv_exeext'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$CYGWIN32" = yes; then +am_cv_exeext=.exe +else +cat > am_c_test.c << 'EOF' +int main() { +/* Nothing needed here */ +} +EOF +${CC-cc} -o am_c_test $CFLAGS $CPPFLAGS $LDFLAGS am_c_test.c $LIBS 1>&5 +am_cv_exeext=`ls am_c_test.* | grep -v am_c_test.c | sed -e s/am_c_test//` +rm -f am_c_test* +fi + +test x"${am_cv_exeext}" = x && am_cv_exeext=no +fi +EXEEXT="" +test x"${am_cv_exeext}" != xno && EXEEXT=${am_cv_exeext} +echo "$ac_t""${am_cv_exeext}" 1>&6 + + +sim_link_files= +sim_link_links= + +sim_link_links=tconfig.h +if test -f ${srcdir}/tconfig.in +then + sim_link_files=tconfig.in +else + sim_link_files=../common/tconfig.in +fi + +# targ-vals.def points to the libc macro description file. +case "${target}" in +*-*-*) TARG_VALS_DEF=../common/nltvals.def ;; +esac +sim_link_files="${sim_link_files} ${TARG_VALS_DEF}" +sim_link_links="${sim_link_links} targ-vals.def" + + + +# Put a useful copy of CPP_FOR_TARGET in Makefile. +# This is only used to build the target values header files. These files are +# shipped with distributions so CPP_FOR_TARGET only needs to work in +# developer's trees. This value is borrowed from ../../Makefile.in. +CPP_FOR_TARGET="\` \ + if test -f \$\${rootme}/../../gcc/Makefile ; then \ + if test -f \$\${rootme}/../../\$(TARGET_SUBDIR)/newlib/Makefile ; then \ + echo \$\${rootme}/../../gcc/xgcc -B\$\${rootme}/../../gcc/ -idirafter \$\${rootme}/../../\$(TARGET_SUBDIR)/newlib/targ-include -idirafter \$(srcroot)/newlib/libc/include -nostdinc; \ + else \ + echo \$\${rootme}/../../gcc/xgcc -B\$\${rootme}/../../gcc/; \ + fi; \ + else \ + if test '\$(host_canonical)' = '\$(target_canonical)' ; then \ + echo \$(CC); \ + else \ + t='\$(program_transform_name)'; echo gcc | sed -e 's/x/x/' \$\$t; \ + fi; \ + fi\` -E" + + +# Set TARGET_SUBDIR, needed by CPP_FOR_TARGET. +if test x"${host}" = x"${target}" ; then + TARGET_SUBDIR="." +else + TARGET_SUBDIR=${target_alias} +fi + + +# These aren't all needed yet, but will be eventually. +for ac_hdr in stdlib.h string.h strings.h time.h sys/times.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:3441: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 3446 "configure" +#include "confdefs.h" +#include <$ac_hdr> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:3451: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <<EOF +#define $ac_tr_hdr 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + + +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set) 2>&1 | grep ac_space` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +DEFS=-DHAVE_CONFIG_H + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS <<EOF +#! /bin/sh +# Generated automatically by configure. +# Run this file to recreate the current configuration. +# This directory was configured as follows, +# on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.12.2" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir +ac_given_INSTALL="$INSTALL" + +trap 'rm -fr `echo "Makefile cconfig.h:config.in" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS <<EOF + +# Protect against being on the right side of a sed subst in config.status. +sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g; + s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@sim_environment@%$sim_environment%g +s%@sim_alignment@%$sim_alignment%g +s%@sim_assert@%$sim_assert%g +s%@sim_bitsize@%$sim_bitsize%g +s%@sim_endian@%$sim_endian%g +s%@sim_hostendian@%$sim_hostendian%g +s%@sim_float@%$sim_float%g +s%@sim_scache@%$sim_scache%g +s%@sim_default_model@%$sim_default_model%g +s%@sim_hw_cflags@%$sim_hw_cflags%g +s%@sim_hw_objs@%$sim_hw_objs%g +s%@sim_hw@%$sim_hw%g +s%@sim_inline@%$sim_inline%g +s%@sim_packages@%$sim_packages%g +s%@sim_regparm@%$sim_regparm%g +s%@sim_reserved_bits@%$sim_reserved_bits%g +s%@sim_smp@%$sim_smp%g +s%@sim_stdcall@%$sim_stdcall%g +s%@sim_xor_endian@%$sim_xor_endian%g +s%@build_warnings@%$build_warnings%g +s%@SHELL@%$SHELL%g +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@host@%$host%g +s%@host_alias@%$host_alias%g +s%@host_cpu@%$host_cpu%g +s%@host_vendor@%$host_vendor%g +s%@host_os@%$host_os%g +s%@target@%$target%g +s%@target_alias@%$target_alias%g +s%@target_cpu@%$target_cpu%g +s%@target_vendor@%$target_vendor%g +s%@target_os@%$target_os%g +s%@build@%$build%g +s%@build_alias@%$build_alias%g +s%@build_cpu@%$build_cpu%g +s%@build_vendor@%$build_vendor%g +s%@build_os@%$build_os%g +s%@CC@%$CC%g +s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g +s%@INSTALL_DATA@%$INSTALL_DATA%g +s%@CC_FOR_BUILD@%$CC_FOR_BUILD%g +s%@HDEFINES@%$HDEFINES%g +s%@AR@%$AR%g +s%@RANLIB@%$RANLIB%g +s%@SET_MAKE@%$SET_MAKE%g +s%@CPP@%$CPP%g +s%@ALLOCA@%$ALLOCA%g +s%@USE_NLS@%$USE_NLS%g +s%@MSGFMT@%$MSGFMT%g +s%@GMSGFMT@%$GMSGFMT%g +s%@XGETTEXT@%$XGETTEXT%g +s%@USE_INCLUDED_LIBINTL@%$USE_INCLUDED_LIBINTL%g +s%@CATALOGS@%$CATALOGS%g +s%@CATOBJEXT@%$CATOBJEXT%g +s%@DATADIRNAME@%$DATADIRNAME%g +s%@GMOFILES@%$GMOFILES%g +s%@INSTOBJEXT@%$INSTOBJEXT%g +s%@INTLDEPS@%$INTLDEPS%g +s%@INTLLIBS@%$INTLLIBS%g +s%@INTLOBJS@%$INTLOBJS%g +s%@POFILES@%$POFILES%g +s%@POSUB@%$POSUB%g +s%@INCLUDE_LOCALE_H@%$INCLUDE_LOCALE_H%g +s%@GT_NO@%$GT_NO%g +s%@GT_YES@%$GT_YES%g +s%@MKINSTALLDIRS@%$MKINSTALLDIRS%g +s%@l@%$l%g +s%@MAINT@%$MAINT%g +s%@sim_bswap@%$sim_bswap%g +s%@sim_cflags@%$sim_cflags%g +s%@sim_debug@%$sim_debug%g +s%@sim_stdio@%$sim_stdio%g +s%@sim_trace@%$sim_trace%g +s%@sim_profile@%$sim_profile%g +s%@EXEEXT@%$EXEEXT%g +s%@CPP_FOR_TARGET@%$CPP_FOR_TARGET%g +s%@TARGET_SUBDIR@%$TARGET_SUBDIR%g + +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <<EOF + +CONFIG_FILES=\${CONFIG_FILES-"Makefile"} +EOF +cat >> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + case "$ac_given_INSTALL" in + [/$]*) INSTALL="$ac_given_INSTALL" ;; + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +s%@INSTALL@%$INSTALL%g +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' +ac_dC='\3' +ac_dD='%g' +# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". +ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='\([ ]\)%\1#\2define\3' +ac_uC=' ' +ac_uD='\4%g' +# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_eB='$%\1#\2define\3' +ac_eC=' ' +ac_eD='%g' + +if test "${CONFIG_HEADERS+set}" != set; then +EOF +cat >> $CONFIG_STATUS <<EOF + CONFIG_HEADERS="cconfig.h:config.in" +EOF +cat >> $CONFIG_STATUS <<\EOF +fi +for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + echo creating $ac_file + + rm -f conftest.frag conftest.in conftest.out + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + cat $ac_file_inputs > conftest.in + +EOF + +# Transform confdefs.h into a sed script conftest.vals that substitutes +# the proper values into config.h.in to produce config.h. And first: +# Protect against being on the right side of a sed subst in config.status. +# Protect against being in an unquoted here document in config.status. +rm -f conftest.vals +cat > conftest.hdr <<\EOF +s/[\\&%]/\\&/g +s%[\\$`]%\\&%g +s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp +s%ac_d%ac_u%gp +s%ac_u%ac_e%gp +EOF +sed -n -f conftest.hdr confdefs.h > conftest.vals +rm -f conftest.hdr + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >> conftest.vals <<\EOF +s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% +EOF + +# Break up conftest.vals because some shells have a limit on +# the size of here documents, and old seds have small limits too. + +rm -f conftest.tail +while : +do + ac_lines=`grep -c . conftest.vals` + # grep -c gives empty output for an empty file on some AIX systems. + if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi + # Write a limited-size here document to conftest.frag. + echo ' cat > conftest.frag <<CEOF' >> $CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS + echo 'CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in +' >> $CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail + rm -f conftest.vals + mv conftest.tail conftest.vals +done +rm -f conftest.vals + +cat >> $CONFIG_STATUS <<\EOF + rm -f conftest.frag conftest.h + echo "/* $ac_file. Generated automatically by configure. */" > conftest.h + cat conftest.in >> conftest.h + rm -f conftest.in + if cmp -s $ac_file conftest.h 2>/dev/null; then + echo "$ac_file is unchanged" + rm -f conftest.h + else + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + fi + rm -f $ac_file + mv conftest.h $ac_file + fi +fi; done + +EOF +cat >> $CONFIG_STATUS <<EOF + +EOF +cat >> $CONFIG_STATUS <<\EOF +case x$CONFIG_HEADERS in xcconfig.h:config.in) echo > stamp-h ;; esac +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + diff --git a/sim/common/configure.in b/sim/common/configure.in new file mode 100644 index 0000000..b8ea538 --- /dev/null +++ b/sim/common/configure.in @@ -0,0 +1,40 @@ +dnl Process this file with autoconf to produce a configure script. +AC_PREREQ(2.5)dnl +AC_INIT(Makefile.in) + +# This is intended for use by the target specific directories, and by us. +SIM_AC_COMMON(cconfig.h) + +# Put a useful copy of CPP_FOR_TARGET in Makefile. +# This is only used to build the target values header files. These files are +# shipped with distributions so CPP_FOR_TARGET only needs to work in +# developer's trees. This value is borrowed from ../../Makefile.in. +CPP_FOR_TARGET="\` \ + if test -f \$\${rootme}/../../gcc/Makefile ; then \ + if test -f \$\${rootme}/../../\$(TARGET_SUBDIR)/newlib/Makefile ; then \ + echo \$\${rootme}/../../gcc/xgcc -B\$\${rootme}/../../gcc/ -idirafter \$\${rootme}/../../\$(TARGET_SUBDIR)/newlib/targ-include -idirafter \$(srcroot)/newlib/libc/include -nostdinc; \ + else \ + echo \$\${rootme}/../../gcc/xgcc -B\$\${rootme}/../../gcc/; \ + fi; \ + else \ + if test '\$(host_canonical)' = '\$(target_canonical)' ; then \ + echo \$(CC); \ + else \ + t='\$(program_transform_name)'; echo gcc | sed -e 's/x/x/' \$\$t; \ + fi; \ + fi\` -E" +AC_SUBST(CPP_FOR_TARGET) + +# Set TARGET_SUBDIR, needed by CPP_FOR_TARGET. +if test x"${host}" = x"${target}" ; then + TARGET_SUBDIR="." +else + TARGET_SUBDIR=${target_alias} +fi +AC_SUBST(TARGET_SUBDIR) + +# These aren't all needed yet, but will be eventually. +AC_CHECK_HEADERS(stdlib.h string.h strings.h time.h sys/times.h) + +AC_OUTPUT(Makefile, +[case x$CONFIG_HEADERS in xcconfig.h:config.in) echo > stamp-h ;; esac]) diff --git a/sim/common/dv-core.c b/sim/common/dv-core.c new file mode 100644 index 0000000..1bf4f68 --- /dev/null +++ b/sim/common/dv-core.c @@ -0,0 +1,118 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#include "sim-main.h" +#include "hw-main.h" + +/* DEVICE + + core - root of the device tree + + DESCRIPTION + + The core device, positioned at the root of the device tree appears + to its child devices as a normal device just like every other + device in the tree. + + Internally it is implemented using a core object. Requests to + attach (or detach) address spaces are passed to that core object. + Requests to transfer (DMA) data are reflected back down the device + tree using the core_map data transfer methods. + + PROPERTIES + + None. + + */ + + +static void +dv_core_attach_address_callback (struct hw *me, + int level, + int space, + address_word addr, + address_word nr_bytes, + struct hw *client) +{ + HW_TRACE ((me, "attach - level=%d, space=%d, addr=0x%lx, nr_bytes=%ld, client=%s", + level, space, (unsigned long) addr, (unsigned long) nr_bytes, hw_path (client))); + /* NOTE: At preset the space is assumed to be zero. Perhaphs the + space should be mapped onto something for instance: space0 - + unified memory; space1 - IO memory; ... */ + if (space != 0) + hw_abort (me, "Hey! Unknown space %d", space); + sim_core_attach (hw_system (me), + NULL, /*cpu*/ + level, + access_read_write_exec, + space, addr, + nr_bytes, + 0, /* modulo */ + client, + NULL); +} + + +static unsigned +dv_core_dma_read_buffer_callback (struct hw *me, + void *dest, + int space, + unsigned_word addr, + unsigned nr_bytes) +{ + return sim_core_read_buffer (hw_system (me), + NULL, /*CPU*/ + space, /*???*/ + dest, + addr, + nr_bytes); +} + + +static unsigned +dv_core_dma_write_buffer_callback (struct hw *me, + const void *source, + int space, + unsigned_word addr, + unsigned nr_bytes, + int violate_read_only_section) +{ + return sim_core_write_buffer (hw_system (me), + NULL, /*cpu*/ + space, /*???*/ + source, + addr, + nr_bytes); +} + + +static void +dv_core_finish (struct hw *me) +{ + set_hw_attach_address (me, dv_core_attach_address_callback); + set_hw_dma_write_buffer (me, dv_core_dma_write_buffer_callback); + set_hw_dma_read_buffer (me, dv_core_dma_read_buffer_callback); +} + +const struct hw_descriptor dv_core_descriptor[] = { + { "core", dv_core_finish, }, + { NULL }, +}; diff --git a/sim/common/dv-glue.c b/sim/common/dv-glue.c new file mode 100644 index 0000000..a235531 --- /dev/null +++ b/sim/common/dv-glue.c @@ -0,0 +1,373 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1996,1998 Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#include "hw-main.h" + +#ifdef HAVE_STRING_H +#include <string.h> +#else +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#endif + +/* DEVICE + + + glue - glue to interconnect and test hardware ports + + + DESCRIPTION + + + The glue device provides two functions. Firstly, it provides a + mechanism for inspecting and driving the port network. Secondly, + it provides a set of boolean primitives that can be used to apply + combinatorial operations to the port network. + + Glue devices have a variable number of big endian <<output>> + registers. Each register is target-word sized. The registers can + be read and written. + + Writing to an output register results in an event being driven + (level determined by the value written) on the devices + corresponding output port. + + Reading an <<output>> register returns either the last value + written or the most recently computed value (for that register) as + a result of an event ariving on that port (which ever was computed + last). + + At present the following sub device types are available: + + <<glue>>: In addition to driving its output interrupt port with any + value written to an interrupt input port is stored in the + corresponding <<output>> register. Such input interrupts, however, + are not propogated to an output interrupt port. + + <<glue-and>>: The bit-wise AND of the interrupt inputs is computed + and then both stored in <<output>> register zero and propogated to + output interrupt output port zero. + + + PROPERTIES + + + reg = <address> <size> (required) + + Specify the address (within the parent bus) that this device is to + live. The address must be 2048 * sizeof (word) (8k in a 32bit + simulation) aligned. + + + interrupt-ranges = <int-number> <range> (optional) + + If present, this specifies the number of valid interrupt inputs (up + to the maximum of 2048). By default, <<int-number>> is zero and + range is determined by the <<reg>> size. + + + PORTS + + + int[0..] (input, output) + + Both an input and an output port. + + + EXAMPLES + + + Enable tracing of the device: + + | -t glue-device \ + + + Create source, bitwize-and, and sink glue devices. Since the + device at address <<0x10000>> is of size <<8>> it will have two + output interrupt ports. + + | -o '/iobus@0xf0000000/glue@0x10000/reg 0x10000 8' \ + | -o '/iobus@0xf0000000/glue-and@0x20000/reg 0x20000 4' \ + | -o '/iobus@0xf0000000/glue-and/interrupt-ranges 0 2' \ + | -o '/iobus@0xf0000000/glue@0x30000/reg 0x30000 4' \ + + + Wire the two source interrupts to the AND device: + + | -o '/iobus@0xf0000000/glue@0x10000 > 0 0 /iobus/glue-and' \ + | -o '/iobus@0xf0000000/glue@0x10000 > 1 1 /iobus/glue-and' \ + + + Wire the AND device up to the sink so that the and's output is not + left open. + + | -o '/iobus@0xf0000000/glue-and > 0 0 /iobus/glue@0x30000' \ + + + With the above configuration. The client program is able to + compute a two bit AND. For instance the <<C>> stub below prints 1 + AND 0. + + | unsigned *input = (void*)0xf0010000; + | unsigned *output = (void*)0xf0030000; + | unsigned ans; + | input[0] = htonl(1); + | input[1] = htonl(0); + | ans = ntohl(*output); + | write_string("AND is "); + | write_int(ans); + | write_line(); + + + BUGS + + + A future implementation of this device may support multiple + interrupt ranges. + + Some of the devices listed may not yet be fully implemented. + + Additional devices such as a D flip-flop (DFF), an inverter (INV) + or a latch (LAT) may prove useful. + + */ + + +enum { + max_nr_ports = 2048, +}; + +enum hw_glue_type { + glue_undefined = 0, + glue_io, + glue_and, + glue_nand, + glue_or, + glue_xor, + glue_nor, + glue_not, +}; + +struct hw_glue { + enum hw_glue_type type; + int int_number; + int *input; + int nr_inputs; + unsigned sizeof_input; + /* our output registers */ + int space; + unsigned_word address; + unsigned sizeof_output; + int *output; + int nr_outputs; +}; + + +static hw_io_read_buffer_method hw_glue_io_read_buffer; +static hw_io_write_buffer_method hw_glue_io_write_buffer; +static hw_port_event_method hw_glue_port_event; +const static struct hw_port_descriptor hw_glue_ports[]; + +static void +hw_glue_finish (struct hw *me) +{ + struct hw_glue *glue = HW_ZALLOC (me, struct hw_glue); + + /* establish our own methods */ + set_hw_data (me, glue); + set_hw_io_read_buffer (me, hw_glue_io_read_buffer); + set_hw_io_write_buffer (me, hw_glue_io_write_buffer); + set_hw_ports (me, hw_glue_ports); + set_hw_port_event (me, hw_glue_port_event); + + /* attach to our parent bus */ + do_hw_attach_regs (me); + + /* establish the output registers */ + { + reg_property_spec unit; + int reg_nr; + /* find a relevant reg entry */ + reg_nr = 0; + while (hw_find_reg_array_property (me, "reg", reg_nr, &unit) + && !hw_unit_size_to_attach_size (hw_parent (me), + &unit.size, + &glue->sizeof_output, + me)) + reg_nr++; + /* check out the size */ + if (glue->sizeof_output == 0) + hw_abort (me, "at least one reg property size must be nonzero"); + if (glue->sizeof_output % sizeof (unsigned_word) != 0) + hw_abort (me, "reg property size must be %d aligned", + sizeof (unsigned_word)); + /* and the address */ + hw_unit_address_to_attach_address (hw_parent (me), + &unit.address, + &glue->space, + &glue->address, + me); + if (glue->address % (sizeof (unsigned_word) * max_nr_ports) != 0) + hw_abort (me, "reg property address must be %d aligned", + sizeof (unsigned_word) * max_nr_ports); + glue->nr_outputs = glue->sizeof_output / sizeof (unsigned_word); + glue->output = hw_zalloc (me, glue->sizeof_output); + } + + /* establish the input ports */ + { + const struct hw_property *ranges; + ranges = hw_find_property (me, "interrupt-ranges"); + if (ranges == NULL) + { + glue->int_number = 0; + glue->nr_inputs = glue->nr_outputs; + } + else if (ranges->sizeof_array != sizeof (unsigned_cell) * 2) + { + hw_abort (me, "invalid interrupt-ranges property (incorrect size)"); + } + else + { + const unsigned_cell *int_range = ranges->array; + glue->int_number = BE2H_cell (int_range[0]); + glue->nr_inputs = BE2H_cell (int_range[1]); + } + glue->sizeof_input = glue->nr_inputs * sizeof (unsigned); + glue->input = hw_zalloc (me, glue->sizeof_input); + } + + /* determine our type */ + { + const char *name = hw_name(me); + if (strcmp (name, "glue") == 0) + glue->type = glue_io; + else if (strcmp (name, "glue-and") == 0) + glue->type = glue_and; + else + hw_abort (me, "unimplemented glue type"); + } + + HW_TRACE ((me, "int-number %d, nr_inputs %d, nr_outputs %d", + glue->int_number, glue->nr_inputs, glue->nr_outputs)); +} + +static unsigned +hw_glue_io_read_buffer (struct hw *me, + void *dest, + int space, + unsigned_word addr, + unsigned nr_bytes) +{ + struct hw_glue *glue = (struct hw_glue *) hw_data (me); + int reg = ((addr - glue->address) / sizeof (unsigned_word)) % glue->nr_outputs; + if (nr_bytes != sizeof (unsigned_word) + || (addr % sizeof (unsigned_word)) != 0) + hw_abort (me, "missaligned read access (%d:0x%lx:%d) not supported", + space, (unsigned long)addr, nr_bytes); + *(unsigned_word*)dest = H2BE_4(glue->output[reg]); + HW_TRACE ((me, "read - port %d (0x%lx), level %d", + reg, (unsigned long) addr, glue->output[reg])); + return nr_bytes; +} + + +static unsigned +hw_glue_io_write_buffer (struct hw *me, + const void *source, + int space, + unsigned_word addr, + unsigned nr_bytes) +{ + struct hw_glue *glue = (struct hw_glue *) hw_data (me); + int reg = ((addr - glue->address) / sizeof (unsigned_word)) % max_nr_ports; + if (nr_bytes != sizeof (unsigned_word) + || (addr % sizeof (unsigned_word)) != 0) + hw_abort (me, "missaligned write access (%d:0x%lx:%d) not supported", + space, (unsigned long) addr, nr_bytes); + glue->output[reg] = H2BE_4 (*(unsigned_word*)source); + HW_TRACE ((me, "write - port %d (0x%lx), level %d", + reg, (unsigned long) addr, glue->output[reg])); + hw_port_event (me, reg, glue->output[reg]); + return nr_bytes; +} + +static void +hw_glue_port_event (struct hw *me, + int my_port, + struct hw *source, + int source_port, + int level) +{ + struct hw_glue *glue = (struct hw_glue *) hw_data (me); + int i; + if (my_port < glue->int_number + || my_port >= glue->int_number + glue->nr_inputs) + hw_abort (me, "port %d outside of valid range", my_port); + glue->input[my_port - glue->int_number] = level; + switch (glue->type) + { + case glue_io: + { + int port = my_port % glue->nr_outputs; + glue->output[port] = level; + HW_TRACE ((me, "input - port %d (0x%lx), level %d", + my_port, + (unsigned long) glue->address + port * sizeof (unsigned_word), + level)); + break; + } + case glue_and: + { + glue->output[0] = glue->input[0]; + for (i = 1; i < glue->nr_inputs; i++) + glue->output[0] &= glue->input[i]; + HW_TRACE ((me, "and - port %d, level %d arrived - output %d", + my_port, level, glue->output[0])); + hw_port_event (me, 0, glue->output[0]); + break; + } + default: + { + hw_abort (me, "operator not implemented"); + break; + } + } +} + + +static const struct hw_port_descriptor hw_glue_ports[] = { + { "int", 0, max_nr_ports }, + { NULL } +}; + + +const struct hw_descriptor dv_glue_descriptor[] = { + { "glue", hw_glue_finish, }, + { "glue-and", hw_glue_finish, }, + { "glue-nand", hw_glue_finish, }, + { "glue-or", hw_glue_finish, }, + { "glue-xor", hw_glue_finish, }, + { "glue-nor", hw_glue_finish, }, + { "glue-not", hw_glue_finish, }, + { NULL }, +}; diff --git a/sim/common/dv-pal.c b/sim/common/dv-pal.c new file mode 100644 index 0000000..421bde7 --- /dev/null +++ b/sim/common/dv-pal.c @@ -0,0 +1,605 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1996,1998, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#include "hw-main.h" +#include "sim-io.h" + +/* NOTE: pal is naughty and grubs around looking at things outside of + its immediate domain */ +#include "hw-tree.h" + +#ifdef HAVE_STRING_H +#include <string.h> +#else +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#endif + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif + +/* DEVICE + + + pal - glue logic device containing assorted junk + + + DESCRIPTION + + + Typical hardware dependant hack. This device allows the firmware + to gain access to all the things the firmware needs (but the OS + doesn't). + + The pal contains the following registers: + + |0 reset register (write, 8bit) + |4 processor id register (read, 8bit) + |8 interrupt register (8 - port, 9 - level) (write, 16bit) + |12 processor count register (read, 8bit) + + |16 tty input fifo register (read, 8bit) + |20 tty input status register (read, 8bit) + |24 tty output fifo register (write, 8bit) + |28 tty output status register (read, 8bit) + + |32 countdown register (read/write, 32bit, big-endian) + |36 countdown value register (read, 32bit, big-endian) + |40 timer register (read/write, 32bit, big-endian) + |44 timer value register (read, 32bit, big-endian) + + RESET (write): halts the simulator. The value written to the + register is used as an exit status. + + PROCESSOR ID (read): returns the processor identifier (0 .. N-1) of + the processor performing the read. + + INTERRUPT (write): This register must be written using a two byte + store. The low byte specifies a port and the upper byte specifies + the a level. LEVEL is driven on the specified port. By + convention, the pal's interrupt ports (int0, int1, ...) are wired + up to the corresponding processor's level sensative external + interrupt pin. Eg: A two byte write to address 8 of 0x0102 + (big-endian) will result in processor 2's external interrupt pin + being asserted. + + PROCESSOR COUNT (read): returns the total number of processors + active in the current simulation. + + TTY INPUT FIFO (read): if the TTY input status register indicates a + character is available by being nonzero, returns the next available + character from the pal's tty input port. + + TTY OUTPUT FIFO (write): if the TTY output status register + indicates the output fifo is not full by being nonzero, outputs the + character written to the tty's output port. + + COUNDOWN (read/write): The countdown registers provide a + non-repeating timed interrupt source. Writing a 32 bit big-endian + zero value to this register clears the countdown timer. Writing a + non-zero 32 bit big-endian value to this register sets the + countdown timer to expire in VALUE ticks (ticks is target + dependant). Reading the countdown register returns the last value + writen. + + COUNTDOWN VALUE (read): Reading this 32 bit big-endian register + returns the number of ticks remaining until the countdown timer + expires. + + TIMER (read/write): The timer registers provide a periodic timed + interrupt source. Writing a 32 bit big-endian zero value to this + register clears the periodic timer. Writing a 32 bit non-zero + value to this register sets the periodic timer to triger every + VALUE ticks (ticks is target dependant). Reading the timer + register returns the last value written. + + TIMER VALUE (read): Reading this 32 bit big-endian register returns + the number of ticks until the next periodic interrupt. + + + PROPERTIES + + + reg = <address> <size> (required) + + Specify the address (within the parent bus) that this device is to + be located. + + poll? = <boolean> + + If present and true, indicates that the device should poll its + input. + + + PORTS + + + int[0..NR_PROCESSORS] (output) + + Driven as a result of a write to the interrupt-port / + interrupt-level register pair. + + + countdown + + Driven whenever the countdown counter reaches zero. + + + timer + + Driven whenever the timer counter reaches zero. + + + BUGS + + + At present the common simulator framework does not support input + polling. + + */ + + +enum { + hw_pal_reset_register = 0x0, + hw_pal_cpu_nr_register = 0x4, + hw_pal_int_register = 0x8, + hw_pal_nr_cpu_register = 0xa, + hw_pal_read_fifo = 0x10, + hw_pal_read_status = 0x14, + hw_pal_write_fifo = 0x18, + hw_pal_write_status = 0x1a, + hw_pal_countdown = 0x20, + hw_pal_countdown_value = 0x24, + hw_pal_timer = 0x28, + hw_pal_timer_value = 0x2c, + hw_pal_address_mask = 0x3f, +}; + + +typedef struct _hw_pal_console_buffer { + char buffer; + int status; +} hw_pal_console_buffer; + +typedef struct _hw_pal_counter { + struct hw_event *handler; + signed64 start; + unsigned32 delta; + int periodic_p; +} hw_pal_counter; + + +typedef struct _hw_pal_device { + hw_pal_console_buffer input; + hw_pal_console_buffer output; + hw_pal_counter countdown; + hw_pal_counter timer; + struct hw *disk; + do_hw_poll_read_method *reader; +} hw_pal_device; + +enum { + COUNTDOWN_PORT, + TIMER_PORT, + INT_PORT, +}; + +static const struct hw_port_descriptor hw_pal_ports[] = { + { "countdown", COUNTDOWN_PORT, 0, output_port, }, + { "timer", TIMER_PORT, 0, output_port, }, + { "int", INT_PORT, MAX_NR_PROCESSORS, output_port, }, + { NULL } +}; + + +/* countdown and simple timer */ + +static void +do_counter_event (struct hw *me, + void *data) +{ + hw_pal_counter *counter = (hw_pal_counter *) data; + if (counter->periodic_p) + { + HW_TRACE ((me, "timer expired")); + counter->start = hw_event_queue_time (me); + hw_port_event (me, TIMER_PORT, 1); + hw_event_queue_schedule (me, counter->delta, do_counter_event, counter); + } + else + { + HW_TRACE ((me, "countdown expired")); + counter->delta = 0; + hw_port_event (me, COUNTDOWN_PORT, 1); + } +} + +static void +do_counter_read (struct hw *me, + hw_pal_device *pal, + const char *reg, + hw_pal_counter *counter, + unsigned32 *word, + unsigned nr_bytes) +{ + unsigned32 val; + if (nr_bytes != 4) + hw_abort (me, "%s - bad read size must be 4 bytes", reg); + val = counter->delta; + HW_TRACE ((me, "read - %s %ld", reg, (long) val)); + *word = H2BE_4 (val); +} + +static void +do_counter_value (struct hw *me, + hw_pal_device *pal, + const char *reg, + hw_pal_counter *counter, + unsigned32 *word, + unsigned nr_bytes) +{ + unsigned32 val; + if (nr_bytes != 4) + hw_abort (me, "%s - bad read size must be 4 bytes", reg); + if (counter->delta != 0) + val = (counter->start + counter->delta + - hw_event_queue_time (me)); + else + val = 0; + HW_TRACE ((me, "read - %s %ld", reg, (long) val)); + *word = H2BE_4 (val); +} + +static void +do_counter_write (struct hw *me, + hw_pal_device *pal, + const char *reg, + hw_pal_counter *counter, + const unsigned32 *word, + unsigned nr_bytes) +{ + if (nr_bytes != 4) + hw_abort (me, "%s - bad write size must be 4 bytes", reg); + if (counter->handler != NULL) + { + hw_event_queue_deschedule (me, counter->handler); + counter->handler = NULL; + } + counter->delta = BE2H_4 (*word); + counter->start = hw_event_queue_time (me); + HW_TRACE ((me, "write - %s %ld", reg, (long) counter->delta)); + if (counter->delta > 0) + hw_event_queue_schedule (me, counter->delta, do_counter_event, counter); +} + + + + +/* check the console for an available character */ +static void +scan_hw_pal (struct hw *me) +{ + hw_pal_device *hw_pal = (hw_pal_device *)hw_data (me); + char c; + int count; + count = do_hw_poll_read (me, hw_pal->reader, 0/*STDIN*/, &c, sizeof(c)); + switch (count) + { + case HW_IO_NOT_READY: + case HW_IO_EOF: + hw_pal->input.buffer = 0; + hw_pal->input.status = 0; + break; + default: + hw_pal->input.buffer = c; + hw_pal->input.status = 1; + } +} + +/* write the character to the hw_pal */ + +static void +write_hw_pal (struct hw *me, + char val) +{ + hw_pal_device *hw_pal = (hw_pal_device *) hw_data (me); + sim_io_write_stdout (hw_system (me), &val, 1); + hw_pal->output.buffer = val; + hw_pal->output.status = 1; +} + + +/* Reads/writes */ + +static unsigned +hw_pal_io_read_buffer (struct hw *me, + void *dest, + int space, + unsigned_word addr, + unsigned nr_bytes) +{ + hw_pal_device *hw_pal = (hw_pal_device *) hw_data (me); + unsigned_1 *byte = (unsigned_1 *) dest; + memset (dest, 0, nr_bytes); + switch (addr & hw_pal_address_mask) + { + + case hw_pal_cpu_nr_register: +#ifdef CPU_INDEX + *byte = CPU_INDEX (hw_system_cpu (me)); +#else + *byte = 0; +#endif + HW_TRACE ((me, "read - cpu-nr %d\n", *byte)); + break; + + case hw_pal_nr_cpu_register: + if (hw_tree_find_property (me, "/openprom/options/smp") == NULL) + { + *byte = 1; + HW_TRACE ((me, "read - nr-cpu %d (not defined)\n", *byte)); + } + else + { + *byte = hw_tree_find_integer_property (me, "/openprom/options/smp"); + HW_TRACE ((me, "read - nr-cpu %d\n", *byte)); + } + break; + + case hw_pal_read_fifo: + *byte = hw_pal->input.buffer; + HW_TRACE ((me, "read - input-fifo %d\n", *byte)); + break; + + case hw_pal_read_status: + scan_hw_pal (me); + *byte = hw_pal->input.status; + HW_TRACE ((me, "read - input-status %d\n", *byte)); + break; + + case hw_pal_write_fifo: + *byte = hw_pal->output.buffer; + HW_TRACE ((me, "read - output-fifo %d\n", *byte)); + break; + + case hw_pal_write_status: + *byte = hw_pal->output.status; + HW_TRACE ((me, "read - output-status %d\n", *byte)); + break; + + case hw_pal_countdown: + do_counter_read (me, hw_pal, "countdown", + &hw_pal->countdown, dest, nr_bytes); + break; + + case hw_pal_countdown_value: + do_counter_value (me, hw_pal, "countdown-value", + &hw_pal->countdown, dest, nr_bytes); + break; + + case hw_pal_timer: + do_counter_read (me, hw_pal, "timer", + &hw_pal->timer, dest, nr_bytes); + break; + + case hw_pal_timer_value: + do_counter_value (me, hw_pal, "timer-value", + &hw_pal->timer, dest, nr_bytes); + break; + + default: + HW_TRACE ((me, "read - ???\n")); + break; + + } + return nr_bytes; +} + + +static unsigned +hw_pal_io_write_buffer (struct hw *me, + const void *source, + int space, + unsigned_word addr, + unsigned nr_bytes) +{ + hw_pal_device *hw_pal = (hw_pal_device*) hw_data (me); + unsigned_1 *byte = (unsigned_1 *) source; + + switch (addr & hw_pal_address_mask) + { + + case hw_pal_reset_register: + hw_halt (me, sim_exited, byte[0]); + break; + + case hw_pal_int_register: + hw_port_event (me, + INT_PORT + byte[0], /*port*/ + (nr_bytes > 1 ? byte[1] : 0)); /* val */ + break; + + case hw_pal_read_fifo: + hw_pal->input.buffer = byte[0]; + HW_TRACE ((me, "write - input-fifo %d\n", byte[0])); + break; + + case hw_pal_read_status: + hw_pal->input.status = byte[0]; + HW_TRACE ((me, "write - input-status %d\n", byte[0])); + break; + + case hw_pal_write_fifo: + write_hw_pal (me, byte[0]); + HW_TRACE ((me, "write - output-fifo %d\n", byte[0])); + break; + + case hw_pal_write_status: + hw_pal->output.status = byte[0]; + HW_TRACE ((me, "write - output-status %d\n", byte[0])); + break; + + case hw_pal_countdown: + do_counter_write (me, hw_pal, "countdown", + &hw_pal->countdown, source, nr_bytes); + break; + + case hw_pal_timer: + do_counter_write (me, hw_pal, "timer", + &hw_pal->timer, source, nr_bytes); + break; + + } + return nr_bytes; +} + + +/* instances of the hw_pal struct hw */ + +#if NOT_YET +static void +hw_pal_instance_delete_callback(hw_instance *instance) +{ + /* nothing to delete, the hw_pal is attached to the struct hw */ + return; +} +#endif + +#if NOT_YET +static int +hw_pal_instance_read_callback (hw_instance *instance, + void *buf, + unsigned_word len) +{ + DITRACE (pal, ("read - %s (%ld)", (const char*) buf, (long int) len)); + return sim_io_read_stdin (buf, len); +} +#endif + +#if NOT_YET +static int +hw_pal_instance_write_callback (hw_instance *instance, + const void *buf, + unsigned_word len) +{ + int i; + const char *chp = buf; + hw_pal_device *hw_pal = hw_instance_data (instance); + DITRACE (pal, ("write - %s (%ld)", (const char*) buf, (long int) len)); + for (i = 0; i < len; i++) + write_hw_pal (hw_pal, chp[i]); + sim_io_flush_stdoutput (); + return i; +} +#endif + +#if NOT_YET +static const hw_instance_callbacks hw_pal_instance_callbacks = { + hw_pal_instance_delete_callback, + hw_pal_instance_read_callback, + hw_pal_instance_write_callback, +}; +#endif + +#if 0 +static hw_instance * +hw_pal_create_instance (struct hw *me, + const char *path, + const char *args) +{ + return hw_create_instance_from (me, NULL, + hw_data (me), + path, args, + &hw_pal_instance_callbacks); +} +#endif + + +static void +hw_pal_attach_address (struct hw *me, + int level, + int space, + address_word addr, + address_word nr_bytes, + struct hw *client) +{ + hw_pal_device *pal = (hw_pal_device*) hw_data (me); + pal->disk = client; +} + + +#if 0 +static hw_callbacks const hw_pal_callbacks = { + { generic_hw_init_address, }, + { hw_pal_attach_address, }, /* address */ + { hw_pal_io_read_buffer_callback, + hw_pal_io_write_buffer_callback, }, + { NULL, }, /* DMA */ + { NULL, NULL, hw_pal_interrupt_ports }, /* interrupt */ + { generic_hw_unit_decode, + generic_hw_unit_encode, + generic_hw_address_to_attach_address, + generic_hw_size_to_attach_size }, + hw_pal_create_instance, +}; +#endif + + +static void +hw_pal_finish (struct hw *hw) +{ + /* create the descriptor */ + hw_pal_device *hw_pal = HW_ZALLOC (hw, hw_pal_device); + hw_pal->output.status = 1; + hw_pal->output.buffer = '\0'; + hw_pal->input.status = 0; + hw_pal->input.buffer = '\0'; + set_hw_data (hw, hw_pal); + set_hw_attach_address (hw, hw_pal_attach_address); + set_hw_io_read_buffer (hw, hw_pal_io_read_buffer); + set_hw_io_write_buffer (hw, hw_pal_io_write_buffer); + set_hw_ports (hw, hw_pal_ports); + /* attach ourselves */ + do_hw_attach_regs (hw); + /* If so configured, enable polled input */ + if (hw_find_property (hw, "poll?") != NULL + && hw_find_boolean_property (hw, "poll?")) + { + hw_pal->reader = sim_io_poll_read; + } + else + { + hw_pal->reader = sim_io_read; + } + /* tag the periodic timer */ + hw_pal->timer.periodic_p = 1; +} + + +const struct hw_descriptor dv_pal_descriptor[] = { + { "pal", hw_pal_finish, }, + { NULL }, +}; diff --git a/sim/common/dv-sockser.c b/sim/common/dv-sockser.c new file mode 100644 index 0000000..c95288c --- /dev/null +++ b/sim/common/dv-sockser.c @@ -0,0 +1,386 @@ +/* Serial port emulation using sockets. + Copyright (C) 1998 Free Software Foundation, Inc. + Contributed by Cygnus Solutions. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* FIXME: will obviously need to evolve. + - connectionless sockets might be more appropriate. */ + +#include "sim-main.h" + +#ifdef HAVE_STRING_H +#include <string.h> +#else +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#endif +#include <signal.h> +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include <errno.h> +#include <sys/types.h> +#include <sys/time.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <sys/socket.h> + +#ifndef __CYGWIN32__ +#include <netinet/tcp.h> +#endif + +#include "sim-assert.h" +#include "sim-options.h" + +#include "dv-sockser.h" + +/* Get definitions for both O_NONBLOCK and O_NDELAY. */ + +#ifndef O_NDELAY +#ifdef FNDELAY +#define O_NDELAY FNDELAY +#else /* ! defined (FNDELAY) */ +#define O_NDELAY 0 +#endif /* ! defined (FNDELAY) */ +#endif /* ! defined (O_NDELAY) */ + +#ifndef O_NONBLOCK +#ifdef FNBLOCK +#define O_NONBLOCK FNBLOCK +#else /* ! defined (FNBLOCK) */ +#define O_NONBLOCK 0 +#endif /* ! defined (FNBLOCK) */ +#endif /* ! defined (O_NONBLOCK) */ + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + +/* Compromise between eating cpu and properly busy-waiting. + One could have an option to set this but for now that seems + like featuritis. */ +#define DEFAULT_TIMEOUT 1000 /* microseconds */ + +/* FIXME: These should allocated at run time and kept with other simulator + state (duh...). Later. */ +const char * sockser_addr = NULL; +/* Timeout in microseconds during status flag computation. + Setting this to zero achieves proper busy wait semantics but eats cpu. */ +static unsigned int sockser_timeout = DEFAULT_TIMEOUT; +static int sockser_listen_fd = -1; +static int sockser_fd = -1; + +/* FIXME: use tree properties when they're ready. */ + +typedef enum { + OPTION_ADDR = OPTION_START +} SOCKSER_OPTIONS; + +static DECLARE_OPTION_HANDLER (sockser_option_handler); + +static const OPTION sockser_options[] = +{ + { { "sockser-addr", required_argument, NULL, OPTION_ADDR }, + '\0', "SOCKET ADDRESS", "Set serial emulation socket address", + sockser_option_handler }, + { { NULL, no_argument, NULL, 0 }, '\0', NULL, NULL, NULL } +}; + +static SIM_RC +sockser_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt, + char *arg, int is_command) +{ + switch (opt) + { + case OPTION_ADDR : + sockser_addr = arg; + break; + } + + return SIM_RC_OK; +} + +static SIM_RC +dv_sockser_init (SIM_DESC sd) +{ + struct hostent *hostent; + struct sockaddr_in sockaddr; + char hostname[100]; + const char *port_str; + int tmp,port; + + if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT + || sockser_addr == NULL) + return SIM_RC_OK; + + if (*sockser_addr == '/') + { + /* support for these can come later */ + sim_io_eprintf (sd, "sockser init: unix domain sockets not supported: `%s'\n", + sockser_addr); + return SIM_RC_FAIL; + } + + port_str = strchr (sockser_addr, ':'); + if (!port_str) + { + sim_io_eprintf (sd, "sockser init: missing port number: `%s'\n", + sockser_addr); + return SIM_RC_FAIL; + } + tmp = MIN (port_str - sockser_addr, (int) sizeof hostname - 1); + strncpy (hostname, sockser_addr, tmp); + hostname[tmp] = '\000'; + port = atoi (port_str + 1); + + hostent = gethostbyname (hostname); + if (! hostent) + { + sim_io_eprintf (sd, "sockser init: unknown host: %s\n", + hostname); + return SIM_RC_FAIL; + } + + sockser_listen_fd = socket (PF_INET, SOCK_STREAM, 0); + if (sockser_listen_fd < 0) + { + sim_io_eprintf (sd, "sockser init: unable to get socket: %s\n", + strerror (errno)); + return SIM_RC_FAIL; + } + + sockaddr.sin_family = PF_INET; + sockaddr.sin_port = htons(port); + memcpy (&sockaddr.sin_addr.s_addr, hostent->h_addr, + sizeof (struct in_addr)); + + tmp = 1; + if (setsockopt (sockser_listen_fd, SOL_SOCKET, SO_REUSEADDR, (void*)& tmp, sizeof(tmp)) < 0) + { + sim_io_eprintf (sd, "sockser init: unable to set SO_REUSEADDR: %s\n", + strerror (errno)); + } + if (bind (sockser_listen_fd, (struct sockaddr *) &sockaddr, sizeof (sockaddr)) < 0) + { + sim_io_eprintf (sd, "sockser init: unable to bind socket address: %s\n", + strerror (errno)); + close (sockser_listen_fd); + sockser_listen_fd = -1; + return SIM_RC_FAIL; + } + if (listen (sockser_listen_fd, 1) < 0) + { + sim_io_eprintf (sd, "sockser init: unable to set up listener: %s\n", + strerror (errno)); + close (sockser_listen_fd); + sockser_listen_fd = -1; + return SIM_RC_OK; + } + + /* Handle writes to missing client -> SIGPIPE. + ??? Need a central signal management module. */ + { + RETSIGTYPE (*orig) (); + orig = signal (SIGPIPE, SIG_IGN); + /* If a handler is already set up, don't mess with it. */ + if (orig != SIG_DFL && orig != SIG_IGN) + signal (SIGPIPE, orig); + } + + return SIM_RC_OK; +} + +static void +dv_sockser_uninstall (SIM_DESC sd) +{ + if (sockser_listen_fd != -1) + { + close (sockser_listen_fd); + sockser_listen_fd = -1; + } + if (sockser_fd != -1) + { + close (sockser_fd); + sockser_fd = -1; + } +} + +SIM_RC +dv_sockser_install (SIM_DESC sd) +{ + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + if (sim_add_option_table (sd, NULL, sockser_options) != SIM_RC_OK) + return SIM_RC_FAIL; + sim_module_add_init_fn (sd, dv_sockser_init); + sim_module_add_uninstall_fn (sd, dv_sockser_uninstall); + return SIM_RC_OK; +} + +static int +connected_p (SIM_DESC sd) +{ + int numfds,flags; + struct timeval tv; + fd_set readfds; + struct sockaddr sockaddr; + int addrlen; + + if (sockser_listen_fd == -1) + return 0; + + if (sockser_fd >= 0) + { + /* FIXME: has client gone away? */ + return 1; + } + + /* Not connected. Connect with a client if there is one. */ + + FD_ZERO (&readfds); + FD_SET (sockser_listen_fd, &readfds); + + /* ??? One can certainly argue this should be done differently, + but for now this is sufficient. */ + tv.tv_sec = 0; + tv.tv_usec = sockser_timeout; + + numfds = select (sockser_listen_fd + 1, &readfds, 0, 0, &tv); + if (numfds <= 0) + return 0; + + sockser_fd = accept (sockser_listen_fd, &sockaddr, &addrlen); + if (sockser_fd < 0) + return 0; + + /* Set non-blocking i/o. */ + flags = fcntl (sockser_fd, F_GETFL); + flags |= O_NONBLOCK | O_NDELAY; + if (fcntl (sockser_fd, F_SETFL, flags) == -1) + { + sim_io_eprintf (sd, "unable to set nonblocking i/o"); + close (sockser_fd); + sockser_fd = -1; + return 0; + } + return 1; +} + +int +dv_sockser_status (SIM_DESC sd) +{ + int numrfds,numwfds,status; + struct timeval tv; + fd_set readfds,writefds; + + /* status to return if the socket isn't set up, or select fails */ + status = DV_SOCKSER_INPUT_EMPTY | DV_SOCKSER_OUTPUT_EMPTY; + + if (! connected_p (sd)) + return status; + + FD_ZERO (&readfds); + FD_ZERO (&writefds); + FD_SET (sockser_fd, &readfds); + FD_SET (sockser_fd, &writefds); + + /* ??? One can certainly argue this should be done differently, + but for now this is sufficient. The read is done separately + from the write to enforce the delay which we heuristically set to + once every SOCKSER_TIMEOUT_FREQ tries. + No, this isn't great for SMP situations, blah blah blah. */ + + { + static int n; +#define SOCKSER_TIMEOUT_FREQ 42 + if (++n == SOCKSER_TIMEOUT_FREQ) + n = 0; + if (n == 0) + { + tv.tv_sec = 0; + tv.tv_usec = sockser_timeout; + numrfds = select (sockser_fd + 1, &readfds, 0, 0, &tv); + tv.tv_sec = 0; + tv.tv_usec = 0; + numwfds = select (sockser_fd + 1, 0, &writefds, 0, &tv); + } + else /* do both selects at once */ + { + tv.tv_sec = 0; + tv.tv_usec = 0; + numrfds = numwfds = select (sockser_fd + 1, &readfds, &writefds, 0, &tv); + } + } + + status = 0; + if (numrfds <= 0 || ! FD_ISSET (sockser_fd, &readfds)) + status |= DV_SOCKSER_INPUT_EMPTY; + if (numwfds <= 0 || FD_ISSET (sockser_fd, &writefds)) + status |= DV_SOCKSER_OUTPUT_EMPTY; + return status; +} + +int +dv_sockser_write (SIM_DESC sd, unsigned char c) +{ + int n; + + if (! connected_p (sd)) + return -1; + n = write (sockser_fd, &c, 1); + if (n == -1) + { + if (errno == EPIPE) + { + close (sockser_fd); + sockser_fd = -1; + } + return -1; + } + if (n != 1) + return -1; + return 1; +} + +int +dv_sockser_read (SIM_DESC sd) +{ + unsigned char c; + int n; + + if (! connected_p (sd)) + return -1; + n = read (sockser_fd, &c, 1); + /* ??? We're assuming semantics that may not be correct for all hosts. + In particular (from cvssrc/src/server.c), this assumes that we are using + BSD or POSIX nonblocking I/O. System V nonblocking I/O returns zero if + there is nothing to read. */ + if (n == 0) + { + close (sockser_fd); + sockser_fd = -1; + return -1; + } + if (n != 1) + return -1; + return c; +} diff --git a/sim/common/dv-sockser.h b/sim/common/dv-sockser.h new file mode 100644 index 0000000..ef0a7a9 --- /dev/null +++ b/sim/common/dv-sockser.h @@ -0,0 +1,32 @@ +/* Serial port emulation via sockets. + Copyright (C) 1998, Free Software Foundation, Inc. + +This file is part of the GNU simulators. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef DV_SOCKSER_H +#define DV_SOCKSER_H + +/* bits in result of dev_sockser_status */ +#define DV_SOCKSER_INPUT_EMPTY 1 +#define DV_SOCKSER_OUTPUT_EMPTY 2 + +/* FIXME: later add a device ptr arg */ +extern int dv_sockser_status (SIM_DESC); +int dv_sockser_write (SIM_DESC, unsigned char); +int dv_sockser_read (SIM_DESC); + +#endif /* DV_SOCKSER_H */ diff --git a/sim/common/gdbinit.in b/sim/common/gdbinit.in new file mode 100644 index 0000000..ddda344 --- /dev/null +++ b/sim/common/gdbinit.in @@ -0,0 +1,10 @@ +break sim_io_error + +define dump +set sim_debug_dump () +end + +document dump +Dump cpu and simulator registers for debugging the simulator. +Requires the simulator to provide function sim_debug_dump. +end diff --git a/sim/common/genmloop.sh b/sim/common/genmloop.sh new file mode 100644 index 0000000..865fe72 --- /dev/null +++ b/sim/common/genmloop.sh @@ -0,0 +1,1122 @@ +# Generate the main loop of the simulator. +# Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc. +# Contributed by Cygnus Support. +# +# This file is part of the GNU simulators. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# This file creates two files: eng.hin and mloop.cin. +# eng.hin defines a few macros that specify what kind of engine was selected +# based on the arguments to this script. +# mloop.cin contains the engine. +# +# ??? Rename mloop.c to eng.c? +# ??? Rename mainloop.in to engine.in? +# ??? Add options to specify output file names? +# ??? Rename this file to genengine.sh? +# +# Syntax: genmloop.sh [options] +# +# Options: +# +# -mono | -multi +# - specify single cpu or multiple cpus (number specifyable at runtime), +# maximum number is a configuration parameter +# - -multi wip +# +# -fast: include support for fast execution in addition to full featured mode +# +# Full featured mode is for tracing, profiling, etc. and is always +# provided. Fast mode contains no frills, except speed. +# A target need only provide a "full" version of one of +# simple,scache,pbb. If the target wants it can also provide a fast +# version of same. It can't provide more than this. +# ??? Later add ability to have another set of full/fast semantics +# for use in with-devices/with-smp situations (pbb can be inappropriate +# here). +# +# -full-switch: same as -fast but for full featured version of -switch +# Only needed if -fast present. +# +# -simple: simple execution engine (the default) +# +# This engine fetches and executes one instruction at a time. +# Field extraction is done in the semantic routines. +# +# ??? There are two possible flavours of -simple. One that extracts +# fields in the semantic routine (which is what is implemented here), +# and one that stores the extracted fields in ARGBUF before calling the +# semantic routine. The latter is essentially the -scache case with a +# cache size of one (and the scache lookup code removed). There are no +# current uses of this and it's not clear when doing this would be a win. +# More complicated ISA's that want to use -simple may find this a win. +# Should this ever be desirable, implement a new engine style here and +# call it -extract (or some such). It's believed that the CGEN-generated +# code for the -scache case would be usable here, so no new code +# generation option would be needed for CGEN. +# +# -scache: use the scache to speed things up (not always a win) +# +# This engine caches the extracted instruction before executing it. +# When executing instructions they are first looked up in the scache. +# +# -pbb: same as -scache but extract a (pseudo-) basic block at a time +# +# This engine is basically identical to the scache version except that +# extraction is done a pseudo-basic-block at a time and the address of +# the scache entry of a branch target is recorded as well. +# Additional speedups are then possible by defering Ctrl-C checking +# to the end of basic blocks and by threading the insns together. +# We call them pseudo-basic-block's instead of just basic-blocks because +# they're not necessarily basic-blocks, though normally are. +# +# -parallel-read: support parallel execution with read-before-exec support. +# -parallel-write: support parallel execution with write-after-exec support. +# +# One of these options is specified in addition to -simple, -scache, +# -pbb. Note that while the code can determine if the cpu supports +# parallel execution with HAVE_PARALLEL_INSNS [and thus this option is +# technically unnecessary], having this option cuts down on the clutter +# in the result. +# +# -switch file: specify file containing semantics implemented as a switch() +# +# -cpu <cpu-family> +# +# Specify the cpu family name. +# +# -infile <input-file> +# +# Specify the mainloop.in input file. +# +# Only one of -scache/-pbb may be selected. +# -simple is the default. +# +#### +# +# TODO +# - build mainloop.in from .cpu file + +type=mono +#scache= +#fast= +#full_switch= +#pbb= +parallel=no +switch= +cpu="unknown" +infile="" + +while test $# -gt 0 +do + case $1 in + -mono) type=mono ;; + -multi) type=multi ;; + -no-fast) ;; + -fast) fast=yes ;; + -full-switch) full_switch=yes ;; + -simple) ;; + -scache) scache=yes ;; + -pbb) pbb=yes ;; + -no-parallel) ;; + -parallel-read) parallel=read ;; + -parallel-write) parallel=write ;; + -switch) shift ; switch=$1 ;; + -cpu) shift ; cpu=$1 ;; + -infile) shift ; infile=$1 ;; + *) echo "unknown option: $1" >&2 ; exit 1 ;; + esac + shift +done + +# Argument validation. + +if [ x$scache = xyes -a x$pbb = xyes ] ; then + echo "only one of -scache and -pbb may be selected" >&2 + exit 1 +fi + +if [ "x$cpu" = xunknown ] ; then + echo "cpu family not specified" >&2 + exit 1 +fi + +if [ "x$infile" = x ] ; then + echo "mainloop.in not specified" >&2 + exit 1 +fi + +lowercase='abcdefghijklmnopqrstuvwxyz' +uppercase='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +CPU=`echo ${cpu} | tr "${lowercase}" "${uppercase}"` + +########################################################################## + +rm -f eng.hin +exec 1>eng.hin + +echo "/* engine configuration for ${cpu} */" +echo "" + +echo "/* WITH_FAST: non-zero if a fast version of the engine is available" +echo " in addition to the full-featured version. */" +if [ x$fast = xyes ] ; then + echo "#define WITH_FAST 1" +else + echo "#define WITH_FAST 0" +fi + +echo "" +echo "/* WITH_SCACHE_PBB_${CPU}: non-zero if the pbb engine was selected. */" +if [ x$pbb = xyes ] ; then + echo "#define WITH_SCACHE_PBB_${CPU} 1" +else + echo "#define WITH_SCACHE_PBB_${CPU} 0" +fi + +echo "" +echo "/* HAVE_PARALLEL_INSNS: non-zero if cpu can parallelly execute > 1 insn. */" +if [ x$parallel != xno ] ; then + echo "#define HAVE_PARALLEL_INSNS 1" + if [ x$parallel = xread ] ; then + echo "/* Parallel execution is supported by read-before-exec. */" + echo "#define WITH_PARALLEL_READ 1" + echo "#define WITH_PARALLEL_WRITE 0" + else + echo "/* Parallel execution is supported by write-after-exec. */" + echo "#define WITH_PARALLEL_READ 0" + echo "#define WITH_PARALLEL_WRITE 1" + fi +else + echo "#define HAVE_PARALLEL_INSNS 0" + echo "#define WITH_PARALLEL_READ 0" + echo "#define WITH_PARALLEL_WRITE 0" +fi + +if [ "x$switch" != x ] ; then + echo "" + echo "/* WITH_SEM_SWITCH_FULL: non-zero if full-featured engine is" + echo " implemented as a switch(). */" + if [ x$fast != xyes -o x$full_switch = xyes ] ; then + echo "#define WITH_SEM_SWITCH_FULL 1" + else + echo "#define WITH_SEM_SWITCH_FULL 0" + fi + echo "" + echo "/* WITH_SEM_SWITCH_FAST: non-zero if fast engine is" + echo " implemented as a switch(). */" + if [ x$fast = xyes ] ; then + echo "#define WITH_SEM_SWITCH_FAST 1" + else + echo "#define WITH_SEM_SWITCH_FAST 0" + fi +fi + +# Decls of functions we define. + +echo "" +echo "/* Functions defined in the generated mainloop.c file" +echo " (which doesn't necessarily have that file name). */" +echo "" +echo "extern ENGINE_FN ${cpu}_engine_run_full;" +echo "extern ENGINE_FN ${cpu}_engine_run_fast;" + +if [ x$pbb = xyes ] ; then + echo "" + echo "extern SEM_PC ${cpu}_pbb_begin (SIM_CPU *, int);" + echo "extern SEM_PC ${cpu}_pbb_chain (SIM_CPU *, SEM_ARG);" + echo "extern SEM_PC ${cpu}_pbb_cti_chain (SIM_CPU *, SEM_ARG, SEM_PC *, PCADDR);" + echo "extern void ${cpu}_pbb_before (SIM_CPU *, SCACHE *);" + echo "extern void ${cpu}_pbb_after (SIM_CPU *, SCACHE *);" +fi + +########################################################################## + +rm -f tmp-mloop.cin mloop.cin +exec 1>tmp-mloop.cin + +# We use @cpu@ instead of ${cpu} because we still need to run sed to handle +# transformation of @cpu@ for mainloop.in, so there's no need to use ${cpu} +# here. + +cat << EOF +/* This file is generated by the genmloop script. DO NOT EDIT! */ + +/* Enable switch() support in cgen headers. */ +#define SEM_IN_SWITCH + +#define WANT_CPU @cpu@ +#define WANT_CPU_@CPU@ + +#include "sim-main.h" +#include "bfd.h" +#include "cgen-mem.h" +#include "cgen-ops.h" +#include "sim-assert.h" + +/* Fill in the administrative ARGBUF fields required by all insns, + virtual and real. */ + +static INLINE void +@cpu@_fill_argbuf (const SIM_CPU *cpu, ARGBUF *abuf, const IDESC *idesc, + PCADDR pc, int fast_p) +{ +#if WITH_SCACHE + SEM_SET_CODE (abuf, idesc, fast_p); + ARGBUF_ADDR (abuf) = pc; +#endif + ARGBUF_IDESC (abuf) = idesc; +} + +/* Fill in tracing/profiling fields of an ARGBUF. */ + +static INLINE void +@cpu@_fill_argbuf_tp (const SIM_CPU *cpu, ARGBUF *abuf, + int trace_p, int profile_p) +{ + ARGBUF_TRACE_P (abuf) = trace_p; + ARGBUF_PROFILE_P (abuf) = profile_p; +} + +#if WITH_SCACHE_PBB + +/* Emit the "x-before" handler. + x-before is emitted before each insn (serial or parallel). + This is as opposed to x-after which is only emitted at the end of a group + of parallel insns. */ + +static INLINE void +@cpu@_emit_before (SIM_CPU *current_cpu, SCACHE *sc, PCADDR pc, int first_p) +{ + ARGBUF *abuf = &sc[0].argbuf; + const IDESC *id = & CPU_IDESC (current_cpu) [@CPU@_INSN_X_BEFORE]; + + abuf->fields.before.first_p = first_p; + @cpu@_fill_argbuf (current_cpu, abuf, id, pc, 0); + /* no need to set trace_p,profile_p */ +} + +/* Emit the "x-after" handler. + x-after is emitted after a serial insn or at the end of a group of + parallel insns. */ + +static INLINE void +@cpu@_emit_after (SIM_CPU *current_cpu, SCACHE *sc, PCADDR pc) +{ + ARGBUF *abuf = &sc[0].argbuf; + const IDESC *id = & CPU_IDESC (current_cpu) [@CPU@_INSN_X_AFTER]; + + @cpu@_fill_argbuf (current_cpu, abuf, id, pc, 0); + /* no need to set trace_p,profile_p */ +} + +#endif /* WITH_SCACHE_PBB */ + +EOF + +${SHELL} $infile support + +########################################################################## + +# Simple engine: fetch an instruction, execute the instruction. +# +# Instruction fields are not extracted into ARGBUF, they are extracted in +# the semantic routines themselves. However, there is still a need to pass +# and return misc. information to the semantic routines so we still use ARGBUF. +# [One could certainly implement things differently and remove ARGBUF. +# It's not clear this is necessarily always a win.] +# ??? The use of the SCACHE struct is for consistency with the with-scache +# case though it might be a source of confusion. + +if [ x$scache != xyes -a x$pbb != xyes ] ; then + + cat << EOF + +#define FAST_P 0 + +void +@cpu@_engine_run_full (SIM_CPU *current_cpu) +{ +#define FAST_P 0 + SIM_DESC current_state = CPU_STATE (current_cpu); + /* ??? Use of SCACHE is a bit of a hack as we don't actually use the scache. + We do however use ARGBUF so for consistency with the other engine flavours + the SCACHE type is used. */ + SCACHE cache[MAX_LIW_INSNS]; + SCACHE *sc = &cache[0]; + +EOF + +if [ x$parallel != xno ] ; then + cat << EOF + PAREXEC pbufs[MAX_PARALLEL_INSNS]; + PAREXEC *par_exec; + +EOF +fi + +# Any initialization code before looping starts. +# Note that this code may declare some locals. +${SHELL} $infile init + +if [ x$parallel != xno ] ; then + cat << EOF + +#if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__) + { + if (! CPU_IDESC_READ_INIT_P (current_cpu)) + { +/* ??? Later maybe paste read.c in when building mainloop.c. */ +#define DEFINE_LABELS +#include "readx.c" + CPU_IDESC_READ_INIT_P (current_cpu) = 1; + } + } +#endif + +EOF +fi + +cat << EOF + +#if WITH_SEM_SWITCH_FULL && defined (__GNUC__) + { + if (! CPU_IDESC_SEM_INIT_P (current_cpu)) + { +/* ??? Later maybe paste sem-switch.c in when building mainloop.c. */ +#define DEFINE_LABELS +#include "$switch" + CPU_IDESC_SEM_INIT_P (current_cpu) = 1; + } + } +#endif + + do + { +/* begin full-exec-simple */ +EOF + +${SHELL} $infile full-exec-simple + +cat << EOF +/* end full-exec-simple */ + + ++ CPU_INSN_COUNT (current_cpu); + } + while (0 /*CPU_RUNNING_P (current_cpu)*/); +} + +#undef FAST_P + +EOF + +#################################### + +# Simple engine: fast version. +# ??? A somewhat dubious effort, but for completeness' sake. + +if [ x$fast = xyes ] ; then + + cat << EOF + +#define FAST_P 1 + +FIXME: "fast simple version unimplemented, delete -fast arg to genmloop.sh." + +#undef FAST_P + +EOF + +fi # -fast + +fi # simple engine + +########################################################################## + +# Scache engine: lookup insn in scache, fetch if missing, then execute it. + +if [ x$scache = xyes ] ; then + + cat << EOF + +static INLINE SCACHE * +@cpu@_scache_lookup (SIM_CPU *current_cpu, PCADDR vpc, SCACHE *scache, + unsigned int hash_mask, int FAST_P) +{ + /* First step: look up current insn in hash table. */ + SCACHE *sc = scache + SCACHE_HASH_PC (vpc, hash_mask); + + /* If the entry isn't the one we want (cache miss), + fetch and decode the instruction. */ + if (sc->argbuf.addr != vpc) + { + insn_t insn; + + if (FAST_P) + PROFILE_COUNT_SCACHE_MISS (current_cpu); + +/* begin extract-scache */ +EOF + +${SHELL} $infile extract-scache + +cat << EOF +/* end extract-scache */ + } + else if (FAST_P) + { + PROFILE_COUNT_SCACHE_HIT (current_cpu); + /* Make core access statistics come out right. + The size is a guess, but it's currently not used either. */ + PROFILE_COUNT_CORE (current_cpu, vpc, 2, exec_map); + } + + return sc; +} + +#define FAST_P 0 + +void +@cpu@_engine_run_full (SIM_CPU *current_cpu) +{ + SIM_DESC current_state = CPU_STATE (current_cpu); + SCACHE *scache = CPU_SCACHE_CACHE (current_cpu); + unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu); + SEM_PC vpc; + +EOF + +if [ x$parallel != xno ] ; then + cat << EOF + PAREXEC pbufs[MAX_PARALLEL_INSNS]; + PAREXEC *par_exec; + +EOF +fi + +# Any initialization code before looping starts. +# Note that this code may declare some locals. +${SHELL} $infile init + +if [ x$parallel != xno ] ; then + cat << EOF + +#if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__) + { + if (! CPU_IDESC_READ_INIT_P (current_cpu)) + { +/* ??? Later maybe paste read.c in when building mainloop.c. */ +#define DEFINE_LABELS +#include "readx.c" + CPU_IDESC_READ_INIT_P (current_cpu) = 1; + } + } +#endif + +EOF +fi + +cat << EOF + + vpc = GET_H_PC (); + + do + { + SCACHE *sc; + + sc = @cpu@_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P); + +/* begin full-exec-scache */ +EOF + +${SHELL} $infile full-exec-scache + +cat << EOF +/* end full-exec-scache */ + + SET_H_PC (vpc); + + ++ CPU_INSN_COUNT (current_cpu); + } + while (0 /*CPU_RUNNING_P (current_cpu)*/); +} + +#undef FAST_P + +EOF + +#################################### + +# Scache engine: fast version. + +if [ x$fast = xyes ] ; then + + cat << EOF + +#define FAST_P 1 + +void +@cpu@_engine_run_fast (SIM_CPU *current_cpu) +{ + SIM_DESC current_state = CPU_STATE (current_cpu); + SCACHE *scache = CPU_SCACHE_CACHE (current_cpu); + unsigned int hash_mask = CPU_SCACHE_HASH_MASK (current_cpu); + SEM_PC vpc; + +EOF + +if [ x$parallel != xno ] ; then + cat << EOF + PAREXEC pbufs[MAX_PARALLEL_INSNS]; + PAREXEC *par_exec; + +EOF +fi + +# Any initialization code before looping starts. +# Note that this code may declare some locals. +${SHELL} $infile init + +if [ x$parallel != xno ] ; then + cat << EOF + +#if defined (HAVE_PARALLEL_EXEC) && defined (__GNUC__) + { + if (! CPU_IDESC_READ_INIT_P (current_cpu)) + { +/* ??? Later maybe paste read.c in when building mainloop.c. */ +#define DEFINE_LABELS +#include "readx.c" + CPU_IDESC_READ_INIT_P (current_cpu) = 1; + } + } +#endif + +EOF +fi # parallel != no + +cat << EOF + +#if WITH_SEM_SWITCH_FAST && defined (__GNUC__) + { + if (! CPU_IDESC_SEM_INIT_P (current_cpu)) + { +/* ??? Later maybe paste sem-switch.c in when building mainloop.c. */ +#define DEFINE_LABELS +#include "$switch" + CPU_IDESC_SEM_INIT_P (current_cpu) = 1; + } + } +#endif + + vpc = GET_H_PC (); + + do + { + SCACHE *sc; + + sc = @cpu@_scache_lookup (current_cpu, vpc, scache, hash_mask, FAST_P); + +/* begin fast-exec-scache */ +EOF + +${SHELL} $infile fast-exec-scache + +cat << EOF +/* end fast-exec-scache */ + + SET_H_PC (vpc); + + ++ CPU_INSN_COUNT (current_cpu); + } + while (0 /*CPU_RUNNING_P (current_cpu)*/); +} + +#undef FAST_P + +EOF + +fi # -fast + +fi # -scache + +########################################################################## + +# Compilation engine: lookup insn in scache, extract a pbb +# (pseudo-basic-block) if missing, then execute the pbb. +# A "pbb" is a sequence of insns up to the next cti insn or until +# some prespecified maximum. +# CTI: control transfer instruction. + +if [ x$pbb = xyes ] ; then + + cat << EOF + +/* Record address of cti terminating a pbb. */ +#define SET_CTI_VPC(sc) do { _cti_sc = (sc); } while (0) +/* Record number of [real] insns in pbb. */ +#define SET_INSN_COUNT(n) do { _insn_count = (n); } while (0) + +/* Fetch and extract a pseudo-basic-block. + FAST_P is non-zero if no tracing/profiling/etc. is wanted. */ + +INLINE SEM_PC +@cpu@_pbb_begin (SIM_CPU *current_cpu, int FAST_P) +{ + SEM_PC new_vpc; + PCADDR pc; + SCACHE *sc; + int max_insns = CPU_SCACHE_MAX_CHAIN_LENGTH (current_cpu); + + pc = GET_H_PC (); + + new_vpc = scache_lookup_or_alloc (current_cpu, pc, max_insns, &sc); + if (! new_vpc) + { + /* Leading '_' to avoid collision with mainloop.in. */ + int _insn_count = 0; + SCACHE *orig_sc = sc; + SCACHE *_cti_sc = NULL; + int slice_insns = CPU_MAX_SLICE_INSNS (current_cpu); + + /* First figure out how many instructions to compile. + MAX_INSNS is the size of the allocated buffer, which includes space + for before/after handlers if they're being used. + SLICE_INSNS is the maxinum number of real insns that can be + executed. Zero means "as many as we want". */ + /* ??? max_insns is serving two incompatible roles. + 1) Number of slots available in scache buffer. + 2) Number of real insns to execute. + They're incompatible because there are virtual insns emitted too + (chain,cti-chain,before,after handlers). */ + + if (slice_insns == 1) + { + /* No need to worry about extra slots required for virtual insns + and parallel exec support because MAX_CHAIN_LENGTH is + guaranteed to be big enough to execute at least 1 insn! */ + max_insns = 1; + } + else + { + /* Allow enough slop so that while compiling insns, if max_insns > 0 + then there's guaranteed to be enough space to emit one real insn. + MAX_CHAIN_LENGTH is typically much longer than + the normal number of insns between cti's anyway. */ + max_insns -= (1 /* one for the trailing chain insn */ + + (FAST_P + ? 0 + : (1 + MAX_PARALLEL_INSNS) /* before+after */) + + (MAX_PARALLEL_INSNS > 1 + ? (MAX_PARALLEL_INSNS * 2) + : 0)); + + /* Account for before/after handlers. */ + if (! FAST_P) + slice_insns *= 3; + + if (slice_insns > 0 + && slice_insns < max_insns) + max_insns = slice_insns; + } + + new_vpc = sc; + + /* SC,PC must be updated to point passed the last entry used. + SET_CTI_VPC must be called if pbb is terminated by a cti. + SET_INSN_COUNT must be called to record number of real insns in + pbb [could be computed by us of course, extra cpu but perhaps + negligible enough]. */ + +/* begin extract-pbb */ +EOF + +${SHELL} $infile extract-pbb + +cat << EOF +/* end extract-pbb */ + + /* The last one is a pseudo-insn to link to the next chain. + It is also used to record the insn count for this chain. */ + { + const IDESC *id; + + /* Was pbb terminated by a cti? */ + if (_cti_sc) + { + id = & CPU_IDESC (current_cpu) [@CPU@_INSN_X_CTI_CHAIN]; + } + else + { + id = & CPU_IDESC (current_cpu) [@CPU@_INSN_X_CHAIN]; + } + SEM_SET_CODE (&sc->argbuf, id, FAST_P); + sc->argbuf.idesc = id; + sc->argbuf.addr = pc; + sc->argbuf.fields.chain.insn_count = _insn_count; + sc->argbuf.fields.chain.next = 0; + ++sc; + } + + /* Update the pointer to the next free entry. */ + CPU_SCACHE_NEXT_FREE (current_cpu) = sc; + /* Record length of chain if profiling. + This includes virtual insns since they count against + max_insns too. */ + if (! FAST_P) + PROFILE_COUNT_SCACHE_CHAIN_LENGTH (current_cpu, sc - orig_sc); + } + + return new_vpc; +} + +/* Chain to the next block from a non-cti terminated previous block. */ + +INLINE SEM_PC +@cpu@_pbb_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg) +{ + ARGBUF *abuf = SEM_ARGBUF (sem_arg); + + PBB_UPDATE_INSN_COUNT (current_cpu, sem_arg); + + SET_H_PC (abuf->addr); + + /* If not running forever, exit back to main loop. */ + if (CPU_MAX_SLICE_INSNS (current_cpu) != 0 + /* Also exit back to main loop if there's an event. + Note that if CPU_MAX_SLICE_INSNS != 1, events won't get processed + at the "right" time, but then that was what was asked for. + There is no silver bullet for simulator engines. + ??? Clearly this needs a cleaner interface. + At present it's just so Ctrl-C works. */ + || STATE_EVENTS (CPU_STATE (current_cpu))->work_pending) + CPU_RUNNING_P (current_cpu) = 0; + + /* If chained to next block, go straight to it. */ + if (abuf->fields.chain.next) + return abuf->fields.chain.next; + /* See if next block has already been compiled. */ + abuf->fields.chain.next = scache_lookup (current_cpu, abuf->addr); + if (abuf->fields.chain.next) + return abuf->fields.chain.next; + /* Nope, so next insn is a virtual insn to invoke the compiler + (begin a pbb). */ + return CPU_SCACHE_PBB_BEGIN (current_cpu); +} + +/* Chain to the next block from a cti terminated previous block. + NEW_VPC_PTR is one of SEM_BRANCH_UNTAKEN, SEM_BRANCH_UNCACHEABLE, or + a pointer to a location containing the SEM_PC of the branch's address. + NEW_PC is the target's branch address, and is only valid if + NEW_VPC_PTR != SEM_BRANCH_UNTAKEN. */ + +INLINE SEM_PC +@cpu@_pbb_cti_chain (SIM_CPU *current_cpu, SEM_ARG sem_arg, + SEM_PC *new_vpc_ptr, PCADDR new_pc) +{ + ARGBUF *abuf; + + PBB_UPDATE_INSN_COUNT (current_cpu, sem_arg); + + /* If not running forever, exit back to main loop. */ + if (CPU_MAX_SLICE_INSNS (current_cpu) != 0 + /* Also exit back to main loop if there's an event. + Note that if CPU_MAX_SLICE_INSNS != 1, events won't get processed + at the "right" time, but then that was what was asked for. + There is no silver bullet for simulator engines. + ??? Clearly this needs a cleaner interface. + At present it's just so Ctrl-C works. */ + || STATE_EVENTS (CPU_STATE (current_cpu))->work_pending) + CPU_RUNNING_P (current_cpu) = 0; + + /* Restart compiler if we branched to an uncacheable address + (e.g. "j reg"). */ + if (new_vpc_ptr == SEM_BRANCH_UNCACHEABLE) + { + SET_H_PC (new_pc); + return CPU_SCACHE_PBB_BEGIN (current_cpu); + } + + /* If branch wasn't taken, update the pc and set BR_ADDR_PTR to our + next chain ptr. */ + if (new_vpc_ptr == SEM_BRANCH_UNTAKEN) + { + abuf = SEM_ARGBUF (sem_arg); + SET_H_PC (abuf->addr); + new_vpc_ptr = &abuf->fields.chain.next; + } + else + { + SET_H_PC (new_pc); + } + + /* If chained to next block, go straight to it. */ + if (*new_vpc_ptr) + return *new_vpc_ptr; + /* See if next block has already been compiled. */ + *new_vpc_ptr = scache_lookup (current_cpu, GET_H_PC ()); + if (*new_vpc_ptr) + return *new_vpc_ptr; + /* Nope, so next insn is a virtual insn to invoke the compiler + (begin a pbb). */ + return CPU_SCACHE_PBB_BEGIN (current_cpu); +} + +/* x-before handler. + This is called before each insn. */ + +void +@cpu@_pbb_before (SIM_CPU *current_cpu, SCACHE *sc) +{ + SEM_ARG sem_arg = sc; + const ARGBUF *abuf = SEM_ARGBUF (sem_arg); + int first_p = abuf->fields.before.first_p; + const ARGBUF *cur_abuf = SEM_ARGBUF (sc + 1); + const IDESC *cur_idesc = cur_abuf->idesc; + PCADDR pc = cur_abuf->addr; + + if (ARGBUF_PROFILE_P (cur_abuf)) + PROFILE_COUNT_INSN (current_cpu, pc, cur_idesc->num); + + /* If this isn't the first insn, finish up the previous one. */ + + if (! first_p) + { + if (PROFILE_MODEL_P (current_cpu)) + { + const SEM_ARG prev_sem_arg = sc - 1; + const ARGBUF *prev_abuf = SEM_ARGBUF (prev_sem_arg); + const IDESC *prev_idesc = prev_abuf->idesc; + int cycles; + + /* ??? May want to measure all insns if doing insn tracing. */ + if (ARGBUF_PROFILE_P (prev_abuf)) + { + cycles = (*prev_idesc->timing->model_fn) (current_cpu, prev_sem_arg); + @cpu@_model_insn_after (current_cpu, 0 /*last_p*/, cycles); + } + } + + TRACE_INSN_FINI (current_cpu, cur_abuf, 0 /*last_p*/); + } + + /* FIXME: Later make cover macros: PROFILE_INSN_{INIT,FINI}. */ + if (PROFILE_MODEL_P (current_cpu) + && ARGBUF_PROFILE_P (cur_abuf)) + @cpu@_model_insn_before (current_cpu, first_p); + + TRACE_INSN_INIT (current_cpu, cur_abuf, first_p); + TRACE_INSN (current_cpu, cur_idesc->idata, cur_abuf, pc); +} + +/* x-after handler. + This is called after a serial insn or at the end of a group of parallel + insns. */ + +void +@cpu@_pbb_after (SIM_CPU *current_cpu, SCACHE *sc) +{ + SEM_ARG sem_arg = sc; + const ARGBUF *abuf = SEM_ARGBUF (sem_arg); + const SEM_ARG prev_sem_arg = sc - 1; + const ARGBUF *prev_abuf = SEM_ARGBUF (prev_sem_arg); + + /* ??? May want to measure all insns if doing insn tracing. */ + if (PROFILE_MODEL_P (current_cpu) + && ARGBUF_PROFILE_P (prev_abuf)) + { + const IDESC *prev_idesc = prev_abuf->idesc; + int cycles; + + cycles = (*prev_idesc->timing->model_fn) (current_cpu, prev_sem_arg); + @cpu@_model_insn_after (current_cpu, 1 /*last_p*/, cycles); + } + TRACE_INSN_FINI (current_cpu, prev_abuf, 1 /*last_p*/); +} + +#define FAST_P 0 + +void +@cpu@_engine_run_full (SIM_CPU *current_cpu) +{ + SIM_DESC current_state = CPU_STATE (current_cpu); + SCACHE *scache = CPU_SCACHE_CACHE (current_cpu); + /* virtual program counter */ + SEM_PC vpc; +#if WITH_SEM_SWITCH_FULL + /* For communication between cti's and cti-chain. */ + PCADDR pbb_br_npc; + SEM_PC *pbb_br_npc_ptr; +#endif + +EOF + +if [ x$parallel != xno ] ; then + cat << EOF + PAREXEC pbufs[MAX_PARALLEL_INSNS]; + PAREXEC *par_exec = &pbufs[0]; + +EOF +fi + +# Any initialization code before looping starts. +# Note that this code may declare some locals. +${SHELL} $infile init + +cat << EOF + + if (! CPU_IDESC_SEM_INIT_P (current_cpu)) + { + /* ??? 'twould be nice to move this up a level and only call it once. + On the other hand, in the "let's go fast" case the test is only done + once per pbb (since we only return to the main loop at the end of + a pbb). And in the "let's run until we're done" case we don't return + until the program exits. */ + +#if WITH_SEM_SWITCH_FULL && defined (__GNUC__) +/* ??? Later maybe paste sem-switch.c in when building mainloop.c. */ +#define DEFINE_LABELS +#include "$switch" +#endif + + /* Initialize the "begin (compile) a pbb" virtual insn. */ + vpc = CPU_SCACHE_PBB_BEGIN (current_cpu); + SEM_SET_FULL_CODE (SEM_ARGBUF (vpc), + & CPU_IDESC (current_cpu) [@CPU@_INSN_X_BEGIN]); + vpc->argbuf.idesc = & CPU_IDESC (current_cpu) [@CPU@_INSN_X_BEGIN]; + + CPU_IDESC_SEM_INIT_P (current_cpu) = 1; + } + + CPU_RUNNING_P (current_cpu) = 1; + /* ??? In the case where we're returning to the main loop after every + pbb we don't want to call pbb_begin each time (which hashes on the pc + and does a table lookup). A way to speed this up is to save vpc + between calls. */ + vpc = @cpu@_pbb_begin (current_cpu, FAST_P); + + do + { +/* begin full-exec-pbb */ +EOF + +${SHELL} $infile full-exec-pbb + +cat << EOF +/* end full-exec-pbb */ + } + while (CPU_RUNNING_P (current_cpu)); +} + +#undef FAST_P + +EOF + +#################################### + +# Compile engine: fast version. + +if [ x$fast = xyes ] ; then + + cat << EOF + +#define FAST_P 1 + +void +@cpu@_engine_run_fast (SIM_CPU *current_cpu) +{ + SIM_DESC current_state = CPU_STATE (current_cpu); + SCACHE *scache = CPU_SCACHE_CACHE (current_cpu); + /* virtual program counter */ + SEM_PC vpc; +#if WITH_SEM_SWITCH_FAST + /* For communication between cti's and cti-chain. */ + PCADDR pbb_br_npc; + SEM_PC *pbb_br_npc_ptr; +#endif + +EOF + +if [ x$parallel != xno ] ; then + cat << EOF + PAREXEC pbufs[MAX_PARALLEL_INSNS]; + PAREXEC *par_exec = &pbufs[0]; + +EOF +fi + +# Any initialization code before looping starts. +# Note that this code may declare some locals. +${SHELL} $infile init + +cat << EOF + + if (! CPU_IDESC_SEM_INIT_P (current_cpu)) + { + /* ??? 'twould be nice to move this up a level and only call it once. + On the other hand, in the "let's go fast" case the test is only done + once per pbb (since we only return to the main loop at the end of + a pbb). And in the "let's run until we're done" case we don't return + until the program exits. */ + +#if WITH_SEM_SWITCH_FAST && defined (__GNUC__) +/* ??? Later maybe paste sem-switch.c in when building mainloop.c. */ +#define DEFINE_LABELS +#include "$switch" +#endif + + /* Initialize the "begin (compile) a pbb" virtual insn. */ + vpc = CPU_SCACHE_PBB_BEGIN (current_cpu); + SEM_SET_FAST_CODE (SEM_ARGBUF (vpc), + & CPU_IDESC (current_cpu) [@CPU@_INSN_X_BEGIN]); + vpc->argbuf.idesc = & CPU_IDESC (current_cpu) [@CPU@_INSN_X_BEGIN]; + + CPU_IDESC_SEM_INIT_P (current_cpu) = 1; + } + + CPU_RUNNING_P (current_cpu) = 1; + /* ??? In the case where we're returning to the main loop after every + pbb we don't want to call pbb_begin each time (which hashes on the pc + and does a table lookup). A way to speed this up is to save vpc + between calls. */ + vpc = @cpu@_pbb_begin (current_cpu, FAST_P); + + do + { +/* begin fast-exec-pbb */ +EOF + +${SHELL} $infile fast-exec-pbb + +cat << EOF +/* end fast-exec-pbb */ + } + while (CPU_RUNNING_P (current_cpu)); +} + +#undef FAST_P + +EOF +fi # -fast + +fi # -pbb + +# Process @cpu@,@CPU@ appearing in mainloop.in. +sed -e "s/@cpu@/$cpu/g" -e "s/@CPU@/$CPU/g" < tmp-mloop.cin > mloop.cin +rc=$? +rm -f tmp-mloop.cin + +exit $rc diff --git a/sim/common/gennltvals.sh b/sim/common/gennltvals.sh new file mode 100644 index 0000000..63ff662 --- /dev/null +++ b/sim/common/gennltvals.sh @@ -0,0 +1,67 @@ +#! /bin/sh +# Generate nltvals.def, a file that describes various newlib/libgloss +# target values used by the host/target interface. +# +# Syntax: /bin/sh gennltvals.sh shell srcroot cpp + +shell=$1 +srcroot=$2 +cpp=$3 + +srccom=$srcroot/sim/common + +echo '/* Newlib/libgloss macro values needed by remote target support. */' +echo '/* This file is machine generated by gennltvals.sh. */' + +$shell ${srccom}/gentvals.sh "" errno ${srcroot}/newlib/libc/include \ + "errno.h sys/errno.h" 'E[A-Z0-9]*' "${cpp}" + +$shell ${srccom}/gentvals.sh "" signal ${srcroot}/newlib/libc/include \ + "signal.h sys/signal.h" 'SIG[A-Z0-9]*' "${cpp}" + +$shell ${srccom}/gentvals.sh "" open ${srcroot}/newlib/libc/include \ + "fcntl.h sys/fcntl.h" 'O_[A-Z0-9]*' "${cpp}" + +# Unfortunately, each newlib/libgloss port has seen fit to define their own +# syscall.h file. This means that system call numbers can vary for each port. +# Support for all this crud is kept here, rather than trying to get too fancy. +# If you want to try to improve this, please do, but don't break anything. +# Note that there is a standard syscall.h file (libgloss/syscall.h) now which +# hopefully more targets can use. + +dir=newlib/libc/sys/d10v/sys target=d10v +$shell ${srccom}/gentvals.sh $target sys ${srcroot}/$dir \ + "syscall.h" 'SYS_[_A-Za-z0-9]*' "${cpp}" + +dir=libgloss target=d30v +$shell ${srccom}/gentvals.sh $target sys ${srcroot}/$dir \ + "syscall.h" 'SYS_[_A-Za-z0-9]*' "${cpp}" + +dir=libgloss target=fr30 +$shell ${srccom}/gentvals.sh $target sys ${srcroot}/$dir \ + "syscall.h" 'SYS_[_A-Za-z0-9]*' "${cpp}" + +dir=libgloss/i960 target=i960 +$shell ${srccom}/gentvals.sh $target sys ${srcroot}/$dir \ + "syscall.h" 'SYS_[_A-Za-z0-9]*' "${cpp}" + +dir=libgloss target=m32r +$shell ${srccom}/gentvals.sh $target sys ${srcroot}/$dir \ + "syscall.h" 'SYS_[_A-Za-z0-9]*' "${cpp}" + +dir=libgloss target=mn10200 +$shell ${srccom}/gentvals.sh $target sys ${srcroot}/$dir \ + "syscall.h" 'SYS_[_A-Za-z0-9]*' "${cpp}" + +dir=libgloss target=mn10300 +$shell ${srccom}/gentvals.sh $target sys ${srcroot}/$dir \ + "syscall.h" 'SYS_[_A-Za-z0-9]*' "${cpp}" + +dir=libgloss target=sparc +$shell ${srccom}/gentvals.sh $target sys ${srcroot}/$dir \ + "syscall.h" 'SYS_[_A-Za-z0-9]*' "${cpp}" + +dir=libgloss/v850/sys target=v850 +$shell ${srccom}/gentvals.sh $target sys ${srcroot}/$dir \ + "syscall.h" 'SYS_[_A-Za-z0-9]*' "${cpp}" + diff --git a/sim/common/gentmap.c b/sim/common/gentmap.c new file mode 100644 index 0000000..e4f5d0d --- /dev/null +++ b/sim/common/gentmap.c @@ -0,0 +1,125 @@ +/* Generate targ-vals.h and targ-map.c. */ + +#include <stdio.h> + +struct tdefs { + char *symbol; + int value; +}; + +static struct tdefs sys_tdefs[] = { +#define sys_defs +#include "targ-vals.def" +#undef sys_defs + { 0, 0 } +}; + +static struct tdefs errno_tdefs[] = { +#define errno_defs +#include "targ-vals.def" +#undef errno_defs + { 0, 0 } +}; + +static struct tdefs open_tdefs[] = { +#define open_defs +#include "targ-vals.def" +#undef open_defs + { 0, 0 } +}; + +static void +gen_targ_vals_h () +{ + struct tdefs *t; + + printf ("/* Target header values needed by the simulator and gdb. */\n"); + printf ("/* This file is machine generated by gentmap.c. */\n\n"); + + printf ("#ifndef TARG_VALS_H\n"); + printf ("#define TARG_VALS_H\n\n"); + + printf ("/* syscall values */\n"); + for (t = &sys_tdefs[0]; t->symbol; ++t) + printf ("#define TARGET_%s %d\n", t->symbol, t->value); + printf ("\n"); + + printf ("/* errno values */\n"); + for (t = &errno_tdefs[0]; t->symbol; ++t) + printf ("#define TARGET_%s %d\n", t->symbol, t->value); + printf ("\n"); + + printf ("/* open flag values */\n"); + for (t = &open_tdefs[0]; t->symbol; ++t) + printf ("#define TARGET_%s 0x%x\n", t->symbol, t->value); + printf ("\n"); + + printf ("#endif /* TARG_VALS_H */\n"); +} + +static void +gen_targ_map_c () +{ + struct tdefs *t; + + printf ("/* Target value mapping utilities needed by the simulator and gdb. */\n"); + printf ("/* This file is machine generated by gentmap.c. */\n\n"); + + printf ("#include <errno.h>\n"); + printf ("#include <fcntl.h>\n"); + printf ("#include \"ansidecl.h\"\n"); + printf ("#include \"callback.h\"\n"); + printf ("#include \"targ-vals.h\"\n"); + printf ("\n"); + + printf ("/* syscall mapping table */\n"); + printf ("CB_TARGET_DEFS_MAP cb_init_syscall_map[] = {\n"); + for (t = &sys_tdefs[0]; t->symbol; ++t) + { + printf ("#ifdef CB_%s\n", t->symbol); + printf (" { CB_%s, TARGET_%s },\n", t->symbol, t->symbol); + printf ("#endif\n"); + } + printf (" { -1, -1 }\n"); + printf ("};\n\n"); + + printf ("/* errno mapping table */\n"); + printf ("CB_TARGET_DEFS_MAP cb_init_errno_map[] = {\n"); + for (t = &errno_tdefs[0]; t->symbol; ++t) + { + printf ("#ifdef %s\n", t->symbol); + printf (" { %s, TARGET_%s },\n", t->symbol, t->symbol); + printf ("#endif\n"); + } + printf (" { 0, 0 }\n"); + printf ("};\n\n"); + + printf ("/* open flags mapping table */\n"); + printf ("CB_TARGET_DEFS_MAP cb_init_open_map[] = {\n"); + for (t = &open_tdefs[0]; t->symbol; ++t) + { + printf ("#ifdef %s\n", t->symbol); + printf (" { %s, TARGET_%s },\n", t->symbol, t->symbol); + printf ("#endif\n"); + } + printf (" { -1, -1 }\n"); + printf ("};\n\n"); +} + +int +main (argc, argv) + int argc; + char *argv[]; +{ + if (argc != 2) + abort (); + + if (strcmp (argv[1], "-h") == 0) + gen_targ_vals_h (); + else if (strcmp (argv[1], "-c") == 0) + gen_targ_map_c (); + else + abort (); + + exit (0); +} diff --git a/sim/common/gentvals.sh b/sim/common/gentvals.sh new file mode 100644 index 0000000..6dd7315 --- /dev/null +++ b/sim/common/gentvals.sh @@ -0,0 +1,74 @@ +#!/bin/sh +# Usage: gentvals.sh target type dir files pattern cpp + +target=$1 +type=$2 +dir=$3 +# FIXME: Would be nice to process #include's in these files. +files=$4 +pattern=$5 +cpp=$6 + +# FIXME: need trap to remove tmp files. + +rm -f tmpvals.list tmpvals.uniq +for f in $files +do + if test -f $dir/$f ; then + grep "#define[ ]$pattern" $dir/$f | sed -e "s/^.*#define[ ]\($pattern\)[ ]*\([^ ][^ ]*\).*$/\1/" >> tmpvals.list + fi +done + +sort <tmpvals.list | uniq >tmpvals.uniq + +rm -f tmpvals.h +for f in $files +do + if test -f $dir/$f ; then + echo "#include <$f>" >>tmpvals.h + fi +done + +cat tmpvals.uniq | +while read sym +do + echo "#ifdef $sym" >>tmpvals.h + echo 'DEFVAL { "'$sym'", '$sym ' },' >>tmpvals.h + echo "#endif" >>tmpvals.h +done + +if test -z "$target" +then + echo "#ifdef ${type}_defs" +else + echo "#ifdef NL_TARGET_$target" + echo "#ifdef ${type}_defs" +fi + +for f in $files +do + if test -f $dir/$f ; then + echo "/* from $f */" + fi +done + +if test -z "$target" +then + echo "/* begin $type target macros */" +else + echo "/* begin $target $type target macros */" +fi + +$cpp -I$dir tmpvals.h | grep DEFVAL | sed -e 's/DEFVAL//' -e 's/ / /' + +if test -z "$target" +then + echo "/* end $type target macros */" + echo "#endif" +else + echo "/* end $target $type target macros */" + echo "#endif" + echo "#endif" +fi + +rm -f tmpvals.list tmpvals.uniq tmpvals.h diff --git a/sim/common/hw-alloc.c b/sim/common/hw-alloc.c new file mode 100644 index 0000000..e64ae82 --- /dev/null +++ b/sim/common/hw-alloc.c @@ -0,0 +1,99 @@ +/* Hardware memory allocator. + Copyright (C) 1998 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +#include "hw-main.h" +#include "hw-base.h" + + +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif + +struct hw_alloc_data { + void *alloc; + int zalloc_p; + struct hw_alloc_data *next; +}; + +void +create_hw_alloc_data (struct hw *me) +{ + /* NULL */ +} + +void +delete_hw_alloc_data (struct hw *me) +{ + if (me->alloc_of_hw != NULL) + hw_abort (me, "hw-alloc botch"); + while (me->alloc_of_hw != NULL) + { + hw_free (me, me->alloc_of_hw->alloc); + } +} + + + +void * +hw_zalloc (struct hw *me, unsigned long size) +{ + struct hw_alloc_data *memory = ZALLOC (struct hw_alloc_data); + memory->alloc = zalloc (size); + memory->zalloc_p = 1; + memory->next = me->alloc_of_hw; + me->alloc_of_hw = memory; + return memory->alloc; +} + +void * +hw_malloc (struct hw *me, unsigned long size) +{ + struct hw_alloc_data *memory = ZALLOC (struct hw_alloc_data); + memory->alloc = zalloc (size); + memory->zalloc_p = 0; + memory->next = me->alloc_of_hw; + me->alloc_of_hw = memory; + return memory->alloc; +} + +void +hw_free (struct hw *me, + void *alloc) +{ + struct hw_alloc_data **memory; + for (memory = &me->alloc_of_hw; + *memory != NULL; + memory = &(*memory)->next) + { + if ((*memory)->alloc == alloc) + { + struct hw_alloc_data *die = (*memory); + (*memory) = die->next; + if (die->zalloc_p) + zfree (die->alloc); + else + free (die->alloc); + zfree (die); + return; + } + } + hw_abort (me, "free of memory not belonging to a device"); +} diff --git a/sim/common/hw-alloc.h b/sim/common/hw-alloc.h new file mode 100644 index 0000000..48b03f2 --- /dev/null +++ b/sim/common/hw-alloc.h @@ -0,0 +1,49 @@ +/* Hardware memory allocator. + Copyright (C) 1998 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +#ifndef HW_ALLOC_H +#define HW_ALLOC_H + +/* Mechanism for associating memory allocated by a device to that + device. + + When a device is deleted any remaining memory regions associated to + it are reclaimed. + + FIXME: Perhaphs this can be generalized. Perhaphs it should not + be. */ + + +#define HW_ZALLOC(me,type) (type*) hw_zalloc (me, sizeof (type)) +#define HW_MALLOC(me,type) (type*) hw_malloc (me, sizeof (type)) +#define HW_NZALLOC(ME,TYPE,N) (TYPE*) hw_zalloc (me, sizeof (TYPE) * (N)) + +extern void *hw_zalloc (struct hw *me, unsigned long size); +extern void *hw_malloc (struct hw *me, unsigned long size); + +extern void hw_free (struct hw *me, void *); + + +/* Duplicate a string allocating memory using the per-device heap */ + +extern char *hw_strdup (struct hw *me, const char *str); + +#endif diff --git a/sim/common/hw-base.c b/sim/common/hw-base.c new file mode 100644 index 0000000..a13ac64 --- /dev/null +++ b/sim/common/hw-base.c @@ -0,0 +1,571 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1996, 1998, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#include "hw-main.h" +#include "hw-base.h" + + +#ifdef HAVE_STRING_H +#include <string.h> +#else +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#endif + +#if HAVE_STDLIB_H +#include <stdlib.h> +#endif + +#include <ctype.h> + +#include "hw-config.h" + +struct hw_base_data { + int finished_p; + const struct hw_descriptor *descriptor; + hw_delete_callback *to_delete; +}; + +static int +generic_hw_unit_decode (struct hw *bus, + const char *unit, + hw_unit *phys) +{ + memset (phys, 0, sizeof (*phys)); + if (unit == NULL) + return 0; + else + { + int nr_cells = 0; + const int max_nr_cells = hw_unit_nr_address_cells (bus); + while (1) + { + char *end = NULL; + unsigned long val; + val = strtoul (unit, &end, 0); + /* parse error? */ + if (unit == end) + return -1; + /* two many cells? */ + if (nr_cells >= max_nr_cells) + return -1; + /* save it */ + phys->cells[nr_cells] = val; + nr_cells++; + unit = end; + /* more to follow? */ + if (isspace (*unit) || *unit == '\0') + break; + if (*unit != ',') + return -1; + unit++; + } + if (nr_cells < max_nr_cells) { + /* shift everything to correct position */ + int i; + for (i = 1; i <= nr_cells; i++) + phys->cells[max_nr_cells - i] = phys->cells[nr_cells - i]; + for (i = 0; i < (max_nr_cells - nr_cells); i++) + phys->cells[i] = 0; + } + phys->nr_cells = max_nr_cells; + return max_nr_cells; + } +} + +static int +generic_hw_unit_encode (struct hw *bus, + const hw_unit *phys, + char *buf, + int sizeof_buf) +{ + int i; + int len; + char *pos = buf; + /* skip leading zero's */ + for (i = 0; i < phys->nr_cells; i++) + { + if (phys->cells[i] != 0) + break; + } + /* don't output anything if empty */ + if (phys->nr_cells == 0) + { + strcpy(pos, ""); + len = 0; + } + else if (i == phys->nr_cells) + { + /* all zero */ + strcpy(pos, "0"); + len = 1; + } + else + { + for (; i < phys->nr_cells; i++) + { + if (pos != buf) { + strcat(pos, ","); + pos = strchr(pos, '\0'); + } + if (phys->cells[i] < 10) + sprintf (pos, "%ld", (unsigned long)phys->cells[i]); + else + sprintf (pos, "0x%lx", (unsigned long)phys->cells[i]); + pos = strchr(pos, '\0'); + } + len = pos - buf; + } + if (len >= sizeof_buf) + hw_abort (NULL, "generic_unit_encode - buffer overflow\n"); + return len; +} + +static int +generic_hw_unit_address_to_attach_address (struct hw *me, + const hw_unit *address, + int *attach_space, + unsigned_word *attach_address, + struct hw *client) +{ + int i; + for (i = 0; i < address->nr_cells - 2; i++) + { + if (address->cells[i] != 0) + hw_abort (me, "Only 32bit addresses supported"); + } + if (address->nr_cells >= 2) + *attach_space = address->cells[address->nr_cells - 2]; + else + *attach_space = 0; + *attach_address = address->cells[address->nr_cells - 1]; + return 1; +} + +static int +generic_hw_unit_size_to_attach_size (struct hw *me, + const hw_unit *size, + unsigned *nr_bytes, + struct hw *client) +{ + int i; + for (i = 0; i < size->nr_cells - 1; i++) + { + if (size->cells[i] != 0) + hw_abort (me, "Only 32bit sizes supported"); + } + *nr_bytes = size->cells[0]; + return *nr_bytes; +} + + +/* ignore/passthrough versions of each function */ + +static void +passthrough_hw_attach_address (struct hw *me, + int level, + int space, + address_word addr, + address_word nr_bytes, + struct hw *client) /*callback/default*/ +{ + if (hw_parent (me) == NULL) + hw_abort (client, "hw_attach_address: no parent attach method"); + hw_attach_address (hw_parent (me), level, + space, addr, nr_bytes, + client); +} + +static void +passthrough_hw_detach_address (struct hw *me, + int level, + int space, + address_word addr, + address_word nr_bytes, + struct hw *client) /*callback/default*/ +{ + if (hw_parent (me) == NULL) + hw_abort (client, "hw_attach_address: no parent attach method"); + hw_detach_address (hw_parent (me), level, + space, addr, nr_bytes, + client); +} + +static unsigned +panic_hw_io_read_buffer (struct hw *me, + void *dest, + int space, + unsigned_word addr, + unsigned nr_bytes) +{ + hw_abort (me, "no io-read method"); + return 0; +} + +static unsigned +panic_hw_io_write_buffer (struct hw *me, + const void *source, + int space, + unsigned_word addr, + unsigned nr_bytes) +{ + hw_abort (me, "no io-write method"); + return 0; +} + +static unsigned +passthrough_hw_dma_read_buffer (struct hw *me, + void *dest, + int space, + unsigned_word addr, + unsigned nr_bytes) +{ + if (hw_parent (me) == NULL) + hw_abort (me, "no parent dma-read method"); + return hw_dma_read_buffer (hw_parent (me), dest, + space, addr, nr_bytes); +} + +static unsigned +passthrough_hw_dma_write_buffer (struct hw *me, + const void *source, + int space, + unsigned_word addr, + unsigned nr_bytes, + int violate_read_only_section) +{ + if (hw_parent (me) == NULL) + hw_abort (me, "no parent dma-write method"); + return hw_dma_write_buffer (hw_parent (me), source, + space, addr, + nr_bytes, + violate_read_only_section); +} + +static void +ignore_hw_delete (struct hw *me) +{ + /* NOP */ +} + + + + +static const char * +full_name_of_hw (struct hw *leaf, + char *buf, + unsigned sizeof_buf) +{ + /* get a buffer */ + char full_name[1024]; + if (buf == (char*)0) + { + buf = full_name; + sizeof_buf = sizeof (full_name); + } + + /* use head recursion to construct the path */ + + if (hw_parent (leaf) == NULL) + /* root */ + { + if (sizeof_buf < 1) + hw_abort (leaf, "buffer overflow"); + *buf = '\0'; + } + else + /* sub node */ + { + char unit[1024]; + full_name_of_hw (hw_parent (leaf), buf, sizeof_buf); + if (hw_unit_encode (hw_parent (leaf), + hw_unit_address (leaf), + unit + 1, + sizeof (unit) - 1) + > 0) + unit[0] = '@'; + else + unit[0] = '\0'; + if (strlen (buf) + strlen ("/") + strlen (hw_name (leaf)) + strlen (unit) + >= sizeof_buf) + hw_abort (leaf, "buffer overflow"); + strcat (buf, "/"); + strcat (buf, hw_name (leaf)); + strcat (buf, unit); + } + + /* return it usefully */ + if (buf == full_name) + buf = hw_strdup (leaf, full_name); + return buf; +} + +struct hw * +hw_create (struct sim_state *sd, + struct hw *parent, + const char *family, + const char *name, + const char *unit, + const char *args) +{ + /* NOTE: HW must be allocated using ZALLOC, others use HW_ZALLOC */ + struct hw *hw = ZALLOC (struct hw); + + /* our identity */ + hw->family_of_hw = hw_strdup (hw, family); + hw->name_of_hw = hw_strdup (hw, name); + hw->args_of_hw = hw_strdup (hw, args); + + /* a hook into the system */ + if (sd != NULL) + hw->system_of_hw = sd; + else if (parent != NULL) + hw->system_of_hw = hw_system (parent); + else + hw_abort (parent, "No system found"); + + /* in a tree */ + if (parent != NULL) + { + struct hw **sibling = &parent->child_of_hw; + while ((*sibling) != NULL) + sibling = &(*sibling)->sibling_of_hw; + *sibling = hw; + hw->parent_of_hw = parent; + } + + /* top of tree */ + if (parent != NULL) + { + struct hw *root = parent; + while (root->parent_of_hw != NULL) + root = root->parent_of_hw; + hw->root_of_hw = root; + } + + /* a unique identifier for the device on the parents bus */ + if (parent != NULL) + { + hw_unit_decode (parent, unit, &hw->unit_address_of_hw); + } + + /* Determine our path */ + if (parent != NULL) + hw->path_of_hw = full_name_of_hw (hw, NULL, 0); + else + hw->path_of_hw = "/"; + + /* create our base type */ + hw->base_of_hw = HW_ZALLOC (hw, struct hw_base_data); + hw->base_of_hw->finished_p = 0; + + /* our callbacks */ + set_hw_io_read_buffer (hw, panic_hw_io_read_buffer); + set_hw_io_write_buffer (hw, panic_hw_io_write_buffer); + set_hw_dma_read_buffer (hw, passthrough_hw_dma_read_buffer); + set_hw_dma_write_buffer (hw, passthrough_hw_dma_write_buffer); + set_hw_unit_decode (hw, generic_hw_unit_decode); + set_hw_unit_encode (hw, generic_hw_unit_encode); + set_hw_unit_address_to_attach_address (hw, generic_hw_unit_address_to_attach_address); + set_hw_unit_size_to_attach_size (hw, generic_hw_unit_size_to_attach_size); + set_hw_attach_address (hw, passthrough_hw_attach_address); + set_hw_detach_address (hw, passthrough_hw_detach_address); + set_hw_delete (hw, ignore_hw_delete); + + /* locate a descriptor */ + { + const struct hw_descriptor **table; + for (table = hw_descriptors; + *table != NULL; + table++) + { + const struct hw_descriptor *entry; + for (entry = *table; + entry->family != NULL; + entry++) + { + if (strcmp (family, entry->family) == 0) + { + hw->base_of_hw->descriptor = entry; + break; + } + } + } + if (hw->base_of_hw->descriptor == NULL) + { + hw_abort (parent, "Unknown device `%s'", family); + } + } + + /* Attach dummy ports */ + create_hw_alloc_data (hw); + create_hw_property_data (hw); + create_hw_port_data (hw); + create_hw_event_data (hw); + create_hw_handle_data (hw); + create_hw_instance_data (hw); + + return hw; +} + + +int +hw_finished_p (struct hw *me) +{ + return (me->base_of_hw->finished_p); +} + +void +hw_finish (struct hw *me) +{ + if (hw_finished_p (me)) + hw_abort (me, "Attempt to finish finished device"); + + /* Fill in the (hopefully) defined address/size cells values */ + if (hw_find_property (me, "#address-cells") != NULL) + me->nr_address_cells_of_hw_unit = + hw_find_integer_property (me, "#address-cells"); + else + me->nr_address_cells_of_hw_unit = 2; + if (hw_find_property (me, "#size-cells") != NULL) + me->nr_size_cells_of_hw_unit = + hw_find_integer_property (me, "#size-cells"); + else + me->nr_size_cells_of_hw_unit = 1; + + /* Fill in the (hopefully) defined trace variable */ + if (hw_find_property (me, "trace?") != NULL) + me->trace_of_hw_p = hw_find_boolean_property (me, "trace?"); + /* allow global variable to define default tracing */ + else if (! hw_trace_p (me) + && hw_find_property (hw_root (me), "global-trace?") != NULL + && hw_find_boolean_property (hw_root (me), "global-trace?")) + me->trace_of_hw_p = 1; + + + /* Allow the real device to override any methods */ + me->base_of_hw->descriptor->to_finish (me); + me->base_of_hw->finished_p = 1; +} + + +void +hw_delete (struct hw *me) +{ + /* give the object a chance to tidy up */ + me->base_of_hw->to_delete (me); + + delete_hw_instance_data (me); + delete_hw_handle_data (me); + delete_hw_event_data (me); + delete_hw_port_data (me); + delete_hw_property_data (me); + + /* now unlink us from the tree */ + if (hw_parent (me)) + { + struct hw **sibling = &hw_parent (me)->child_of_hw; + while (*sibling != NULL) + { + if (*sibling == me) + { + *sibling = me->sibling_of_hw; + me->sibling_of_hw = NULL; + me->parent_of_hw = NULL; + break; + } + } + } + + /* some sanity checks */ + if (hw_child (me) != NULL) + { + hw_abort (me, "attempt to delete device with children"); + } + if (hw_sibling (me) != NULL) + { + hw_abort (me, "attempt to delete device with siblings"); + } + + /* blow away all memory belonging to the device */ + delete_hw_alloc_data (me); + + /* finally */ + zfree (me->base_of_hw); + zfree (me); +} + + +/* Go through the devices various reg properties for those that + specify attach addresses */ + + +void +do_hw_attach_regs (struct hw *hw) +{ + static const char *(reg_property_names[]) = { + "attach-addresses", + "assigned-addresses", + "reg", + "alternate-reg" , + NULL + }; + const char **reg_property_name; + int nr_valid_reg_properties = 0; + for (reg_property_name = reg_property_names; + *reg_property_name != NULL; + reg_property_name++) + { + if (hw_find_property (hw, *reg_property_name) != NULL) + { + reg_property_spec reg; + int reg_entry; + for (reg_entry = 0; + hw_find_reg_array_property (hw, *reg_property_name, reg_entry, + ®); + reg_entry++) + { + unsigned_word attach_address; + int attach_space; + unsigned attach_size; + if (!hw_unit_address_to_attach_address (hw_parent (hw), + ®.address, + &attach_space, + &attach_address, + hw)) + continue; + if (!hw_unit_size_to_attach_size (hw_parent (hw), + ®.size, + &attach_size, hw)) + continue; + hw_attach_address (hw_parent (hw), + 0, + attach_space, attach_address, attach_size, + hw); + nr_valid_reg_properties++; + } + /* if first option matches don't try for any others */ + if (reg_property_name == reg_property_names) + break; + } + } +} diff --git a/sim/common/hw-base.h b/sim/common/hw-base.h new file mode 100644 index 0000000..d6452d1 --- /dev/null +++ b/sim/common/hw-base.h @@ -0,0 +1,109 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1998, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef HW_BASE +#define HW_BASE + +/* Create a primative device */ + +struct hw *hw_create +(struct sim_state *sd, + struct hw *parent, + const char *family, + const char *name, + const char *unit, + const char *args); + + +/* Complete the creation of that device (finish overrides methods + using the set_hw_* operations below) */ + +void hw_finish +(struct hw *me); + +int hw_finished_p +(struct hw *me); + + +/* Delete the entire device */ + +void hw_delete +(struct hw *me); + + +/* Override device methods */ + +typedef void (hw_delete_callback) + (struct hw *me); + +#define set_hw_delete(hw, method) \ +((hw)->base_of_hw->to_delete = (method)) + + +/* ALLOC */ + +extern void create_hw_alloc_data +(struct hw *hw); +extern void delete_hw_alloc_data +(struct hw *hw); + + +/* PORTS */ + +extern void create_hw_port_data +(struct hw *hw); +extern void delete_hw_port_data +(struct hw *hw); + + +/* PROPERTIES */ + +extern void create_hw_property_data +(struct hw *hw); +extern void delete_hw_property_data +(struct hw *hw); + + +/* EVENTS */ + +extern void create_hw_event_data +(struct hw *hw); +extern void delete_hw_event_data +(struct hw *hw); + + +/* HANDLES */ + +extern void create_hw_handle_data +(struct hw *hw); +extern void delete_hw_handle_data +(struct hw *hw); + + +/* INSTANCES */ + +extern void create_hw_instance_data +(struct hw *hw); +extern void delete_hw_instance_data +(struct hw *hw); + + +#endif diff --git a/sim/common/hw-device.c b/sim/common/hw-device.c new file mode 100644 index 0000000..c7f50e3 --- /dev/null +++ b/sim/common/hw-device.c @@ -0,0 +1,66 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1998, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#include "hw-main.h" +#include "hw-base.h" + +#if HAVE_STDLIB_H +#include <stdlib.h> +#endif + +/* Address methods */ + +const hw_unit * +hw_unit_address (struct hw *me) +{ + return &me->unit_address_of_hw; +} + + +/* IOCTL: */ + +int +hw_ioctl (struct hw *me, + hw_ioctl_request request, + ...) +{ + int status; + va_list ap; + va_start(ap, request); + status = me->to_ioctl (me, request, ap); + va_end(ap); + return status; +} + +char * +hw_strdup (struct hw *me, const char *str) +{ + if (str != NULL) + { + char *dup = hw_zalloc (me, strlen (str) + 1); + strcpy (dup, str); + return dup; + } + else + { + return NULL; + } +} diff --git a/sim/common/hw-device.h b/sim/common/hw-device.h new file mode 100644 index 0000000..2cbdc5a --- /dev/null +++ b/sim/common/hw-device.h @@ -0,0 +1,535 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1998, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef HW_DEVICE_H +#define HW_DEVICE_H + +/* declared in sim-basics.h, this object is used everywhere */ +/* typedef struct _device device; */ + + +/* Introduction: + + As explained in earlier sections, the device, device instance, + property and ports lie at the heart of PSIM's device model. + + In the below a synopsis of the device object and the operations it + supports are given. + */ + + +/* Creation: + + The devices are created using a sequence of steps. In particular: + + o A tree framework is created. + + At this point, properties can be modified and extra + devices inserted (or removed?). + +#if LATER + + Any properties that have a run-time value (eg ihandle + or device instance pointer properties) are entered + into the device tree using a named reference to the + corresponding runtime object that is to be created. + +#endif + + o Real devices are created for all the dummy devices. + + A device can assume that all of its parents have been + initialized. + + A device can assume that all non run-time properties + have been initialized. + + As part of being created, the device normally attaches + itself to its parent bus. + +#if LATER + + Device instance data is initialized. + +#endif + +#if LATER + + o Any run-time properties are created. + +#endif + +#if MUCH_MUCH_LATER + + o Some devices, as part of their initialization + might want to refer to ihandle properties + in the device tree. + +#endif + + NOTES: + + o It is important to separate the creation + of an actual device from the creation + of the tree. The alternative creating + the device in two stages: As a separate + entity and then as a part of the tree. + +#if LATER + o Run-time properties can not be created + until after the devices in the tree + have been created. Hence an extra pass + for handling them. +#endif + + */ + +/* Relationships: + + A device is able to determine its relationship to other devices + within the tree. Operations include querying for a devices parent, + sibling, child, name, and path (from the root). + + */ + + +#define hw_parent(hw) ((hw)->parent_of_hw + 0) + +#define hw_sibling(hw) ((hw)->sibling_of_hw + 0) + +#define hw_child(hw) ((hw)->child_of_hw + 0) + + + +/* Herritage: + + */ + +#define hw_family(hw) ((hw)->family_of_hw + 0) + +#define hw_name(hw) ((hw)->name_of_hw + 0) + +#define hw_args(hw) ((hw)->args_of_hw + 0) + +#define hw_path(hw) ((hw)->path_of_hw + 0) + + + +/* Short cut to the root node of the tree */ + +#define hw_root(hw) ((hw)->root_of_hw + 0) + +/* Short cut back to the simulator object */ + +#define hw_system(hw) ((hw)->system_of_hw) + +/* For requests initiated by a CPU the cpu that initiated the request */ + +struct _sim_cpu *hw_system_cpu (struct hw *hw); + + +/* Device private data */ + +#define hw_data(hw) ((hw)->data_of_hw) + +#define set_hw_data(hw, value) \ +((hw)->data_of_hw = (value)) + + + +/* Perform a soft reset of the device */ + +typedef unsigned (hw_reset_method) + (struct hw *me); + +#define hw_reset(hw) ((hw)->to_reset (hw)) + +#define set_hw_reset(hw, method) \ +((hw)->to_reset = method) + + +/* Hardware operations: + + Connecting a parent to its children is a common bus. The parent + node is described as the bus owner and is responisble for + co-ordinating bus operations. On the bus, a SPACE:ADDR pair is used + to specify an address. A device that is both a bus owner (parent) + and bus client (child) are refered to as a bridging device. + + A child performing a data (DMA) transfer will pass its request to + the bus owner (the devices parent). The bus owner will then either + reflect the request to one of the other devices attached to the bus + (a child of the bus owner) or bridge the request up the tree to the + next bus. */ + + +/* Children attached to a bus can register (attach) themselves to + specific addresses on their attached bus. + + (A device may also be implicitly attached to certain bus + addresses). + + The SPACE:ADDR pair specify an address on the common bus that + connects the parent and child devices. */ + +typedef void (hw_attach_address_method) + (struct hw *me, + int level, + int space, + address_word addr, + address_word nr_bytes, + struct hw *client); /*callback/default*/ + +#define hw_attach_address(me, level, space, addr, nr_bytes, client) \ +((me)->to_attach_address (me, level, space, addr, nr_bytes, client)) + +#define set_hw_attach_address(hw, method) \ +((hw)->to_attach_address = (method)) + +typedef void (hw_detach_address_method) + (struct hw *me, + int level, + int space, + address_word addr, + address_word nr_bytes, + struct hw *client); /*callback/default*/ + +#define hw_detach_address(me, level, space, addr, nr_bytes, client) \ +((me)->to_detach_address (me, level, space, addr, nr_bytes, client)) + +#define set_hw_detach_address(hw, method) \ +((hw)->to_detach_address = (method)) + + +/* An IO operation from a parent to a child via the conecting bus. + + The SPACE:ADDR pair specify an address on the bus shared between + the parent and child devices. */ + +typedef unsigned (hw_io_read_buffer_method) + (struct hw *me, + void *dest, + int space, + unsigned_word addr, + unsigned nr_bytes); + +#define hw_io_read_buffer(hw, dest, space, addr, nr_bytes) \ +((hw)->to_io_read_buffer (hw, dest, space, addr, nr_bytes)) + +#define set_hw_io_read_buffer(hw, method) \ +((hw)->to_io_read_buffer = (method)) + +typedef unsigned (hw_io_write_buffer_method) + (struct hw *me, + const void *source, + int space, + unsigned_word addr, + unsigned nr_bytes); + +#define hw_io_write_buffer(hw, src, space, addr, nr_bytes) \ +((hw)->to_io_write_buffer (hw, src, space, addr, nr_bytes)) + +#define set_hw_io_write_buffer(hw, method) \ +((hw)->to_io_write_buffer = (method)) + + +/* Conversly, the device pci1000,1@1 may need to perform a dma transfer + into the cpu/memory core. Just as I/O moves towards the leaves, + dma transfers move towards the core via the initiating devices + parent nodes. The root device (special) converts the DMA transfer + into reads/writes to memory. + + The SPACE:ADDR pair specify an address on the common bus connecting + the parent and child devices. */ + +typedef unsigned (hw_dma_read_buffer_method) + (struct hw *bus, + void *dest, + int space, + unsigned_word addr, + unsigned nr_bytes); + +#define hw_dma_read_buffer(bus, dest, space, addr, nr_bytes) \ +((bus)->to_dma_read_buffer (bus, dest, space, addr, nr_bytes)) + +#define set_hw_dma_read_buffer(me, method) \ +((me)->to_dma_read_buffer = (method)) + +typedef unsigned (hw_dma_write_buffer_method) + (struct hw *bus, + const void *source, + int space, + unsigned_word addr, + unsigned nr_bytes, + int violate_read_only_section); + +#define hw_dma_write_buffer(bus, src, space, addr, nr_bytes, violate_ro) \ +((bus)->to_dma_write_buffer (bus, src, space, addr, nr_bytes, violate_ro)) + +#define set_hw_dma_write_buffer(me, method) \ +((me)->to_dma_write_buffer = (method)) + +/* Address/size specs for devices are encoded following a convention + similar to that used by OpenFirmware. In particular, an + address/size is packed into a sequence of up to four cell words. + The number of words determined by the number of {address,size} + cells attributes of the device. */ + +typedef struct _hw_unit { + int nr_cells; + unsigned_cell cells[4]; /* unused cells are zero */ +} hw_unit; + + +/* For the given bus, the number of address and size cells used in a + hw_unit. */ + +#define hw_unit_nr_address_cells(bus) ((bus)->nr_address_cells_of_hw_unit + 0) + +#define hw_unit_nr_size_cells(bus) ((bus)->nr_size_cells_of_hw_unit + 0) + + +/* For the given device, its identifying hw_unit address. + + Each device has an identifying hw_unit address. That address is + used when identifying one of a number of identical devices on a + common controller bus. ex fd0&fd1. */ + +const hw_unit *hw_unit_address +(struct hw *me); + + +/* Convert between a textual and the internal representation of a + hw_unit address/size. + + NOTE: A device asks its parent to translate between a hw_unit and + textual representation. This is because the textual address of a + device is specified using the parent busses notation. */ + +typedef int (hw_unit_decode_method) + (struct hw *bus, + const char *encoded, + hw_unit *unit); + +#define hw_unit_decode(bus, encoded, unit) \ +((bus)->to_unit_decode (bus, encoded, unit)) + +#define set_hw_unit_decode(hw, method) \ +((hw)->to_unit_decode = (method)) + +typedef int (hw_unit_encode_method) + (struct hw *bus, + const hw_unit *unit, + char *encoded, + int sizeof_buf); + +#define hw_unit_encode(bus, unit, encoded, sizeof_encoded) \ +((bus)->to_unit_encode (bus, unit, encoded, sizeof_encoded)) + +#define set_hw_unit_encode(hw, method) \ +((hw)->to_unit_encode = (method)) + + +/* As the bus that the device is attached too, to translate a devices + hw_unit address/size into a form suitable for an attach address + call. + + Return a zero result if the address should be ignored when looking + for attach addresses. */ + +typedef int (hw_unit_address_to_attach_address_method) + (struct hw *bus, + const hw_unit *unit_addr, + int *attach_space, + unsigned_word *attach_addr, + struct hw *client); + +#define hw_unit_address_to_attach_address(bus, unit_addr, attach_space, attach_addr, client) \ +((bus)->to_unit_address_to_attach_address (bus, unit_addr, attach_space, attach_addr, client)) + +#define set_hw_unit_address_to_attach_address(hw, method) \ +((hw)->to_unit_address_to_attach_address = (method)) + +typedef int (hw_unit_size_to_attach_size_method) + (struct hw *bus, + const hw_unit *unit_size, + unsigned *attach_size, + struct hw *client); + +#define hw_unit_size_to_attach_size(bus, unit_size, attach_size, client) \ +((bus)->to_unit_size_to_attach_size (bus, unit_size, attach_size, client)) + +#define set_hw_unit_size_to_attach_size(hw, method) \ +((hw)->to_unit_size_to_attach_size = (method)) + + +extern char *hw_strdup (struct hw *me, const char *str); + + +/* Utilities: + + */ + +/* IOCTL:: + + Often devices require `out of band' operations to be performed. + For instance a pal device may need to notify a PCI bridge device + that an interrupt ack cycle needs to be performed on the PCI bus. + Within PSIM such operations are performed by using the generic + ioctl call <<hw_ioctl()>>. + + */ + +typedef enum { + hw_ioctl_break, /* unsigned_word requested_break */ + hw_ioctl_set_trace, /* void */ + hw_ioctl_create_stack, /* unsigned_word *sp, char **argv, char **envp */ + hw_ioctl_change_media, /* const char *new_image (possibly NULL) */ + nr_hw_ioctl_requests, +} hw_ioctl_request; + +typedef int (hw_ioctl_method) + (struct hw *me, + hw_ioctl_request request, + va_list ap); + +int hw_ioctl +(struct hw *me, + hw_ioctl_request request, + ...); + + +/* Error reporting:: + + So that errors originating from devices appear in a consistent + format, the <<hw_abort()>> function can be used. Formats and + outputs the error message before aborting the simulation + + Devices should use this function to abort the simulation except + when the abort reason leaves the simulation in a hazardous + condition (for instance a failed malloc). + + */ + +void hw_abort +(struct hw *me, + const char *fmt, + ...) __attribute__ ((format (printf, 2, 3))); + +void hw_vabort +(struct hw *me, + const char *fmt, + va_list ap); + +void hw_halt +(struct hw *me, + int reason, + int status); + + +#define hw_trace_p(hw) ((hw)->trace_of_hw_p + 0) + +void hw_trace +(struct hw *me, + const char *fmt, + ...) __attribute__ ((format (printf, 2, 3))); + +#define HW_TRACE(ARGS) \ +do { \ + if (hw_trace_p (me)) \ + { \ + hw_trace ARGS; \ + } \ +} while (0) + + +/* Some of the related functions require specific types */ + +struct hw_property_data; +struct hw_port_data; +struct hw_base_data; +struct hw_alloc_data; +struct hw_event_data; +struct hw_handle_data; +struct hw_instance_data; + +/* Finally the hardware device - keep your grubby little mits off of + these internals! :-) */ + +struct hw { + + /* our relatives */ + struct hw *parent_of_hw; + struct hw *sibling_of_hw; + struct hw *child_of_hw; + + /* our identity */ + const char *name_of_hw; + const char *family_of_hw; + const char *args_of_hw; + const char *path_of_hw; + + /* our data */ + void *data_of_hw; + + /* hot links */ + struct hw *root_of_hw; + struct sim_state *system_of_hw; + + /* identifying data */ + hw_unit unit_address_of_hw; + int nr_address_cells_of_hw_unit; + int nr_size_cells_of_hw_unit; + + /* Soft reset */ + hw_reset_method *to_reset; + + /* Basic callbacks */ + hw_io_read_buffer_method *to_io_read_buffer; + hw_io_write_buffer_method *to_io_write_buffer; + hw_dma_read_buffer_method *to_dma_read_buffer; + hw_dma_write_buffer_method *to_dma_write_buffer; + hw_attach_address_method *to_attach_address; + hw_detach_address_method *to_detach_address; + + /* More complicated callbacks */ + hw_ioctl_method *to_ioctl; + int trace_of_hw_p; + + /* address callbacks */ + hw_unit_decode_method *to_unit_decode; + hw_unit_encode_method *to_unit_encode; + hw_unit_address_to_attach_address_method *to_unit_address_to_attach_address; + hw_unit_size_to_attach_size_method *to_unit_size_to_attach_size; + + /* related data */ + struct hw_property_data *properties_of_hw; + struct hw_port_data *ports_of_hw; + struct hw_base_data *base_of_hw; + struct hw_alloc_data *alloc_of_hw; + struct hw_event_data *events_of_hw; + struct hw_handle_data *handles_of_hw; + struct hw_instance_data *instances_of_hw; + +}; + + +#endif diff --git a/sim/common/hw-events.c b/sim/common/hw-events.c new file mode 100644 index 0000000..31c5a40 --- /dev/null +++ b/sim/common/hw-events.c @@ -0,0 +1,263 @@ +/* Hardware event manager. + Copyright (C) 1998 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +#include "hw-main.h" +#include "hw-base.h" + +#include "sim-events.h" + + +/* The hw-events object is implemented using sim-events */ + +struct hw_event { + void *data; + struct hw *me; + hw_event_callback *callback; + sim_event *real; + struct hw_event_data *entry; +}; + +struct hw_event_data { + struct hw_event event; + struct hw_event_data *next; +}; + +void +create_hw_event_data (struct hw *me) +{ + if (me->events_of_hw != NULL) + hw_abort (me, "stray events"); + /* NOP */ +} + +void +delete_hw_event_data (struct hw *me) +{ + if (me->events_of_hw != NULL) + hw_abort (me, "stray events"); +} + + +/* Pass the H/W event onto the real callback */ + +static void +bounce_hw_event (SIM_DESC sd, + void *data) +{ + /* save the data */ + struct hw_event_data *entry = (struct hw_event_data *) data; + struct hw *me = entry->event.me; + void *event_data = entry->event.data; + hw_event_callback *callback = entry->event.callback; + struct hw_event_data **prev = &me->events_of_hw; + while ((*prev) != entry) + prev = &(*prev)->next; + (*prev) = entry->next; + hw_free (me, entry); + callback (me, event_data); /* may not return */ +} + + + +/* Map onto the event functions */ + +struct hw_event * +hw_event_queue_schedule (struct hw *me, + signed64 delta_time, + hw_event_callback *callback, + void *data) +{ + struct hw_event *event; + va_list dummy; + event = hw_event_queue_schedule_vtracef (me, delta_time, callback, data, + NULL, dummy); + return event; +} + +struct hw_event * +hw_event_queue_schedule_tracef (struct hw *me, + signed64 delta_time, + hw_event_callback *callback, + void *data, + const char *fmt, + ...) +{ + struct hw_event *event; + va_list ap; + va_start (ap, fmt); + event = hw_event_queue_schedule_vtracef (me, delta_time, callback, data, fmt, ap); + va_end (ap); + return event; +} + +struct hw_event * +hw_event_queue_schedule_vtracef (struct hw *me, + signed64 delta_time, + hw_event_callback *callback, + void *data, + const char *fmt, + va_list ap) +{ + struct hw_event_data *entry = HW_ZALLOC (me, struct hw_event_data); + entry->next = me->events_of_hw; + me->events_of_hw = entry; + /* fill it in */ + entry->event.entry = entry; + entry->event.data = data; + entry->event.callback = callback; + entry->event.me = me; + entry->event.real = sim_events_schedule_vtracef (hw_system (me), + delta_time, + bounce_hw_event, + entry, + fmt, ap); + return &entry->event; +} + + +void +hw_event_queue_deschedule (struct hw *me, + struct hw_event *event_to_remove) +{ +/* ZAP the event but only if it is still in the event queue. Note + that event_to_remove is only de-referenced after its validity has + been confirmed. */ + struct hw_event_data **prev; + for (prev = &me->events_of_hw; + (*prev) != NULL; + prev = &(*prev)->next) + { + struct hw_event_data *entry = (*prev); + if (&entry->event == event_to_remove) + { + sim_events_deschedule (hw_system (me), + entry->event.real); + (*prev) = entry->next; + hw_free (me, entry); + return; + } + } +} + + +signed64 +hw_event_queue_time (struct hw *me) +{ + return sim_events_time (hw_system (me)); +} + + +/* Only worry about this compling on ANSI systems. + Build with `make test-hw-events' in sim/<cpu> directory*/ + +#if defined (MAIN) +#include "sim-main.h" +#include <string.h> +#include <stdio.h> + +static void +test_handler (struct hw *me, + void *data) +{ + int *n = data; + if (*n != hw_event_queue_time (me)) + abort (); + *n = -(*n); +} + +int +main (int argc, + char **argv) +{ + host_callback *cb = ZALLOC (host_callback); + struct sim_state *sd = sim_state_alloc (0, cb); + struct hw *me = ZALLOC (struct hw); + sim_pre_argv_init (sd, "test-hw-events"); + sim_post_argv_init (sd); + me->system_of_hw = sd; + + printf ("Create hw-event-data\n"); + { + create_hw_alloc_data (me); + create_hw_event_data (me); + delete_hw_event_data (me); + delete_hw_alloc_data (me); + } + + printf ("Create hw-events\n"); + { + struct hw_event *a; + struct hw_event *b; + struct hw_event *c; + struct hw_event *d; + create_hw_alloc_data (me); + create_hw_event_data (me); + a = hw_event_queue_schedule (me, 0, NULL, NULL); + b = hw_event_queue_schedule (me, 1, NULL, NULL); + c = hw_event_queue_schedule (me, 2, NULL, NULL); + d = hw_event_queue_schedule (me, 1, NULL, NULL); + hw_event_queue_deschedule (me, c); + hw_event_queue_deschedule (me, b); + hw_event_queue_deschedule (me, a); + hw_event_queue_deschedule (me, d); + c = HW_ZALLOC (me, struct hw_event); + hw_event_queue_deschedule (me, b); /* OOPS! */ + hw_free (me, c); + delete_hw_event_data (me); + delete_hw_alloc_data (me); + } + + printf ("Schedule hw-events\n"); + { + struct hw_event **e; + int *n; + int i; + int nr = 4; + e = HW_NZALLOC (me, struct hw_event *, nr); + n = HW_NZALLOC (me, int, nr); + create_hw_alloc_data (me); + create_hw_event_data (me); + for (i = 0; i < nr; i++) + { + n[i] = i; + e[i] = hw_event_queue_schedule (me, i, test_handler, &n[i]); + } + sim_events_preprocess (sd, 1, 1); + for (i = 0; i < nr; i++) + { + if (sim_events_tick (sd)) + sim_events_process (sd); + } + for (i = 0; i < nr; i++) + { + if (n[i] != -i) + abort (); + hw_event_queue_deschedule (me, e[i]); + } + hw_free (me, n); + hw_free (me, e); + delete_hw_event_data (me); + delete_hw_alloc_data (me); + } + + return 0; +} +#endif diff --git a/sim/common/hw-events.h b/sim/common/hw-events.h new file mode 100644 index 0000000..a9b6f8b --- /dev/null +++ b/sim/common/hw-events.h @@ -0,0 +1,61 @@ +/* Hardware event manager. + Copyright (C) 1998 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef HW_EVENTS_H +#define HW_EVENTS_H + +/* Event manager customized for hardware models. + + This interface is discussed further in sim-events.h. */ + +struct hw_event; +typedef void (hw_event_callback) (struct hw *me, void *data); + +struct hw_event *hw_event_queue_schedule +(struct hw *me, + signed64 delta_time, + hw_event_callback *handler, + void *data); + +struct hw_event *hw_event_queue_schedule_tracef +(struct hw *me, + signed64 delta_time, + hw_event_callback *handler, + void *data, + const char *fmt, + ...) __attribute__ ((format (printf, 5, 6))); + +struct hw_event *hw_event_queue_schedule_vtracef +(struct hw *me, + signed64 delta_time, + hw_event_callback *handler, + void *data, + const char *fmt, + va_list ap); + + +void hw_event_queue_deschedule +(struct hw *me, + struct hw_event *event_to_remove); + +signed64 hw_event_queue_time +(struct hw *me); + +#endif diff --git a/sim/common/hw-handles.c b/sim/common/hw-handles.c new file mode 100644 index 0000000..9400ca8 --- /dev/null +++ b/sim/common/hw-handles.c @@ -0,0 +1,237 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995,1997-1998, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#include "hw-main.h" +#include "hw-base.h" + + +struct hw_handle_mapping { + cell_word external; + struct hw *phandle; + struct hw_instance *ihandle; + struct hw_handle_mapping *next; +}; + + +struct hw_handle_data { + int nr_mappings; + struct hw_handle_mapping *mappings; +}; + +void +create_hw_handle_data (struct hw *hw) +{ + if (hw_parent (hw) == NULL) + { + hw->handles_of_hw = HW_ZALLOC (hw, struct hw_handle_data); + } + else + { + hw->handles_of_hw = hw_root (hw)->handles_of_hw; + } +} + +void +delete_hw_handle_data (struct hw *hw) +{ + /* NULL */ +} + + + +#if 0 +void +hw_handle_init (struct hw *hw) +{ + struct hw_handle_mapping *current_map = db->mappings; + if (current_map != NULL) + { + db->nr_mappings = db->mappings->external; + /* verify that the mappings that were not removed are in + sequence down to nr 1 */ + while (current_map->next != NULL) + { + if (current_map->external != current_map->next->external + 1) + error ("hw_handle: hw_handle database possibly corrupt"); + current_map = current_map->next; + } + ASSERT (current_map->next == NULL); + if (current_map->external != 1) + error ("hw_handle: hw_handle database possibly corrupt"); + } + else + { + db->nr_mappings = 0; + } +} +#endif + + +struct hw_instance * +hw_handle_ihandle2 (struct hw *hw, + cell_word external) +{ + struct hw_handle_data *db = hw->handles_of_hw; + struct hw_handle_mapping *current_map = db->mappings; + while (current_map != NULL) + { + if (current_map->external == external) + return current_map->ihandle; + current_map = current_map->next; + } + return (void*)0; +} + + +struct hw * +hw_handle_phandle2 (struct hw *hw, + cell_word external) +{ + struct hw_handle_data *db = hw->handles_of_hw; + struct hw_handle_mapping *current_map = db->mappings; + while (current_map != NULL) + { + if (current_map->external == external) + return current_map->phandle; + current_map = current_map->next; + } + return (void*)0; +} + + +cell_word +hw_handle_2ihandle (struct hw *hw, + struct hw_instance *internal) +{ + struct hw_handle_data *db = hw->handles_of_hw; + struct hw_handle_mapping *current_map = db->mappings; + while (current_map != NULL) + { + if (current_map->ihandle == internal) + return current_map->external; + current_map = current_map->next; + } + return 0; +} + + +cell_word +hw_handle_2phandle (struct hw *hw, + struct hw *internal) +{ + struct hw_handle_data *db = hw->handles_of_hw; + struct hw_handle_mapping *current_map = db->mappings; + while (current_map != NULL) + { + if (current_map->phandle == internal) + return current_map->external; + current_map = current_map->next; + } + return 0; +} + + +void +hw_handle_add_ihandle (struct hw *hw, + struct hw_instance *internal) +{ + struct hw_handle_data *db = hw->handles_of_hw; + if (hw_handle_2ihandle (hw, internal) != 0) + { + hw_abort (hw, "attempting to add an ihandle already in the data base"); + } + else + { + /* insert at the front making things in decending order */ + struct hw_handle_mapping *new_map = ZALLOC (struct hw_handle_mapping); + new_map->next = db->mappings; + new_map->ihandle = internal; + db->nr_mappings += 1; + new_map->external = db->nr_mappings; + db->mappings = new_map; + } +} + + +void +hw_handle_add_phandle (struct hw *hw, + struct hw *internal) +{ + struct hw_handle_data *db = hw->handles_of_hw; + if (hw_handle_2phandle (hw, internal) != 0) + { + hw_abort (hw, "attempting to add a phandle already in the data base"); + } + else + { + /* insert at the front making things in decending order */ + struct hw_handle_mapping *new_map = ZALLOC (struct hw_handle_mapping); + new_map->next = db->mappings; + new_map->phandle = internal; + db->nr_mappings += 1; + new_map->external = db->nr_mappings; + db->mappings = new_map; + } +} + + +void +hw_handle_remove_ihandle (struct hw *hw, + struct hw_instance *internal) +{ + struct hw_handle_data *db = hw->handles_of_hw; + struct hw_handle_mapping **current_map = &db->mappings; + while (*current_map != NULL) + { + if ((*current_map)->ihandle == internal) + { + struct hw_handle_mapping *delete = *current_map; + *current_map = delete->next; + zfree (delete); + return; + } + current_map = &(*current_map)->next; + } + hw_abort (hw, "attempt to remove nonexistant ihandle"); +} + + +void +hw_handle_remove_phandle (struct hw *hw, + struct hw *internal) +{ + struct hw_handle_data *db = hw->handles_of_hw; + struct hw_handle_mapping **current_map = &db->mappings; + while (*current_map != NULL) + { + if ((*current_map)->phandle == internal) + { + struct hw_handle_mapping *delete = *current_map; + *current_map = delete->next; + zfree (delete); + return; + } + current_map = &(*current_map)->next; + } + hw_abort (hw, "attempt to remove nonexistant phandle"); +} + + diff --git a/sim/common/hw-handles.h b/sim/common/hw-handles.h new file mode 100644 index 0000000..087c9d02 --- /dev/null +++ b/sim/common/hw-handles.h @@ -0,0 +1,63 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995,1997-1998, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef HW_HANDLES_H +#define HW_HANDLES_H + + +/* Export a capability (handle) data base that maps between internal + data values and those given to a simulation. */ + + +cell_word hw_handle_2ihandle +(struct hw *db, + struct hw_instance *instance); + +struct hw_instance *hw_handle_ihandle2 +(struct hw *db, + cell_word external); + +void hw_handle_add_ihandle +(struct hw *db, + struct hw_instance *instance); + +void hw_handle_remove_ihandle +(struct hw *db, + struct hw_instance *instance); + + +cell_word hw_handle_2phandle +(struct hw *db, + struct hw *hw); + +struct hw *hw_handle_phandle2 +(struct hw *db, + cell_word external); + +void hw_handle_add_phandle +(struct hw *db, + struct hw *hw); + +void hw_handle_remove_phandle +(struct hw *db, + struct hw *hw); + +#endif diff --git a/sim/common/hw-instances.c b/sim/common/hw-instances.c new file mode 100644 index 0000000..613f819 --- /dev/null +++ b/sim/common/hw-instances.c @@ -0,0 +1,285 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1998, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#include "hw-main.h" +#include "hw-base.h" + +#include "sim-assert.h" + +struct hw_instance_data { + hw_finish_instance_method *to_finish; + struct hw_instance *instances; +}; + +static hw_finish_instance_method abort_hw_finish_instance; + +void +create_hw_instance_data (struct hw *me) +{ + me->instances_of_hw = HW_ZALLOC (me, struct hw_instance_data); + set_hw_finish_instance (me, abort_hw_finish_instance); +} + +void +delete_hw_instance_data (struct hw *me) +{ + /* NOP */ +} + + +static void +abort_hw_finish_instance (struct hw *hw, + struct hw_instance *instance) +{ + hw_abort (hw, "no instance finish method"); +} + +void +set_hw_finish_instance (struct hw *me, + hw_finish_instance_method *finish) +{ + me->instances_of_hw->to_finish = finish; +} + + +#if 0 +void +clean_hw_instances (struct hw *me) +{ + struct hw_instance **instance = &me->instances; + while (*instance != NULL) + { + struct hw_instance *old_instance = *instance; + hw_instance_delete (old_instance); + instance = &me->instances; + } +} +#endif + + +void +hw_instance_delete (struct hw_instance *instance) +{ +#if 1 + hw_abort (hw_instance_hw (instance), "not implemented"); +#else + struct hw *me = hw_instance_hw (instance); + if (instance->to_instance_delete == NULL) + hw_abort (me, "no delete method"); + instance->method->delete(instance); + if (instance->args != NULL) + zfree (instance->args); + if (instance->path != NULL) + zfree (instance->path); + if (instance->child == NULL) + { + /* only remove leaf nodes */ + struct hw_instance **curr = &me->instances; + while (*curr != instance) + { + ASSERT (*curr != NULL); + curr = &(*curr)->next; + } + *curr = instance->next; + } + else + { + /* check it isn't in the instance list */ + struct hw_instance *curr = me->instances; + while (curr != NULL) + { + ASSERT(curr != instance); + curr = curr->next; + } + /* unlink the child */ + ASSERT (instance->child->parent == instance); + instance->child->parent = NULL; + } + cap_remove (me->ihandles, instance); + zfree (instance); +#endif +} + + +static int +panic_hw_instance_read (struct hw_instance *instance, + void *addr, + unsigned_word len) +{ + hw_abort (hw_instance_hw (instance), "no read method"); + return -1; +} + + + +static int +panic_hw_instance_write (struct hw_instance *instance, + const void *addr, + unsigned_word len) +{ + hw_abort (hw_instance_hw (instance), "no write method"); + return -1; +} + + +static int +panic_hw_instance_seek (struct hw_instance *instance, + unsigned_word pos_hi, + unsigned_word pos_lo) +{ + hw_abort (hw_instance_hw (instance), "no seek method"); + return -1; +} + + +int +hw_instance_call_method (struct hw_instance *instance, + const char *method_name, + int n_stack_args, + unsigned_cell stack_args[/*n_stack_args*/], + int n_stack_returns, + unsigned_cell stack_returns[/*n_stack_args*/]) +{ +#if 1 + hw_abort (hw_instance_hw (instance), "not implemented"); + return -1; +#else + struct hw *me = instance->owner; + const hw_instance_methods *method = instance->method->methods; + if (method == NULL) + { + hw_abort (me, "no methods (want %s)", method_name); + } + while (method->name != NULL) + { + if (strcmp(method->name, method_name) == 0) + { + return method->method (instance, + n_stack_args, stack_args, + n_stack_returns, stack_returns); + } + method++; + } + hw_abort (me, "no %s method", method_name); + return 0; +#endif +} + + +#define set_hw_instance_read(instance, method)\ +((instance)->to_instance_read = (method)) + +#define set_hw_instance_write(instance, method)\ +((instance)->to_instance_write = (method)) + +#define set_hw_instance_seek(instance, method)\ +((instance)->to_instance_seek = (method)) + + +#if 0 +static void +set_hw_instance_finish (struct hw *me, + hw_instance_finish_method *method) +{ + if (me->instances_of_hw == NULL) + me->instances_of_hw = HW_ZALLOC (me, struct hw_instance_data); + me->instances_of_hw->to_finish = method; +} +#endif + + +struct hw_instance * +hw_instance_create (struct hw *me, + struct hw_instance *parent, + const char *path, + const char *args) +{ + struct hw_instance *instance = ZALLOC (struct hw_instance); + /*instance->unit*/ + /* link this instance into the devices list */ + instance->hw_of_instance = me; + instance->parent_of_instance = NULL; + /* link this instance into the front of the devices instance list */ + instance->sibling_of_instance = me->instances_of_hw->instances; + me->instances_of_hw->instances = instance; + if (parent != NULL) + { + ASSERT (parent->child_of_instance == NULL); + parent->child_of_instance = instance; + instance->parent_of_instance = parent; + } + instance->args_of_instance = hw_strdup (me, args); + instance->path_of_instance = hw_strdup (me, path); + set_hw_instance_read (instance, panic_hw_instance_read); + set_hw_instance_write (instance, panic_hw_instance_write); + set_hw_instance_seek (instance, panic_hw_instance_seek); + hw_handle_add_ihandle (me, instance); + me->instances_of_hw->to_finish (me, instance); + return instance; +} + + +struct hw_instance * +hw_instance_interceed (struct hw_instance *parent, + const char *path, + const char *args) +{ +#if 1 + return NULL; +#else + struct hw_instance *instance = ZALLOC (struct hw_instance); + /*instance->unit*/ + /* link this instance into the devices list */ + if (me != NULL) + { + ASSERT (parent == NULL); + instance->hw_of_instance = me; + instance->parent_of_instance = NULL; + /* link this instance into the front of the devices instance list */ + instance->sibling_of_instance = me->instances_of_hw->instances; + me->instances_of_hw->instances = instance; + } + if (parent != NULL) + { + struct hw_instance **previous; + ASSERT (parent->child_of_instance == NULL); + parent->child_of_instance = instance; + instance->owner = parent->owner; + instance->parent_of_instance = parent; + /* in the devices instance list replace the parent instance with + this one */ + instance->next = parent->next; + /* replace parent with this new node */ + previous = &instance->owner->instances; + while (*previous != parent) + { + ASSERT (*previous != NULL); + previous = &(*previous)->next; + } + *previous = instance; + } + instance->data = data; + instance->args = (args == NULL ? NULL : (char *) strdup(args)); + instance->path = (path == NULL ? NULL : (char *) strdup(path)); + cap_add (instance->owner->ihandles, instance); + return instance; +#endif +} diff --git a/sim/common/hw-instances.h b/sim/common/hw-instances.h new file mode 100644 index 0000000..6d27b11 --- /dev/null +++ b/sim/common/hw-instances.h @@ -0,0 +1,157 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1998, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef HW_INSTANCES_H +#define HW_INSTANCES_H + +/* Instances: + + As with IEEE1275, a device can be opened, creating an instance. + Instances provide more abstract interfaces to the underlying + hardware. For example, the instance methods for a disk may include + code that is able to interpret file systems found on disks. Such + methods would there for allow the manipulation of files on the + disks file system. The operations would be implemented using the + basic block I/O model provided by the disk. + + This model includes methods that faciliate the creation of device + instance and (should a given device support it) standard operations + on those instances. + + */ + + +struct hw_instance; + + +typedef void (hw_finish_instance_method) + (struct hw *hw, + struct hw_instance *); + +extern void set_hw_finish_instance +(struct hw *hw, + hw_finish_instance_method *method); + + +/* construct an instance of the hardware */ + +struct hw_instance *hw_instance_create +(struct hw *hw, + struct hw_instance *parent, + const char *path, + const char *args); + +struct hw_instance *hw_instance_interceed +(struct hw_instance *parent, + const char *path, + const char *args); + +void hw_instance_delete +(struct hw_instance *instance); + + +/* methods applied to an instance of the hw */ + +typedef int (hw_instance_read_method) + (struct hw_instance *instance, + void *addr, + unsigned_cell len); + +#define hw_instance_read(instance, addr, len) \ +((instance)->to_instance_read ((instance), (addr), (len))) + +#define set_hw_instance_read(instance, method) \ +((instance)->to_instance_read = (method)) + + +typedef int (hw_instance_write_method) + (struct hw_instance *instance, + const void *addr, + unsigned_cell len); + +#define hw_instance_write(instance, addr, len) \ +((instance)->to_instance_write ((instance), (addr), (len))) + +#define set_hw_instance_write(instance, method) \ +((instance)->to_instance_write = (method)) + + +typedef int (hw_instance_seek_method) + (struct hw_instance *instance, + unsigned_cell pos_hi, + unsigned_cell pos_lo); + +#define hw_instance_seek(instance, pos_hi, pos_lo) \ +((instance)->to_instance_seek ((instance), (pos_hi), (pos_lo))); + +#define set_hw_instance_seek(instance, method) \ +((instance)->to_instance_seek = (method)) + + +int hw_instance_call_method +(struct hw_instance *instance, + const char *method, + int n_stack_args, + unsigned_cell stack_args[/*n_stack_args + 1(NULL)*/], + int n_stack_returns, + unsigned_cell stack_returns[/*n_stack_returns + 1(NULL)*/]); + + + +/* the definition of the instance */ + +#define hw_instance_hw(instance) ((instance)->hw_of_instance + 0) + +#define hw_instance_path(instance) ((instance)->path_of_instance + 0) + +#define hw_instance_args(instance) ((instance)->args_of_instance) + +#define hw_instance_data(instance) ((instance)->data_of_instance) + +#define hw_instance_system(instance) (hw_system (hw_instance_hw (instance))) + + + +/* Finally an instance of a hardware device - keep your grubby little + mits off of these internals! :-) */ + +struct hw_instance { + + void *data_of_instance; + char *args_of_instance; + char *path_of_instance; + + /* the device that owns the instance */ + struct hw *hw_of_instance; + struct hw_instance *sibling_of_instance; + + /* interposed instance */ + struct hw_instance *parent_of_instance; + struct hw_instance *child_of_instance; + + /* methods */ + hw_instance_read_method *to_instance_read; + hw_instance_write_method *to_instance_write; + hw_instance_seek_method *to_instance_seek; + +}; + +#endif diff --git a/sim/common/hw-main.h b/sim/common/hw-main.h new file mode 100644 index 0000000..3c086c1 --- /dev/null +++ b/sim/common/hw-main.h @@ -0,0 +1,73 @@ +/* Common hardware header file. + Copyright (C) 1998 Free Software Foundation, Inc. + Contributed by Andrew Cagney and Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +#ifndef HW_MAIN +#define HW_MAIN + +/* establish a type system */ +#include "sim-basics.h" + +/* construct a hw device */ +#include "hw-device.h" +#include "hw-properties.h" +#include "hw-events.h" +#include "hw-alloc.h" +#include "hw-instances.h" +#include "hw-handles.h" +#include "hw-ports.h" + +/* Description of a hardware device */ + +typedef void (hw_finish_method) + (struct hw *me); + +struct hw_descriptor { + const char *family; + hw_finish_method *to_finish; +}; + +/* Helper functions to make the implementation of a device easier */ + +/* Go through the devices reg properties and look for those specifying + an address to attach various registers to */ + +void do_hw_attach_regs (struct hw *me); + +/* Perform a polling read on FD returning either the number of bytes + or a hw_io status code that indicates the reason for the read + failure */ + +enum { + HW_IO_EOF = -1, HW_IO_NOT_READY = -2, /* See: IEEE 1275 */ +}; + +typedef int (do_hw_poll_read_method) + (SIM_DESC sd, int, char *, int); + +int do_hw_poll_read +(struct hw *me, + do_hw_poll_read_method *read, + int sim_io_fd, + void *buf, + unsigned size_of_buf); + + +#endif diff --git a/sim/common/hw-ports.c b/sim/common/hw-ports.c new file mode 100644 index 0000000..b7dc985 --- /dev/null +++ b/sim/common/hw-ports.c @@ -0,0 +1,339 @@ +/* Hardware ports. + Copyright (C) 1998 Free Software Foundation, Inc. + Contributed by Andrew Cagney and Cygnus Solutions. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +#include "hw-main.h" +#include "hw-base.h" + +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif + +#ifdef HAVE_STRING_H +#include <string.h> +#else +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#endif + +#include <ctype.h> + +#define TRACE(x,y) + + +struct hw_port_edge { + int my_port; + struct hw *dest; + int dest_port; + struct hw_port_edge *next; + object_disposition disposition; +}; + +struct hw_port_data { + hw_port_event_method *to_port_event; + const struct hw_port_descriptor *ports; + struct hw_port_edge *edges; +}; + +const struct hw_port_descriptor empty_hw_ports[] = { + { NULL, }, +}; + +static void +panic_hw_port_event (struct hw *me, + int my_port, + struct hw *source, + int source_port, + int level) +{ + hw_abort (me, "no port method"); +} + +void +create_hw_port_data (struct hw *me) +{ + me->ports_of_hw = HW_ZALLOC (me, struct hw_port_data); + set_hw_port_event (me, panic_hw_port_event); + set_hw_ports (me, empty_hw_ports); +} + +void +delete_hw_port_data (struct hw *me) +{ + hw_free (me, me->ports_of_hw); + me->ports_of_hw = NULL; +} + +void +set_hw_ports (struct hw *me, + const struct hw_port_descriptor ports[]) +{ + me->ports_of_hw->ports = ports; +} + +void +set_hw_port_event (struct hw *me, + hw_port_event_method *port_event) +{ + me->ports_of_hw->to_port_event = port_event; +} + + +static void +attach_hw_port_edge (struct hw *me, + struct hw_port_edge **list, + int my_port, + struct hw *dest, + int dest_port, + object_disposition disposition) +{ + struct hw_port_edge *new_edge = HW_ZALLOC (me, struct hw_port_edge); + new_edge->my_port = my_port; + new_edge->dest = dest; + new_edge->dest_port = dest_port; + new_edge->next = *list; + new_edge->disposition = disposition; + *list = new_edge; +} + + +static void +detach_hw_port_edge (struct hw *me, + struct hw_port_edge **list, + int my_port, + struct hw *dest, + int dest_port) +{ + while (*list != NULL) + { + struct hw_port_edge *old_edge = *list; + if (old_edge->dest == dest + && old_edge->dest_port == dest_port + && old_edge->my_port == my_port) + { + if (old_edge->disposition == permenant_object) + hw_abort (me, "attempt to delete permenant port edge"); + *list = old_edge->next; + hw_free (me, old_edge); + return; + } + } + hw_abort (me, "attempt to delete unattached port"); +} + + +#if 0 +static void +clean_hw_port_edges (struct hw_port_edge **list) +{ + while (*list != NULL) + { + struct hw_port_edge *old_edge = *list; + switch (old_edge->disposition) + { + case permenant_object: + list = &old_edge->next; + break; + case temporary_object: + *list = old_edge->next; + hw_free (me, old_edge); + break; + } + } +} +#endif + + +/* Ports: */ + +void +hw_port_event (struct hw *me, + int my_port, + int level) +{ + int found_an_edge = 0; + struct hw_port_edge *edge; + /* device's lines directly connected */ + for (edge = me->ports_of_hw->edges; + edge != NULL; + edge = edge->next) + { + if (edge->my_port == my_port) + { + edge->dest->ports_of_hw->to_port_event (edge->dest, + edge->dest_port, + me, + my_port, + level); + found_an_edge = 1; + } + } + if (!found_an_edge) + hw_abort (me, "No edge for port %d", my_port); +} + + +void +hw_port_attach (struct hw *me, + int my_port, + struct hw *dest, + int dest_port, + object_disposition disposition) +{ + attach_hw_port_edge (me, + &me->ports_of_hw->edges, + my_port, + dest, + dest_port, + disposition); +} + + +void +hw_port_detach (struct hw *me, + int my_port, + struct hw *dest, + int dest_port) +{ + detach_hw_port_edge (me, + &me->ports_of_hw->edges, + my_port, + dest, + dest_port); +} + + +void +hw_port_traverse (struct hw *me, + hw_port_traverse_function *handler, + void *data) +{ + struct hw_port_edge *port_edge; + for (port_edge = me->ports_of_hw->edges; + port_edge != NULL; + port_edge = port_edge->next) + { + handler (me, port_edge->my_port, + port_edge->dest, port_edge->dest_port, + data); + } +} + + +int +hw_port_decode (struct hw *me, + const char *port_name, + port_direction direction) +{ + if (port_name == NULL || port_name[0] == '\0') + return 0; + if (isdigit(port_name[0])) + { + return strtoul (port_name, NULL, 0); + } + else + { + const struct hw_port_descriptor *ports = + me->ports_of_hw->ports; + if (ports != NULL) + { + while (ports->name != NULL) + { + if (ports->direction == bidirect_port + || ports->direction == direction) + { + if (ports->nr_ports > 0) + { + int len = strlen (ports->name); + if (strncmp (port_name, ports->name, len) == 0) + { + if (port_name[len] == '\0') + return ports->number; + else if(isdigit (port_name[len])) + { + int port = (ports->number + + strtoul (&port_name[len], NULL, 0)); + if (port >= ports->number + ports->nr_ports) + hw_abort (me, + "Port %s out of range", + port_name); + return port; + } + } + } + else if (strcmp (port_name, ports->name) == 0) + return ports->number; + } + ports++; + } + } + } + hw_abort (me, "Unreconized port %s", port_name); + return 0; +} + + +int +hw_port_encode (struct hw *me, + int port_number, + char *buf, + int sizeof_buf, + port_direction direction) +{ + const struct hw_port_descriptor *ports = NULL; + ports = me->ports_of_hw->ports; + if (ports != NULL) { + while (ports->name != NULL) + { + if (ports->direction == bidirect_port + || ports->direction == direction) + { + if (ports->nr_ports > 0) + { + if (port_number >= ports->number + && port_number < ports->number + ports->nr_ports) + { + strcpy (buf, ports->name); + sprintf (buf + strlen(buf), "%d", port_number - ports->number); + if (strlen (buf) >= sizeof_buf) + hw_abort (me, "hw_port_encode: buffer overflow"); + return strlen (buf); + } + } + else + { + if (ports->number == port_number) + { + if (strlen(ports->name) >= sizeof_buf) + hw_abort (me, "hw_port_encode: buffer overflow"); + strcpy(buf, ports->name); + return strlen(buf); + } + } + } + ports++; + } + } + sprintf (buf, "%d", port_number); + if (strlen(buf) >= sizeof_buf) + hw_abort (me, "hw_port_encode: buffer overflow"); + return strlen(buf); +} diff --git a/sim/common/hw-ports.h b/sim/common/hw-ports.h new file mode 100644 index 0000000..566895a --- /dev/null +++ b/sim/common/hw-ports.h @@ -0,0 +1,129 @@ +/* Hardware ports. + Copyright (C) 1998 Free Software Foundation, Inc. + Contributed by Andrew Cagney and Cygnus Solutions. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +#ifndef HW_PORTS_H +#define HW_PORTS_H + +/* Initialize a port */ + +struct hw_port_descriptor { + const char *name; + int number; + int nr_ports; + port_direction direction; +}; + +void set_hw_ports (struct hw *hw, const struct hw_port_descriptor ports[]); + +typedef void (hw_port_event_method) + (struct hw *me, + int my_port, + struct hw *source, + int source_port, + int level); + +void set_hw_port_event (struct hw *hw, hw_port_event_method *to_port_event); + + +/* Port source + + A device drives its output ports using the call + + */ + +void hw_port_event +(struct hw *me, + int my_port, + int value); + +/* This port event will then be propogated to any attached + destination ports. + + Any interpretation of PORT and VALUE is model dependant. As a + guideline the following are recommended: PCI interrupts A-D should + correspond to ports 0-3; level sensative interrupts be requested + with a value of one and withdrawn with a value of 0; edge sensative + interrupts always have a value of 1, the event its self is treated + as the interrupt. + + + Port destinations + + Attached to each port of a device can be zero or more + desitinations. These destinations consist of a device/port pair. + A destination is attached/detached to a device line using the + attach and detach calls. */ + +void hw_port_attach +(struct hw *me, + int my_port, + struct hw *dest, + int dest_port, + object_disposition disposition); + +void hw_port_detach +(struct hw *me, + int my_port, + struct hw *dest, + int dest_port); + + +/* Iterate over the list of ports attached to a device */ + +typedef void (hw_port_traverse_function) + (struct hw *me, + int my_port, + struct hw *dest, + int dest_port, + void *data); + +void hw_port_traverse +(struct hw *me, + hw_port_traverse_function *handler, + void *data); + + +/* DESTINATION is attached (detached) to LINE of the device ME + + + Port conversion + + Users refer to port numbers symbolically. For instance a device + may refer to its `INT' signal which is internally represented by + port 3. + + To convert to/from the symbolic and internal representation of a + port name/number. The following functions are available. */ + +int hw_port_decode +(struct hw *me, + const char *symbolic_name, + port_direction direction); + +int hw_port_encode +(struct hw *me, + int port_number, + char *buf, + int sizeof_buf, + port_direction direction); + + +#endif diff --git a/sim/common/hw-properties.c b/sim/common/hw-properties.c new file mode 100644 index 0000000..a1e9291 --- /dev/null +++ b/sim/common/hw-properties.c @@ -0,0 +1,905 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1998, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + +#include "hw-main.h" +#include "hw-base.h" + +#include "sim-assert.h" + +#ifdef HAVE_STRING_H +#include <string.h> +#else +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#endif + +#define TRACE(A,B) + +/* property entries */ + +struct hw_property_data { + struct hw_property_data *next; + struct hw_property *property; + const void *init_array; + unsigned sizeof_init_array; +}; + +void +create_hw_property_data (struct hw *me) +{ +} + +void +delete_hw_property_data (struct hw *me) +{ +} + + +/* Device Properties: */ + +static struct hw_property_data * +find_property_data (struct hw *me, + const char *property) +{ + struct hw_property_data *entry; + ASSERT (property != NULL); + entry = me->properties_of_hw; + while (entry != NULL) + { + if (strcmp (entry->property->name, property) == 0) + return entry; + entry = entry->next; + } + return NULL; +} + + +static void +hw_add_property (struct hw *me, + const char *property, + hw_property_type type, + const void *init_array, + unsigned sizeof_init_array, + const void *array, + unsigned sizeof_array, + const struct hw_property *original, + object_disposition disposition) +{ + struct hw_property_data *new_entry = NULL; + struct hw_property *new_value = NULL; + + /* find the list end */ + struct hw_property_data **insertion_point = &me->properties_of_hw; + while (*insertion_point != NULL) + { + if (strcmp ((*insertion_point)->property->name, property) == 0) + return; + insertion_point = &(*insertion_point)->next; + } + + /* create a new value */ + new_value = HW_ZALLOC (me, struct hw_property); + new_value->name = (char *) strdup (property); + new_value->type = type; + if (sizeof_array > 0) + { + void *new_array = hw_zalloc (me, sizeof_array); + memcpy (new_array, array, sizeof_array); + new_value->array = new_array; + new_value->sizeof_array = sizeof_array; + } + new_value->owner = me; + new_value->original = original; + new_value->disposition = disposition; + + /* insert the value into the list */ + new_entry = HW_ZALLOC (me, struct hw_property_data); + *insertion_point = new_entry; + if (sizeof_init_array > 0) + { + void *new_init_array = hw_zalloc (me, sizeof_init_array); + memcpy (new_init_array, init_array, sizeof_init_array); + new_entry->init_array = new_init_array; + new_entry->sizeof_init_array = sizeof_init_array; + } + new_entry->property = new_value; +} + + +static void +hw_set_property (struct hw *me, + const char *property, + hw_property_type type, + const void *array, + int sizeof_array) +{ + /* find the property */ + struct hw_property_data *entry = find_property_data (me, property); + if (entry != NULL) + { + /* existing property - update it */ + void *new_array = 0; + struct hw_property *value = entry->property; + /* check the type matches */ + if (value->type != type) + hw_abort (me, "conflict between type of new and old value for property %s", property); + /* replace its value */ + if (value->array != NULL) + hw_free (me, (void*)value->array); + new_array = (sizeof_array > 0 + ? hw_zalloc (me, sizeof_array) + : (void*)0); + value->array = new_array; + value->sizeof_array = sizeof_array; + if (sizeof_array > 0) + memcpy (new_array, array, sizeof_array); + return; + } + else + { + /* new property - create it */ + hw_add_property (me, property, type, + NULL, 0, array, sizeof_array, + NULL, temporary_object); + } +} + + +#if 0 +static void +clean_hw_properties (struct hw *me) +{ + struct hw_property_data **delete_point = &me->properties_of_hw; + while (*delete_point != NULL) + { + struct hw_property_data *current = *delete_point; + switch (current->property->disposition) + { + case permenant_object: + /* zap the current value, will be initialized later */ + ASSERT (current->init_array != NULL); + if (current->property->array != NULL) + { + hw_free (me, (void*)current->property->array); + current->property->array = NULL; + } + delete_point = &(*delete_point)->next; + break; + case temporary_object: + /* zap the actual property, was created during simulation run */ + ASSERT (current->init_array == NULL); + *delete_point = current->next; + if (current->property->array != NULL) + hw_free (me, (void*)current->property->array); + hw_free (me, current->property); + hw_free (me, current); + break; + } + } +} +#endif + +#if 0 +void +hw_init_static_properties (SIM_DESC sd, + struct hw *me, + void *data) +{ + struct hw_property_data *property; + for (property = me->properties_of_hw; + property != NULL; + property = property->next) + { + ASSERT (property->init_array != NULL); + ASSERT (property->property->array == NULL); + ASSERT(property->property->disposition == permenant_object); + switch (property->property->type) + { + case array_property: + case boolean_property: + case range_array_property: + case reg_array_property: + case string_property: + case string_array_property: + case integer_property: + /* delete the property, and replace it with the original */ + hw_set_property (me, property->property->name, + property->property->type, + property->init_array, + property->sizeof_init_array); + break; +#if 0 + case ihandle_property: + break; +#endif + } + } +} +#endif + + +#if 0 +void +hw_init_runtime_properties (SIM_DESC sd, + struct hw *me, + void *data) +{ + struct hw_property_data *property; + for (property = me->properties_of_hw; + property != NULL; + property = property->next) + { + switch (property->property->disposition) + { + case permenant_object: + switch (property->property->type) + { +#if 0 + case ihandle_property: + { + struct hw_instance *ihandle; + ihandle_runtime_property_spec spec; + ASSERT (property->init_array != NULL); + ASSERT (property->property->array == NULL); + hw_find_ihandle_runtime_property (me, property->property->name, &spec); + ihandle = tree_instance (me, spec.full_path); + hw_set_ihandle_property (me, property->property->name, ihandle); + break; + } +#endif + case array_property: + case boolean_property: + case range_array_property: + case integer_property: + case reg_array_property: + case string_property: + case string_array_property: + ASSERT (property->init_array != NULL); + ASSERT (property->property->array != NULL); + break; + } + break; + case temporary_object: + ASSERT (property->init_array == NULL); + ASSERT (property->property->array != NULL); + break; + } + } +} +#endif + + + +const struct hw_property * +hw_next_property (const struct hw_property *property) +{ + /* find the property in the list */ + struct hw *owner = property->owner; + struct hw_property_data *entry = owner->properties_of_hw; + while (entry != NULL && entry->property != property) + entry = entry->next; + /* now return the following property */ + ASSERT (entry != NULL); /* must be a member! */ + if (entry->next != NULL) + return entry->next->property; + else + return NULL; +} + + +const struct hw_property * +hw_find_property (struct hw *me, + const char *property) +{ + if (me == NULL) + { + return NULL; + } + else if (property == NULL || strcmp (property, "") == 0) + { + if (me->properties_of_hw == NULL) + return NULL; + else + return me->properties_of_hw->property; + } + else + { + struct hw_property_data *entry = find_property_data (me, property); + if (entry != NULL) + return entry->property; + } + return NULL; +} + + +void +hw_add_array_property (struct hw *me, + const char *property, + const void *array, + int sizeof_array) +{ + hw_add_property (me, property, array_property, + array, sizeof_array, array, sizeof_array, + NULL, permenant_object); +} + +void +hw_set_array_property (struct hw *me, + const char *property, + const void *array, + int sizeof_array) +{ + hw_set_property (me, property, array_property, array, sizeof_array); +} + +const struct hw_property * +hw_find_array_property (struct hw *me, + const char *property) +{ + const struct hw_property *node; + node = hw_find_property (me, property); + if (node == NULL) + hw_abort (me, "property \"%s\" not found", property); + if (node->type != array_property) + hw_abort (me, "property \"%s\" of wrong type (array)", property); + return node; +} + + + +void +hw_add_boolean_property (struct hw *me, + const char *property, + int boolean) +{ + signed32 new_boolean = (boolean ? -1 : 0); + hw_add_property (me, property, boolean_property, + &new_boolean, sizeof(new_boolean), + &new_boolean, sizeof(new_boolean), + NULL, permenant_object); +} + +int +hw_find_boolean_property (struct hw *me, + const char *property) +{ + const struct hw_property *node; + unsigned_cell boolean; + node = hw_find_property (me, property); + if (node == NULL) + hw_abort (me, "property \"%s\" not found", property); + if (node->type != boolean_property) + hw_abort (me, "property \"%s\" of wrong type (boolean)", property); + ASSERT (sizeof (boolean) == node->sizeof_array); + memcpy (&boolean, node->array, sizeof (boolean)); + return boolean; +} + + + +#if 0 +void +hw_add_ihandle_runtime_property (struct hw *me, + const char *property, + const ihandle_runtime_property_spec *ihandle) +{ + /* enter the full path as the init array */ + hw_add_property (me, property, ihandle_property, + ihandle->full_path, strlen(ihandle->full_path) + 1, + NULL, 0, + NULL, permenant_object); +} +#endif + +#if 0 +void +hw_find_ihandle_runtime_property (struct hw *me, + const char *property, + ihandle_runtime_property_spec *ihandle) +{ + struct hw_property_data *entry = find_property_data (me, property); + TRACE (trace_devices, + ("hw_find_ihandle_runtime_property(me=0x%lx, property=%s)\n", + (long)me, property)); + if (entry == NULL) + hw_abort (me, "property \"%s\" not found", property); + if (entry->property->type != ihandle_property + || entry->property->disposition != permenant_object) + hw_abort (me, "property \"%s\" of wrong type", property); + ASSERT (entry->init_array != NULL); + /* the full path */ + ihandle->full_path = entry->init_array; +} +#endif + + + +#if 0 +void +hw_set_ihandle_property (struct hw *me, + const char *property, + hw_instance *ihandle) +{ + unsigned_cell cells; + cells = H2BE_cell (hw_instance_to_external (ihandle)); + hw_set_property (me, property, ihandle_property, + &cells, sizeof (cells)); + +} +#endif + +#if 0 +hw_instance * +hw_find_ihandle_property (struct hw *me, + const char *property) +{ + const hw_property_data *node; + unsigned_cell ihandle; + hw_instance *instance; + + node = hw_find_property (me, property); + if (node == NULL) + hw_abort (me, "property \"%s\" not found", property); + if (node->type != ihandle_property) + hw_abort(me, "property \"%s\" of wrong type (ihandle)", property); + if (node->array == NULL) + hw_abort(me, "runtime property \"%s\" not yet initialized", property); + + ASSERT (sizeof(ihandle) == node->sizeof_array); + memcpy (&ihandle, node->array, sizeof(ihandle)); + instance = external_to_hw_instance (me, BE2H_cell(ihandle)); + ASSERT (instance != NULL); + return instance; +} +#endif + + +void +hw_add_integer_property (struct hw *me, + const char *property, + signed_cell integer) +{ + H2BE (integer); + hw_add_property (me, property, integer_property, + &integer, sizeof(integer), + &integer, sizeof(integer), + NULL, permenant_object); +} + +signed_cell +hw_find_integer_property (struct hw *me, + const char *property) +{ + const struct hw_property *node; + signed_cell integer; + TRACE (trace_devices, + ("hw_find_integer(me=0x%lx, property=%s)\n", + (long)me, property)); + node = hw_find_property (me, property); + if (node == NULL) + hw_abort (me, "property \"%s\" not found", property); + if (node->type != integer_property) + hw_abort (me, "property \"%s\" of wrong type (integer)", property); + ASSERT (sizeof(integer) == node->sizeof_array); + memcpy (&integer, node->array, sizeof (integer)); + return BE2H_cell (integer); +} + +int +hw_find_integer_array_property (struct hw *me, + const char *property, + unsigned index, + signed_cell *integer) +{ + const struct hw_property *node; + int sizeof_integer = sizeof (*integer); + signed_cell *cell; + TRACE (trace_devices, + ("hw_find_integer(me=0x%lx, property=%s)\n", + (long)me, property)); + + /* check things sane */ + node = hw_find_property (me, property); + if (node == NULL) + hw_abort (me, "property \"%s\" not found", property); + if (node->type != integer_property + && node->type != array_property) + hw_abort (me, "property \"%s\" of wrong type (integer or array)", property); + if ((node->sizeof_array % sizeof_integer) != 0) + hw_abort (me, "property \"%s\" contains an incomplete number of cells", property); + if (node->sizeof_array <= sizeof_integer * index) + return 0; + + /* Find and convert the value */ + cell = ((signed_cell*)node->array) + index; + *integer = BE2H_cell (*cell); + + return node->sizeof_array / sizeof_integer; +} + + +static unsigned_cell * +unit_address_to_cells (const hw_unit *unit, + unsigned_cell *cell, + int nr_cells) +{ + int i; + ASSERT(nr_cells == unit->nr_cells); + for (i = 0; i < unit->nr_cells; i++) + { + *cell = H2BE_cell (unit->cells[i]); + cell += 1; + } + return cell; +} + + +static const unsigned_cell * +cells_to_unit_address (const unsigned_cell *cell, + hw_unit *unit, + int nr_cells) +{ + int i; + memset(unit, 0, sizeof(*unit)); + unit->nr_cells = nr_cells; + for (i = 0; i < unit->nr_cells; i++) + { + unit->cells[i] = BE2H_cell (*cell); + cell += 1; + } + return cell; +} + + +static unsigned +nr_range_property_cells (struct hw *me, + int nr_ranges) +{ + return ((hw_unit_nr_address_cells (me) + + hw_unit_nr_address_cells (hw_parent (me)) + + hw_unit_nr_size_cells (me)) + ) * nr_ranges; +} + +void +hw_add_range_array_property (struct hw *me, + const char *property, + const range_property_spec *ranges, + unsigned nr_ranges) +{ + unsigned sizeof_cells = (nr_range_property_cells (me, nr_ranges) + * sizeof (unsigned_cell)); + unsigned_cell *cells = hw_zalloc (me, sizeof_cells); + unsigned_cell *cell; + int i; + + /* copy the property elements over */ + cell = cells; + for (i = 0; i < nr_ranges; i++) + { + const range_property_spec *range = &ranges[i]; + /* copy the child address */ + cell = unit_address_to_cells (&range->child_address, cell, + hw_unit_nr_address_cells (me)); + /* copy the parent address */ + cell = unit_address_to_cells (&range->parent_address, cell, + hw_unit_nr_address_cells (hw_parent (me))); + /* copy the size */ + cell = unit_address_to_cells (&range->size, cell, + hw_unit_nr_size_cells (me)); + } + ASSERT (cell == &cells[nr_range_property_cells (me, nr_ranges)]); + + /* add it */ + hw_add_property (me, property, range_array_property, + cells, sizeof_cells, + cells, sizeof_cells, + NULL, permenant_object); + + hw_free (me, cells); +} + +int +hw_find_range_array_property (struct hw *me, + const char *property, + unsigned index, + range_property_spec *range) +{ + const struct hw_property *node; + unsigned sizeof_entry = (nr_range_property_cells (me, 1) + * sizeof (unsigned_cell)); + const unsigned_cell *cells; + + /* locate the property */ + node = hw_find_property (me, property); + if (node == NULL) + hw_abort (me, "property \"%s\" not found", property); + if (node->type != range_array_property) + hw_abort (me, "property \"%s\" of wrong type (range array)", property); + + /* aligned ? */ + if ((node->sizeof_array % sizeof_entry) != 0) + hw_abort (me, "property \"%s\" contains an incomplete number of entries", + property); + + /* within bounds? */ + if (node->sizeof_array < sizeof_entry * (index + 1)) + return 0; + + /* find the range of interest */ + cells = (unsigned_cell*)((char*)node->array + sizeof_entry * index); + + /* copy the child address out - converting as we go */ + cells = cells_to_unit_address (cells, &range->child_address, + hw_unit_nr_address_cells (me)); + + /* copy the parent address out - converting as we go */ + cells = cells_to_unit_address (cells, &range->parent_address, + hw_unit_nr_address_cells (hw_parent (me))); + + /* copy the size - converting as we go */ + cells = cells_to_unit_address (cells, &range->size, + hw_unit_nr_size_cells (me)); + + return node->sizeof_array / sizeof_entry; +} + + +static unsigned +nr_reg_property_cells (struct hw *me, + int nr_regs) +{ + return (hw_unit_nr_address_cells (hw_parent(me)) + + hw_unit_nr_size_cells (hw_parent(me)) + ) * nr_regs; +} + +void +hw_add_reg_array_property (struct hw *me, + const char *property, + const reg_property_spec *regs, + unsigned nr_regs) +{ + unsigned sizeof_cells = (nr_reg_property_cells (me, nr_regs) + * sizeof (unsigned_cell)); + unsigned_cell *cells = hw_zalloc (me, sizeof_cells); + unsigned_cell *cell; + int i; + + /* copy the property elements over */ + cell = cells; + for (i = 0; i < nr_regs; i++) + { + const reg_property_spec *reg = ®s[i]; + /* copy the address */ + cell = unit_address_to_cells (®->address, cell, + hw_unit_nr_address_cells (hw_parent (me))); + /* copy the size */ + cell = unit_address_to_cells (®->size, cell, + hw_unit_nr_size_cells (hw_parent (me))); + } + ASSERT (cell == &cells[nr_reg_property_cells (me, nr_regs)]); + + /* add it */ + hw_add_property (me, property, reg_array_property, + cells, sizeof_cells, + cells, sizeof_cells, + NULL, permenant_object); + + hw_free (me, cells); +} + +int +hw_find_reg_array_property (struct hw *me, + const char *property, + unsigned index, + reg_property_spec *reg) +{ + const struct hw_property *node; + unsigned sizeof_entry = (nr_reg_property_cells (me, 1) + * sizeof (unsigned_cell)); + const unsigned_cell *cells; + + /* locate the property */ + node = hw_find_property (me, property); + if (node == NULL) + hw_abort (me, "property \"%s\" not found", property); + if (node->type != reg_array_property) + hw_abort (me, "property \"%s\" of wrong type (reg array)", property); + + /* aligned ? */ + if ((node->sizeof_array % sizeof_entry) != 0) + hw_abort (me, "property \"%s\" contains an incomplete number of entries", + property); + + /* within bounds? */ + if (node->sizeof_array < sizeof_entry * (index + 1)) + return 0; + + /* find the range of interest */ + cells = (unsigned_cell*)((char*)node->array + sizeof_entry * index); + + /* copy the address out - converting as we go */ + cells = cells_to_unit_address (cells, ®->address, + hw_unit_nr_address_cells (hw_parent (me))); + + /* copy the size out - converting as we go */ + cells = cells_to_unit_address (cells, ®->size, + hw_unit_nr_size_cells (hw_parent (me))); + + return node->sizeof_array / sizeof_entry; +} + + +void +hw_add_string_property (struct hw *me, + const char *property, + const char *string) +{ + hw_add_property (me, property, string_property, + string, strlen(string) + 1, + string, strlen(string) + 1, + NULL, permenant_object); +} + +const char * +hw_find_string_property (struct hw *me, + const char *property) +{ + const struct hw_property *node; + const char *string; + node = hw_find_property (me, property); + if (node == NULL) + hw_abort (me, "property \"%s\" not found", property); + if (node->type != string_property) + hw_abort (me, "property \"%s\" of wrong type (string)", property); + string = node->array; + ASSERT (strlen(string) + 1 == node->sizeof_array); + return string; +} + +void +hw_add_string_array_property (struct hw *me, + const char *property, + const string_property_spec *strings, + unsigned nr_strings) +{ + int sizeof_array; + int string_nr; + char *array; + char *chp; + if (nr_strings == 0) + hw_abort (me, "property \"%s\" must be non-null", property); + /* total up the size of the needed array */ + for (sizeof_array = 0, string_nr = 0; + string_nr < nr_strings; + string_nr ++) + { + sizeof_array += strlen (strings[string_nr]) + 1; + } + /* create the array */ + array = (char*) hw_zalloc (me, sizeof_array); + chp = array; + for (string_nr = 0; + string_nr < nr_strings; + string_nr++) + { + strcpy (chp, strings[string_nr]); + chp += strlen (chp) + 1; + } + ASSERT (chp == array + sizeof_array); + /* now enter it */ + hw_add_property (me, property, string_array_property, + array, sizeof_array, + array, sizeof_array, + NULL, permenant_object); +} + +int +hw_find_string_array_property (struct hw *me, + const char *property, + unsigned index, + string_property_spec *string) +{ + const struct hw_property *node; + node = hw_find_property (me, property); + if (node == NULL) + hw_abort (me, "property \"%s\" not found", property); + switch (node->type) + { + default: + hw_abort (me, "property \"%s\" of wrong type", property); + break; + case string_property: + if (index == 0) + { + *string = node->array; + ASSERT (strlen(*string) + 1 == node->sizeof_array); + return 1; + } + break; + case array_property: + if (node->sizeof_array == 0 + || ((char*)node->array)[node->sizeof_array - 1] != '\0') + hw_abort (me, "property \"%s\" invalid for string array", property); + /* FALL THROUGH */ + case string_array_property: + ASSERT (node->sizeof_array > 0); + ASSERT (((char*)node->array)[node->sizeof_array - 1] == '\0'); + { + const char *chp = node->array; + int nr_entries = 0; + /* count the number of strings, keeping an eye out for the one + we're looking for */ + *string = chp; + do + { + if (*chp == '\0') + { + /* next string */ + nr_entries++; + chp++; + if (nr_entries == index) + *string = chp; + } + else + { + chp++; + } + } while (chp < (char*)node->array + node->sizeof_array); + if (index < nr_entries) + return nr_entries; + else + { + *string = NULL; + return 0; + } + } + break; + } + return 0; +} + +void +hw_add_duplicate_property (struct hw *me, + const char *property, + const struct hw_property *original) +{ + struct hw_property_data *master; + TRACE (trace_devices, + ("hw_add_duplicate_property(me=0x%lx, property=%s, ...)\n", + (long)me, property)); + if (original->disposition != permenant_object) + hw_abort (me, "Can only duplicate permenant objects"); + /* find the original's master */ + master = original->owner->properties_of_hw; + while (master->property != original) + { + master = master->next; + ASSERT(master != NULL); + } + /* now duplicate it */ + hw_add_property (me, property, + original->type, + master->init_array, master->sizeof_init_array, + original->array, original->sizeof_array, + original, permenant_object); +} diff --git a/sim/common/hw-properties.h b/sim/common/hw-properties.h new file mode 100644 index 0000000..511fba3 --- /dev/null +++ b/sim/common/hw-properties.h @@ -0,0 +1,244 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1998, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef HW_PROPERTIES_H +#define HW_PROPERTIES_H + +/* The following are valid property types. The property `array' is + for generic untyped data. */ + +typedef enum { + array_property, + boolean_property, +#if 0 + ihandle_property, /*runtime*/ +#endif + integer_property, + range_array_property, + reg_array_property, + string_property, + string_array_property, +} hw_property_type; + +struct hw_property { + struct hw *owner; + const char *name; + hw_property_type type; + unsigned sizeof_array; + const void *array; + const struct hw_property *original; + object_disposition disposition; +}; + +#define hw_property_owner(p) ((p)->owner + 0) +#define hw_property_name(p) ((p)->name + 0) +#define hw_property_type(p) ((p)->type + 0) +#define hw_property_array(p) ((p)->array + 0) +#define hw_property_sizeof_array(p) ((p)->sizeof_array + 0) +#define hw_property_original(p) ((p)->original + 0) +#define hw_property_disposition(p) ((p)->disposition + 0) + + +/* Find/iterate over properites attached to a device. + + To iterate over all properties attached to a device, call + hw_find_property (.., NULL) and then hw_property_next. */ + +const struct hw_property *hw_find_property +(struct hw *me, + const char *property); + +const struct hw_property *hw_next_property +(const struct hw_property *previous); + + +/* Manipulate the properties belonging to a given device. + + HW_ADD_* will, if the property is not already present, add a + property to the device. Adding a property to a device after it has + been created is a checked run-time error (use HW_SET_*). + + HW_SET_* will always update (or create) the property so that it has + the specified value. Changing the type of a property is a checked + run-time error. + + FIND returns the specified properties value. It is a checked + runtime error to either request a nonexistant property or to + request a property using the wrong type. Code locating a property + should first check its type (using hw_find_property above) and then + obtain its value using the below. + + Naming convention: + + void hw_add_<type>_property(struct hw *, const char *, <type>) + void hw_add_*_array_property(struct hw *, const char *, const <type>*, int) + void hw_set_*_property(struct hw *, const char *, <type>) + void hw_set_*_array_property(struct hw *, const char *, const <type>*, int) + <type> hw_find_*_property(struct hw *, const char *) + int hw_find_*_array_property(struct hw *, const char *, int, <type>*) + + */ + + +void hw_add_array_property +(struct hw *me, + const char *property, + const void *array, + int sizeof_array); + +void hw_set_array_property +(struct hw *me, + const char *property, + const void *array, + int sizeof_array); + +const struct hw_property *hw_find_array_property +(struct hw *me, + const char *property); + + + +void hw_add_boolean_property +(struct hw *me, + const char *property, + int bool); + +int hw_find_boolean_property +(struct hw *me, + const char *property); + + + +#if 0 +typedef struct _ihandle_runtime_property_spec { + const char *full_path; +} ihandle_runtime_property_spec; + +void hw_add_ihandle_runtime_property +(struct hw *me, + const char *property, + const ihandle_runtime_property_spec *ihandle); + +void hw_find_ihandle_runtime_property +(struct hw *me, + const char *property, + ihandle_runtime_property_spec *ihandle); + +void hw_set_ihandle_property +(struct hw *me, + const char *property, + hw_instance *ihandle); + +hw_instance * hw_find_ihandle_property +(struct hw *me, + const char *property); +#endif + + +void hw_add_integer_property +(struct hw *me, + const char *property, + signed_cell integer); + +signed_cell hw_find_integer_property +(struct hw *me, + const char *property); + +int hw_find_integer_array_property +(struct hw *me, + const char *property, + unsigned index, + signed_word *integer); + + + +typedef struct _range_property_spec { + hw_unit child_address; + hw_unit parent_address; + hw_unit size; +} range_property_spec; + +void hw_add_range_array_property +(struct hw *me, + const char *property, + const range_property_spec *ranges, + unsigned nr_ranges); + +int hw_find_range_array_property +(struct hw *me, + const char *property, + unsigned index, + range_property_spec *range); + + + +typedef struct _reg_property_spec { + hw_unit address; + hw_unit size; +} reg_property_spec; + +void hw_add_reg_array_property +(struct hw *me, + const char *property, + const reg_property_spec *reg, + unsigned nr_regs); + +int hw_find_reg_array_property +(struct hw *me, + const char *property, + unsigned index, + reg_property_spec *reg); + + + +void hw_add_string_property +(struct hw *me, + const char *property, + const char *string); + +const char *hw_find_string_property +(struct hw *me, + const char *property); + + + +typedef const char *string_property_spec; + +void hw_add_string_array_property +(struct hw *me, + const char *property, + const string_property_spec *strings, + unsigned nr_strings); + +int hw_find_string_array_property +(struct hw *me, + const char *property, + unsigned index, + string_property_spec *string); + + + +void hw_add_duplicate_property +(struct hw *me, + const char *property, + const struct hw_property *original); + +#endif diff --git a/sim/common/hw-tree.c b/sim/common/hw-tree.c new file mode 100644 index 0000000..1a55835 --- /dev/null +++ b/sim/common/hw-tree.c @@ -0,0 +1,1344 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1998, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + +#include "hw-main.h" +#include "hw-base.h" +#include "hw-tree.h" + +#include "sim-assert.h" + +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif + +#ifdef HAVE_STRING_H +#include <string.h> +#else +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#endif + +#include <ctype.h> + +/* manipulate/lookup device names */ + +typedef struct _name_specifier { + + /* components in the full length name */ + char *path; + char *property; + char *value; + + /* current device */ + char *family; + char *name; + char *unit; + char *args; + + /* previous device */ + char *last_name; + char *last_family; + char *last_unit; + char *last_args; + + /* work area */ + char buf[1024]; + +} name_specifier; + + + +/* Given a device specifier, break it up into its main components: + path (and if present) property name and property value. */ + +static int +split_device_specifier (struct hw *current, + const char *device_specifier, + name_specifier *spec) +{ + char *chp = NULL; + + /* expand any leading alias if present */ + if (current != NULL + && *device_specifier != '\0' + && *device_specifier != '.' + && *device_specifier != '/') + { + struct hw *aliases = hw_tree_find_device (current, "/aliases"); + char alias[32]; + int len = 0; + while (device_specifier[len] != '\0' + && device_specifier[len] != '/' + && device_specifier[len] != ':' + && !isspace (device_specifier[len])) + { + alias[len] = device_specifier[len]; + len++; + if (len >= sizeof(alias)) + hw_abort (NULL, "split_device_specifier: buffer overflow"); + } + alias[len] = '\0'; + if (aliases != NULL + && hw_find_property (aliases, alias)) + { + strcpy (spec->buf, hw_find_string_property(aliases, alias)); + strcat (spec->buf, device_specifier + len); + } + else + { + strcpy (spec->buf, device_specifier); + } + } + else + { + strcpy(spec->buf, device_specifier); + } + + /* check no overflow */ + if (strlen(spec->buf) >= sizeof(spec->buf)) + hw_abort (NULL, "split_device_specifier: buffer overflow\n"); + + /* strip leading spaces */ + chp = spec->buf; + while (*chp != '\0' && isspace(*chp)) + chp++; + if (*chp == '\0') + return 0; + + /* find the path and terminate it with null */ + spec->path = chp; + while (*chp != '\0' && !isspace(*chp)) + chp++; + if (*chp != '\0') + { + *chp = '\0'; + chp++; + } + + /* and any value */ + while (*chp != '\0' && isspace(*chp)) + chp++; + spec->value = chp; + + /* now go back and chop the property off of the path */ + if (spec->value[0] == '\0') + { + spec->property = NULL; /*not a property*/ + spec->value = NULL; + } + else if (spec->value[0] == '>' + || spec->value[0] == '<') + { + /* an interrupt spec */ + spec->property = NULL; + } + else { + chp = strrchr(spec->path, '/'); + if (chp == NULL) + { + spec->property = spec->path; + spec->path = strchr(spec->property, '\0'); + } + else { + *chp = '\0'; + spec->property = chp+1; + } + } + + /* and mark the rest as invalid */ + spec->name = NULL; + spec->family = NULL; + spec->unit = NULL; + spec->args = NULL; + spec->last_name = NULL; + spec->last_family = NULL; + spec->last_unit = NULL; + spec->last_args = NULL; + + return 1; +} + + +/* given a device specifier break it up into its main components - + path and property name - assuming that the last `device' is a + property name. */ + +static int +split_property_specifier (struct hw *current, + const char *property_specifier, + name_specifier *spec) +{ + if (split_device_specifier (current, property_specifier, spec)) + { + if (spec->property == NULL) + { + /* force the last name to be a property name */ + char *chp = strrchr (spec->path, '/'); + if (chp == NULL) + { + spec->property = spec->path; + spec->path = strrchr (spec->property, '\0');; + } + else + { + *chp = '\0'; + spec->property = chp + 1; + } + } + return 1; + } + else + return 0; +} + + +/* device the next device name and split it up, return 0 when no more + names to struct hw */ + +static int +split_device_name (name_specifier *spec) +{ + char *chp; + /* remember what came before */ + spec->last_name = spec->name; + spec->last_family = spec->family; + spec->last_unit = spec->unit; + spec->last_args = spec->args; + /* finished? */ + if (spec->path[0] == '\0') + { + spec->name = NULL; + spec->family = NULL; + spec->unit = NULL; + spec->args = NULL; + return 0; + } + /* break the current device spec from the path */ + spec->name = spec->path; + chp = strchr (spec->name, '/'); + if (chp == NULL) + spec->path = strchr (spec->name, '\0'); + else + { + spec->path = chp+1; + *chp = '\0'; + } + /* break out the base */ + if (spec->name[0] == '(') + { + chp = strchr(spec->name, ')'); + if (chp == NULL) + { + spec->family = spec->name; + } + else + { + *chp = '\0'; + spec->family = spec->name + 1; + spec->name = chp + 1; + } + } + else + { + spec->family = spec->name; + } + /* now break out the unit */ + chp = strchr(spec->name, '@'); + if (chp == NULL) + { + spec->unit = NULL; + chp = spec->name; + } + else + { + *chp = '\0'; + chp += 1; + spec->unit = chp; + } + /* finally any args */ + chp = strchr(chp, ':'); + if (chp == NULL) + spec->args = NULL; + else + { + *chp = '\0'; + spec->args = chp+1; + } + return 1; +} + + +/* device the value, returning the next non-space token */ + +static char * +split_value (name_specifier *spec) +{ + char *token; + if (spec->value == NULL) + return NULL; + /* skip leading white space */ + while (isspace (spec->value[0])) + spec->value++; + if (spec->value[0] == '\0') + { + spec->value = NULL; + return NULL; + } + token = spec->value; + /* find trailing space */ + while (spec->value[0] != '\0' && !isspace (spec->value[0])) + spec->value++; + /* chop this value out */ + if (spec->value[0] != '\0') + { + spec->value[0] = '\0'; + spec->value++; + } + return token; +} + + + +/* traverse the path specified by spec starting at current */ + +static struct hw * +split_find_device (struct hw *current, + name_specifier *spec) +{ + /* strip off (and process) any leading ., .., ./ and / */ + while (1) + { + if (strncmp (spec->path, "/", strlen ("/")) == 0) + { + /* cd /... */ + while (current != NULL && hw_parent (current) != NULL) + current = hw_parent (current); + spec->path += strlen ("/"); + } + else if (strncmp (spec->path, "./", strlen ("./")) == 0) + { + /* cd ./... */ + current = current; + spec->path += strlen ("./"); + } + else if (strncmp (spec->path, "../", strlen ("../")) == 0) + { + /* cd ../... */ + if (current != NULL && hw_parent (current) != NULL) + current = hw_parent (current); + spec->path += strlen ("../"); + } + else if (strcmp (spec->path, ".") == 0) + { + /* cd . */ + current = current; + spec->path += strlen ("."); + } + else if (strcmp (spec->path, "..") == 0) + { + /* cd .. */ + if (current != NULL && hw_parent (current) != NULL) + current = hw_parent (current); + spec->path += strlen (".."); + } + else + break; + } + + /* now go through the path proper */ + + if (current == NULL) + { + split_device_name (spec); + return NULL; + } + + while (split_device_name (spec)) + { + struct hw *child; + for (child = hw_child (current); + child != NULL; child = hw_sibling (child)) + { + if (strcmp (spec->name, hw_name (child)) == 0) + { + if (spec->unit == NULL) + break; + else + { + hw_unit phys; + hw_unit_decode (current, spec->unit, &phys); + if (memcmp (&phys, hw_unit_address (child), + sizeof (hw_unit)) == 0) + break; + } + } + } + if (child == NULL) + return current; /* search failed */ + current = child; + } + + return current; +} + + +static struct hw * +split_fill_path (struct hw *current, + const char *device_specifier, + name_specifier *spec) +{ + /* break it up */ + if (!split_device_specifier (current, device_specifier, spec)) + hw_abort (current, "error parsing %s\n", device_specifier); + + /* fill our tree with its contents */ + current = split_find_device (current, spec); + + /* add any additional devices as needed */ + if (spec->name != NULL) + { + do + { + if (current != NULL && !hw_finished_p (current)) + hw_finish (current); + current = hw_create (NULL, + current, + spec->family, + spec->name, + spec->unit, + spec->args); + } + while (split_device_name (spec)); + } + + return current; +} + + +/* <non-white-space> */ + +static const char * +skip_token(const char *chp) +{ + while (!isspace(*chp) && *chp != '\0') + chp++; + while (isspace(*chp) && *chp != '\0') + chp++; + return chp; +} + + +/* count the number of entries */ + +static int +count_entries (struct hw *current, + const char *property_name, + const char *property_value, + int modulo) +{ + const char *chp = property_value; + int nr_entries = 0; + while (*chp != '\0') + { + nr_entries += 1; + chp = skip_token (chp); + } + if ((nr_entries % modulo) != 0) + { + hw_abort (current, "incorrect number of entries for %s property %s, should be multiple of %d", + property_name, property_value, modulo); + } + return nr_entries / modulo; +} + + + +/* parse: <address> ::= <token> ; device dependant */ + +static const char * +parse_address (struct hw *current, + struct hw *bus, + const char *chp, + hw_unit *address) +{ + if (hw_unit_decode (bus, chp, address) < 0) + hw_abort (current, "invalid unit address in %s", chp); + return skip_token (chp); +} + + +/* parse: <size> ::= <number> { "," <number> } ; */ + +static const char * +parse_size (struct hw *current, + struct hw *bus, + const char *chp, + hw_unit *size) +{ + int i; + int nr; + const char *curr = chp; + memset(size, 0, sizeof(*size)); + /* parse the numeric list */ + size->nr_cells = hw_unit_nr_size_cells (bus); + nr = 0; + while (1) + { + char *next; + size->cells[nr] = strtoul (curr, &next, 0); + if (curr == next) + hw_abort (current, "Problem parsing <size> %s", chp); + nr += 1; + if (next[0] != ',') + break; + if (nr == size->nr_cells) + hw_abort (current, "Too many values in <size> %s", chp); + curr = next + 1; + } + ASSERT (nr > 0 && nr <= size->nr_cells); + /* right align the numbers */ + for (i = 1; i <= size->nr_cells; i++) + { + if (i <= nr) + size->cells[size->nr_cells - i] = size->cells[nr - i]; + else + size->cells[size->nr_cells - i] = 0; + } + return skip_token (chp); +} + + +/* parse: <reg> ::= { <address> <size> } ; */ + +static void +parse_reg_property (struct hw *current, + const char *property_name, + const char *property_value) +{ + int nr_regs; + int reg_nr; + reg_property_spec *regs; + const char *chp; + + /* determine the number of reg entries by counting tokens */ + nr_regs = count_entries (current, property_name, property_value, 2); + + /* create working space */ + regs = zalloc (nr_regs * sizeof (*regs)); + + /* fill it in */ + chp = property_value; + for (reg_nr = 0; reg_nr < nr_regs; reg_nr++) + { + chp = parse_address (current, hw_parent(current), + chp, ®s[reg_nr].address); + chp = parse_size (current, hw_parent(current), + chp, ®s[reg_nr].size); + } + + /* create it */ + hw_add_reg_array_property (current, property_name, + regs, nr_regs); + + zfree (regs); +} + + +/* { <child-address> <parent-address> <child-size> }* */ + +static void +parse_ranges_property (struct hw *current, + const char *property_name, + const char *property_value) +{ + int nr_ranges; + int range_nr; + range_property_spec *ranges; + const char *chp; + + /* determine the number of ranges specified */ + nr_ranges = count_entries (current, property_name, property_value, 3); + + /* create a property of that size */ + ranges = zalloc (nr_ranges * sizeof(*ranges)); + + /* fill it in */ + chp = property_value; + for (range_nr = 0; range_nr < nr_ranges; range_nr++) + { + chp = parse_address (current, current, + chp, &ranges[range_nr].child_address); + chp = parse_address (current, hw_parent(current), + chp, &ranges[range_nr].parent_address); + chp = parse_size (current, current, + chp, &ranges[range_nr].size); + } + + /* create it */ + hw_add_range_array_property (current, property_name, ranges, nr_ranges); + + zfree (ranges); +} + + +/* <integer> ... */ + +static void +parse_integer_property (struct hw *current, + const char *property_name, + const char *property_value) +{ + int nr_entries; + unsigned_cell words[1024]; + /* integer or integer array? */ + nr_entries = 0; + while (1) + { + char *end; + words[nr_entries] = strtoul (property_value, &end, 0); + if (property_value == end) + break; + nr_entries += 1; + if (nr_entries * sizeof (words[0]) >= sizeof (words)) + hw_abort (current, "buffer overflow"); + property_value = end; + } + if (nr_entries == 0) + hw_abort (current, "error parsing integer property %s (%s)", + property_name, property_value); + else if (nr_entries == 1) + hw_add_integer_property (current, property_name, words[0]); + else + { + int i; + for (i = 0; i < nr_entries; i++) + { + H2BE (words[i]); + } + /* perhaphs integer array property is better */ + hw_add_array_property (current, property_name, words, + sizeof(words[0]) * nr_entries); + } +} + + +/* <string> ... */ + +static void +parse_string_property (struct hw *current, + const char *property_name, + const char *property_value) +{ + char **strings; + const char *chp; + int nr_strings; + int approx_nr_strings; + + /* get an estimate as to the number of strings by counting double + quotes */ + approx_nr_strings = 2; + for (chp = property_value; *chp; chp++) + { + if (*chp == '"') + approx_nr_strings++; + } + approx_nr_strings = (approx_nr_strings) / 2; + + /* create a string buffer for that many (plus a null) */ + strings = (char**) zalloc ((approx_nr_strings + 1) * sizeof(char*)); + + /* now find all the strings */ + chp = property_value; + nr_strings = 0; + while (1) + { + + /* skip leading space */ + while (*chp != '\0' && isspace (*chp)) + chp += 1; + if (*chp == '\0') + break; + + /* copy it in */ + if (*chp == '"') + { + /* a quoted string - watch for '\' et.al. */ + /* estimate the size and allocate space for it */ + int pos; + chp++; + pos = 0; + while (chp[pos] != '\0' && chp[pos] != '"') + { + if (chp[pos] == '\\' && chp[pos+1] != '\0') + pos += 2; + else + pos += 1; + } + strings[nr_strings] = zalloc (pos + 1); + /* copy the string over */ + pos = 0; + while (*chp != '\0' && *chp != '"') + { + if (*chp == '\\' && *(chp+1) != '\0') { + strings[nr_strings][pos] = *(chp+1); + chp += 2; + pos++; + } + else + { + strings[nr_strings][pos] = *chp; + chp += 1; + pos++; + } + } + if (*chp != '\0') + chp++; + strings[nr_strings][pos] = '\0'; + } + else + { + /* copy over a single unquoted token */ + int len = 0; + while (chp[len] != '\0' && !isspace(chp[len])) + len++; + strings[nr_strings] = zalloc(len + 1); + strncpy(strings[nr_strings], chp, len); + strings[nr_strings][len] = '\0'; + chp += len; + } + nr_strings++; + if (nr_strings > approx_nr_strings) + hw_abort (current, "String property %s badly formatted", + property_name); + } + ASSERT (strings[nr_strings] == NULL); /* from zalloc */ + + /* install it */ + if (nr_strings == 0) + hw_add_string_property (current, property_name, ""); + else if (nr_strings == 1) + hw_add_string_property (current, property_name, strings[0]); + else + { + const char **specs = (const char**) strings; /* stop a bogus error */ + hw_add_string_array_property (current, property_name, + specs, nr_strings); + } + + /* flush the created string */ + while (nr_strings > 0) + { + nr_strings--; + zfree (strings[nr_strings]); + } + zfree(strings); +} + + +/* <path-to-ihandle-device> */ + +#if NOT_YET +static void +parse_ihandle_property (struct hw *current, + const char *property, + const char *value) +{ + ihandle_runtime_property_spec ihandle; + + /* pass the full path */ + ihandle.full_path = value; + + /* save this ready for the ihandle create */ + hw_add_ihandle_runtime_property (current, property, + &ihandle); +} +#endif + + +struct hw * +hw_tree_create (SIM_DESC sd, + const char *family) +{ + return hw_create (sd, NULL, family, family, NULL, NULL); +} + +void +hw_tree_delete (struct hw *me) +{ + /* Need to allow devices to disapear under our feet */ + while (hw_child (me) != NULL) + { + hw_tree_delete (hw_child (me)); + } + hw_delete (me); +} + + +struct hw * +hw_tree_parse (struct hw *current, + const char *fmt, + ...) +{ + va_list ap; + va_start (ap, fmt); + current = hw_tree_vparse (current, fmt, ap); + va_end (ap); + return current; +} + +struct hw * +hw_tree_vparse (struct hw *current, + const char *fmt, + va_list ap) +{ + char device_specifier[1024]; + name_specifier spec; + + /* format the path */ + vsprintf (device_specifier, fmt, ap); + if (strlen (device_specifier) >= sizeof (device_specifier)) + hw_abort (NULL, "device_tree_add_deviced: buffer overflow\n"); + + /* construct the tree down to the final struct hw */ + current = split_fill_path (current, device_specifier, &spec); + + /* is there an interrupt spec */ + if (spec.property == NULL + && spec.value != NULL) + { + char *op = split_value (&spec); + switch (op[0]) + { + case '>': + { + char *my_port_name = split_value (&spec); + int my_port; + char *dest_port_name = split_value (&spec); + int dest_port; + name_specifier dest_spec; + char *dest_hw_name = split_value (&spec); + struct hw *dest; + /* find my name */ + if (!hw_finished_p (current)) + hw_finish (current); + my_port = hw_port_decode (current, my_port_name, output_port); + /* find the dest device and port */ + dest = split_fill_path (current, dest_hw_name, &dest_spec); + if (!hw_finished_p (dest)) + hw_finish (dest); + dest_port = hw_port_decode (dest, dest_port_name, + input_port); + /* connect the two */ + hw_port_attach (current, + my_port, + dest, + dest_port, + permenant_object); + break; + } + default: + hw_abort (current, "unreconised interrupt spec %s\n", spec.value); + break; + } + } + + /* is there a property */ + if (spec.property != NULL) + { + if (strcmp (spec.value, "true") == 0) + hw_add_boolean_property (current, spec.property, 1); + else if (strcmp (spec.value, "false") == 0) + hw_add_boolean_property (current, spec.property, 0); + else + { + const struct hw_property *property; + switch (spec.value[0]) + { +#if NOT_YET + case '*': + { + parse_ihandle_property (current, spec.property, spec.value + 1); + break; + } +#endif + case '[': + { + unsigned8 words[1024]; + char *curr = spec.value + 1; + int nr_words = 0; + while (1) + { + char *next; + words[nr_words] = H2BE_1 (strtoul (curr, &next, 0)); + if (curr == next) + break; + curr = next; + nr_words += 1; + } + hw_add_array_property (current, spec.property, + words, sizeof(words[0]) * nr_words); + break; + } + case '"': + { + parse_string_property (current, spec.property, spec.value); + break; + } + case '!': + { + spec.value++; + property = hw_tree_find_property (current, spec.value); + if (property == NULL) + hw_abort (current, "property %s not found\n", spec.value); + hw_add_duplicate_property (current, + spec.property, + property); + break; + } + default: + { + if (strcmp (spec.property, "reg") == 0 + || strcmp (spec.property, "assigned-addresses") == 0 + || strcmp (spec.property, "alternate-reg") == 0) + { + parse_reg_property (current, spec.property, spec.value); + } + else if (strcmp (spec.property, "ranges") == 0) + { + parse_ranges_property (current, spec.property, spec.value); + } + else if (isdigit(spec.value[0]) + || (spec.value[0] == '-' && isdigit(spec.value[1])) + || (spec.value[0] == '+' && isdigit(spec.value[1]))) + { + parse_integer_property(current, spec.property, spec.value); + } + else + parse_string_property(current, spec.property, spec.value); + break; + } + } + } + } + return current; +} + + +static void +finish_hw_tree (struct hw *me, + void *data) +{ + if (!hw_finished_p (me)) + hw_finish (me); +} + +void +hw_tree_finish (struct hw *root) +{ + hw_tree_traverse (root, finish_hw_tree, NULL, NULL); +} + + + +void +hw_tree_traverse (struct hw *root, + hw_tree_traverse_function *prefix, + hw_tree_traverse_function *postfix, + void *data) +{ + struct hw *child; + if (prefix != NULL) + prefix (root, data); + for (child = hw_child (root); + child != NULL; + child = hw_sibling (child)) + { + hw_tree_traverse (child, prefix, postfix, data); + } + if (postfix != NULL) + postfix (root, data); +} + + + +struct printer { + hw_tree_print_callback *print; + void *file; +}; + +static void +print_address (struct hw *bus, + const hw_unit *phys, + struct printer *p) +{ + char unit[32]; + hw_unit_encode (bus, phys, unit, sizeof(unit)); + p->print (p->file, " %s", unit); +} + +static void +print_size (struct hw *bus, + const hw_unit *size, + struct printer *p) +{ + int i; + for (i = 0; i < size->nr_cells; i++) + if (size->cells[i] != 0) + break; + if (i < size->nr_cells) { + p->print (p->file, " 0x%lx", (unsigned long) size->cells[i]); + i++; + for (; i < size->nr_cells; i++) + p->print (p->file, ",0x%lx", (unsigned long) size->cells[i]); + } + else + p->print (p->file, " 0"); +} + +static void +print_reg_property (struct hw *me, + const struct hw_property *property, + struct printer *p) +{ + int reg_nr; + reg_property_spec reg; + for (reg_nr = 0; + hw_find_reg_array_property (me, property->name, reg_nr, ®); + reg_nr++) { + print_address (hw_parent (me), ®.address, p); + print_size (me, ®.size, p); + } +} + +static void +print_ranges_property (struct hw *me, + const struct hw_property *property, + struct printer *p) +{ + int range_nr; + range_property_spec range; + for (range_nr = 0; + hw_find_range_array_property (me, property->name, range_nr, &range); + range_nr++) + { + print_address (me, &range.child_address, p); + print_address (hw_parent (me), &range.parent_address, p); + print_size (me, &range.size, p); + } +} + +static void +print_string (struct hw *me, + const char *string, + struct printer *p) +{ + p->print (p->file, " \""); + while (*string != '\0') { + switch (*string) { + case '"': + p->print (p->file, "\\\""); + break; + case '\\': + p->print (p->file, "\\\\"); + break; + default: + p->print (p->file, "%c", *string); + break; + } + string++; + } + p->print (p->file, "\""); +} + +static void +print_string_array_property (struct hw *me, + const struct hw_property *property, + struct printer *p) +{ + int nr; + string_property_spec string; + for (nr = 0; + hw_find_string_array_property (me, property->name, nr, &string); + nr++) + { + print_string (me, string, p); + } +} + +static void +print_properties (struct hw *me, + struct printer *p) +{ + const struct hw_property *property; + for (property = hw_find_property (me, NULL); + property != NULL; + property = hw_next_property (property)) + { + if (hw_parent (me) == NULL) + p->print (p->file, "/%s", property->name); + else + p->print (p->file, "%s/%s", hw_path (me), property->name); + if (property->original != NULL) + { + p->print (p->file, " !"); + p->print (p->file, "%s/%s", + hw_path (property->original->owner), + property->original->name); + } + else + { + switch (property->type) + { + case array_property: + { + if ((property->sizeof_array % sizeof (signed_cell)) == 0) + { + unsigned_cell *w = (unsigned_cell*) property->array; + int cell_nr; + for (cell_nr = 0; + cell_nr < (property->sizeof_array / sizeof (unsigned_cell)); + cell_nr++) + { + p->print (p->file, " 0x%lx", (unsigned long) BE2H_cell (w[cell_nr])); + } + } + else + { + unsigned8 *w = (unsigned8*)property->array; + p->print (p->file, " ["); + while ((char*)w - (char*)property->array < property->sizeof_array) { + p->print (p->file, " 0x%2x", BE2H_1 (*w)); + w++; + } + } + break; + } + case boolean_property: + { + int b = hw_find_boolean_property(me, property->name); + p->print (p->file, " %s", b ? "true" : "false"); + break; + } +#if NOT_YET + case ihandle_property: + { + if (property->array != NULL) + { + device_instance *instance = hw_find_ihandle_property (me, property->name); + p->print (p->file, " *%s", device_instance_path(instance)); + } + else + { + /* not yet initialized, ask the device for the path */ + ihandle_runtime_property_spec spec; + hw_find_ihandle_runtime_property (me, property->name, &spec); + p->print (p->file, " *%s", spec.full_path); + } + break; + } +#endif + case integer_property: + { + unsigned_word w = hw_find_integer_property (me, property->name); + p->print (p->file, " 0x%lx", (unsigned long)w); + break; + } + case range_array_property: + { + print_ranges_property (me, property, p); + break; + } + case reg_array_property: + { + print_reg_property (me, property, p); + break; + } + case string_property: + { + const char *s = hw_find_string_property (me, property->name); + print_string (me, s, p); + break; + } + case string_array_property: + { + print_string_array_property (me, property, p); + break; + } + } + } + p->print (p->file, "\n"); + } +} + +static void +print_interrupts (struct hw *me, + int my_port, + struct hw *dest, + int dest_port, + void *data) +{ + struct printer *p = data; + char src[32]; + char dst[32]; + hw_port_encode (me, my_port, src, sizeof(src), output_port); + hw_port_encode (dest, dest_port, dst, sizeof(dst), input_port); + p->print (p->file, + "%s > %s %s %s\n", + hw_path (me), + src, dst, + hw_path (dest)); +} + +static void +print_device (struct hw *me, + void *data) +{ + struct printer *p = data; + p->print (p->file, "%s\n", hw_path (me)); + print_properties (me, p); + hw_port_traverse (me, print_interrupts, data); +} + +void +hw_tree_print (struct hw *root, + hw_tree_print_callback *print, + void *file) +{ + struct printer p; + p.print = print; + p.file = file; + hw_tree_traverse (root, + print_device, NULL, + &p); +} + + + +#if NOT_YET +device_instance * +tree_instance(struct hw *root, + const char *device_specifier) +{ + /* find the device node */ + struct hw *me; + name_specifier spec; + if (!split_device_specifier(root, device_specifier, &spec)) + return NULL; + me = split_find_device(root, &spec); + if (spec.name != NULL) + return NULL; + /* create the instance */ + return device_create_instance(me, device_specifier, spec.last_args); +} +#endif + +struct hw * +hw_tree_find_device (struct hw *root, + const char *path_to_device) +{ + struct hw *node; + name_specifier spec; + + /* parse the path */ + split_device_specifier (root, path_to_device, &spec); + if (spec.value != NULL) + return NULL; /* something wierd */ + + /* now find it */ + node = split_find_device (root, &spec); + if (spec.name != NULL) + return NULL; /* not a leaf */ + + return node; +} + + +const struct hw_property * +hw_tree_find_property (struct hw *root, + const char *path_to_property) +{ + name_specifier spec; + if (!split_property_specifier (root, path_to_property, &spec)) + hw_abort (root, "Invalid property path %s", path_to_property); + root = split_find_device (root, &spec); + if (spec.name != NULL) + return NULL; /* not a leaf */ + return hw_find_property (root, spec.property); +} + +int +hw_tree_find_boolean_property (struct hw *root, + const char *path_to_property) +{ + name_specifier spec; + if (!split_property_specifier (root, path_to_property, &spec)) + hw_abort (root, "Invalid property path %s", path_to_property); + root = split_find_device (root, &spec); + if (spec.name != NULL) + hw_abort (root, "device \"%s\" not found (property \"%s\")", + spec.name, path_to_property); + return hw_find_boolean_property (root, spec.property); +} + +signed_cell +hw_tree_find_integer_property (struct hw *root, + const char *path_to_property) +{ + name_specifier spec; + if (!split_property_specifier (root, path_to_property, &spec)) + hw_abort (root, "Invalid property path %s", path_to_property); + root = split_find_device (root, &spec); + if (spec.name != NULL) + hw_abort (root, "device \"%s\" not found (property \"%s\")", + spec.name, path_to_property); + return hw_find_integer_property (root, spec.property); +} + +#if NOT_YET +device_instance * +hw_tree_find_ihandle_property (struct hw *root, + const char *path_to_property) +{ + struct hw *root; + name_specifier spec; + if (!split_property_specifier (root, path_to_property, &spec)) + hw_abort (root, "Invalid property path %s", path_to_property); + root = split_find_device (root, &spec); + if (spec.name != NULL) + hw_abort (root, "device \"%s\" not found (property \"%s\")", + spec.name, path_to_property); + return hw_find_ihandle_property (root, spec.property); +} +#endif + +const char * +hw_tree_find_string_property (struct hw *root, + const char *path_to_property) +{ + name_specifier spec; + if (!split_property_specifier (root, path_to_property, &spec)) + hw_abort (root, "Invalid property path %s", path_to_property); + root = split_find_device (root, &spec); + if (spec.name != NULL) + hw_abort (root, "device \"%s\" not found (property \"%s\")", + spec.name, path_to_property); + return hw_find_string_property (root, spec.property); +} diff --git a/sim/common/hw-tree.h b/sim/common/hw-tree.h new file mode 100644 index 0000000..bfa5681 --- /dev/null +++ b/sim/common/hw-tree.h @@ -0,0 +1,119 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef HW_TREE +#define HW_TREE + + +struct hw *hw_tree_create +(SIM_DESC sd, + const char *device); + +void hw_tree_delete +(struct hw *root); + +struct hw *hw_tree_parse +(struct hw *root, + const char *fmt, + ...) __attribute__ ((format (printf, 2, 3))); + +struct hw *hw_tree_vparse +(struct hw *root, + const char *fmt, + va_list ap); + + +void hw_tree_finish +(struct hw *root); + +typedef void (hw_tree_print_callback) + (void *, + const char *fmt, + ...); + +void hw_tree_print +(struct hw *root, + hw_tree_print_callback *print, + void *file); + + +/* Tree traversal:: + + The entire device tree can be traversed using the + <<device_tree_traverse()>> function. The traversal can be in + either prefix or postfix order. + + */ + +typedef void (hw_tree_traverse_function) + (struct hw *device, + void *data); + +void hw_tree_traverse +(struct hw *root, + hw_tree_traverse_function *prefix, + hw_tree_traverse_function *postfix, + void *data); + + +/* Tree lookup:: + + The function <<hw_tree_find_device()>> will attempt to locate the + specified device within the tree. If the device is not found a + NULL device is returned. + + */ + +struct hw * hw_tree_find_device +(struct hw *root, + const char *path); + + +const struct hw_property *hw_tree_find_property +(struct hw *root, + const char *path_to_property); + +int hw_tree_find_boolean_property +(struct hw *root, + const char *path_to_property); + +signed_cell hw_tree_find_integer_property +(struct hw *root, + const char *path_to_property); + +#if NOT_YET +device_instance *hw_tree_find_ihandle_property +(struct hw *root, + const char *path_to_property); +#endif + +const char *hw_tree_find_string_property +(struct hw *root, + const char *path_to_property); + + +/* Perform a soft reset on the created tree. */ + +void hw_tree_reset +(struct hw *root); + + +#endif diff --git a/sim/common/nltvals.def b/sim/common/nltvals.def new file mode 100644 index 0000000..b5e82fc --- /dev/null +++ b/sim/common/nltvals.def @@ -0,0 +1,418 @@ +/* Newlib/libgloss macro values needed by remote target support. */ +/* This file is machine generated by gennltvals.sh. */ +#ifdef errno_defs +/* from errno.h */ +/* from sys/errno.h */ +/* begin errno target macros */ + { "E2BIG", 7 }, + { "EACCES", 13 }, + { "EADDRINUSE", 112 }, + { "EADDRNOTAVAIL", 125 }, + { "EADV", 68 }, + { "EAFNOSUPPORT", 106 }, + { "EAGAIN", 11 }, + { "EALREADY", 120 }, + { "EBADE", 50 }, + { "EBADF", 9 }, + { "EBADFD", 81 }, + { "EBADMSG", 77 }, + { "EBADR", 51 }, + { "EBADRQC", 54 }, + { "EBADSLT", 55 }, + { "EBFONT", 57 }, + { "EBUSY", 16 }, + { "ECHILD", 10 }, + { "ECHRNG", 37 }, + { "ECOMM", 70 }, + { "ECONNABORTED", 113 }, + { "ECONNREFUSED", 111 }, + { "ECONNRESET", 104 }, + { "EDEADLK", 45 }, + { "EDEADLOCK", 56 }, + { "EDESTADDRREQ", 121 }, + { "EDOM", 33 }, + { "EDOTDOT", 76 }, + { "EDQUOT", 132 }, + { "EEXIST", 17 }, + { "EFAULT", 14 }, + { "EFBIG", 27 }, + { "EHOSTDOWN", 117 }, + { "EHOSTUNREACH", 118 }, + { "EIDRM", 36 }, + { "EINPROGRESS", 119 }, + { "EINTR", 4 }, + { "EINVAL", 22 }, + { "EIO", 5 }, + { "EISCONN", 127 }, + { "EISDIR", 21 }, + { "EL2HLT", 44 }, + { "EL2NSYNC", 38 }, + { "EL3HLT", 39 }, + { "EL3RST", 40 }, + { "ELBIN", 75 }, + { "ELIBACC", 83 }, + { "ELIBBAD", 84 }, + { "ELIBEXEC", 87 }, + { "ELIBMAX", 86 }, + { "ELIBSCN", 85 }, + { "ELNRNG", 41 }, + { "ELOOP", 92 }, + { "EMFILE", 24 }, + { "EMLINK", 31 }, + { "EMSGSIZE", 122 }, + { "EMULTIHOP", 74 }, + { "ENAMETOOLONG", 91 }, + { "ENETDOWN", 115 }, + { "ENETRESET", 126 }, + { "ENETUNREACH", 114 }, + { "ENFILE", 23 }, + { "ENMFILE", 89 }, + { "ENOANO", 53 }, + { "ENOBUFS", 105 }, + { "ENOCSI", 43 }, + { "ENODATA", 61 }, + { "ENODEV", 19 }, + { "ENOENT", 2 }, + { "ENOEXEC", 8 }, + { "ENOLCK", 46 }, + { "ENOLINK", 67 }, + { "ENOMEM", 12 }, + { "ENOMSG", 35 }, + { "ENONET", 64 }, + { "ENOPKG", 65 }, + { "ENOPROTOOPT", 109 }, + { "ENOSPC", 28 }, + { "ENOSR", 63 }, + { "ENOSTR", 60 }, + { "ENOSYS", 88 }, + { "ENOTBLK", 15 }, + { "ENOTCONN", 128 }, + { "ENOTDIR", 20 }, + { "ENOTEMPTY", 90 }, + { "ENOTSOCK", 108 }, + { "ENOTSUP", 134 }, + { "ENOTTY", 25 }, + { "ENOTUNIQ", 80 }, + { "ENXIO", 6 }, + { "EOPNOTSUPP", 95 }, + { "EPERM", 1 }, + { "EPFNOSUPPORT", 96 }, + { "EPIPE", 32 }, + { "EPROCLIM", 130 }, + { "EPROTO", 71 }, + { "EPROTONOSUPPORT", 123 }, + { "EPROTOTYPE", 107 }, + { "ERANGE", 34 }, + { "EREMCHG", 82 }, + { "EREMOTE", 66 }, + { "EROFS", 30 }, + { "ESHUTDOWN", 110 }, + { "ESOCKTNOSUPPORT", 124 }, + { "ESPIPE", 29 }, + { "ESRCH", 3 }, + { "ESRMNT", 69 }, + { "ESTALE", 133 }, + { "ETIME", 62 }, + { "ETIMEDOUT", 116 }, + { "ETOOMANYREFS", 129 }, + { "ETXTBSY", 26 }, + { "EUNATCH", 42 }, + { "EUSERS", 131 }, + { "EWOULDBLOCK", 11 }, + { "EXDEV", 18 }, + { "EXFULL", 52 }, +/* end errno target macros */ +#endif +#ifdef signal_defs +/* from signal.h */ +/* from sys/signal.h */ +/* begin signal target macros */ + { "SIGABRT", 6 }, + { "SIGALRM", 14 }, + { "SIGBUS", 10 }, + { "SIGCHLD", 20 }, + { "SIGCLD", 20 }, + { "SIGCONT", 19 }, + { "SIGEMT", 7 }, + { "SIGFPE", 8 }, + { "SIGHUP", 1 }, + { "SIGILL", 4 }, + { "SIGINT", 2 }, + { "SIGIO", 23 }, + { "SIGIOT", 6 }, + { "SIGKILL", 9 }, + { "SIGLOST", 29 }, + { "SIGPIPE", 13 }, + { "SIGPOLL", 23 }, + { "SIGPROF", 27 }, + { "SIGQUIT", 3 }, + { "SIGSEGV", 11 }, + { "SIGSTOP", 17 }, + { "SIGSYS", 12 }, + { "SIGTERM", 15 }, + { "SIGTRAP", 5 }, + { "SIGTSTP", 18 }, + { "SIGTTIN", 21 }, + { "SIGTTOU", 22 }, + { "SIGURG", 16 }, + { "SIGUSR1", 30 }, + { "SIGUSR2", 31 }, + { "SIGVTALRM", 26 }, + { "SIGWINCH", 28 }, + { "SIGXCPU", 24 }, + { "SIGXFSZ", 25 }, +/* end signal target macros */ +#endif +#ifdef open_defs +/* from fcntl.h */ +/* from sys/fcntl.h */ +/* begin open target macros */ + { "O_ACCMODE", (0 | 1 | 2 ) }, + { "O_APPEND", 0x0008 }, + { "O_CREAT", 0x0200 }, + { "O_EXCL", 0x0800 }, + { "O_NOCTTY", 0x8000 }, + { "O_NONBLOCK", 0x4000 }, + { "O_RDONLY", 0 }, + { "O_RDWR", 2 }, + { "O_SYNC", 0x2000 }, + { "O_TRUNC", 0x0400 }, + { "O_WRONLY", 1 }, +/* end open target macros */ +#endif +#ifdef NL_TARGET_d10v +#ifdef sys_defs +/* from syscall.h */ +/* begin d10v sys target macros */ + { "SYS_ARG", 24 }, + { "SYS_chdir", 12 }, + { "SYS_chmod", 15 }, + { "SYS_chown", 16 }, + { "SYS_close", 6 }, + { "SYS_creat", 8 }, + { "SYS_execv", 11 }, + { "SYS_execve", 59 }, + { "SYS_exit", 1 }, + { "SYS_fork", 2 }, + { "SYS_fstat", 22 }, + { "SYS_getpid", 20 }, + { "SYS_isatty", 21 }, + { "SYS_kill", 60 }, + { "SYS_link", 9 }, + { "SYS_lseek", 19 }, + { "SYS_mknod", 14 }, + { "SYS_open", 5 }, + { "SYS_pipe", 42 }, + { "SYS_read", 3 }, + { "SYS_stat", 38 }, + { "SYS_time", 23 }, + { "SYS_unlink", 10 }, + { "SYS_utime", 201 }, + { "SYS_wait", 202 }, + { "SYS_wait4", 7 }, + { "SYS_write", 4 }, +/* end d10v sys target macros */ +#endif +#endif +#ifdef NL_TARGET_d30v +#ifdef sys_defs +/* from syscall.h */ +/* begin d30v sys target macros */ + { "SYS_argv", 13 }, + { "SYS_argvlen", 12 }, + { "SYS_chdir", 14 }, + { "SYS_chmod", 16 }, + { "SYS_close", 3 }, + { "SYS_exit", 1 }, + { "SYS_fstat", 10 }, + { "SYS_getpid", 8 }, + { "SYS_kill", 9 }, + { "SYS_lseek", 6 }, + { "SYS_open", 2 }, + { "SYS_read", 4 }, + { "SYS_stat", 15 }, + { "SYS_time", 18 }, + { "SYS_unlink", 7 }, + { "SYS_utime", 17 }, + { "SYS_write", 5 }, +/* end d30v sys target macros */ +#endif +#endif +#ifdef NL_TARGET_fr30 +#ifdef sys_defs +/* from syscall.h */ +/* begin fr30 sys target macros */ + { "SYS_argv", 13 }, + { "SYS_argvlen", 12 }, + { "SYS_chdir", 14 }, + { "SYS_chmod", 16 }, + { "SYS_close", 3 }, + { "SYS_exit", 1 }, + { "SYS_fstat", 10 }, + { "SYS_getpid", 8 }, + { "SYS_kill", 9 }, + { "SYS_lseek", 6 }, + { "SYS_open", 2 }, + { "SYS_read", 4 }, + { "SYS_stat", 15 }, + { "SYS_time", 18 }, + { "SYS_unlink", 7 }, + { "SYS_utime", 17 }, + { "SYS_write", 5 }, +/* end fr30 sys target macros */ +#endif +#endif +#ifdef NL_TARGET_i960 +#ifdef sys_defs +/* from syscall.h */ +/* begin i960 sys target macros */ + { "SYS_argv", 13 }, + { "SYS_argvlen", 12 }, + { "SYS_chdir", 14 }, + { "SYS_chmod", 16 }, + { "SYS_close", 234 }, + { "SYS_exit", 257 }, + { "SYS_fstat", 10 }, + { "SYS_getpid", 8 }, + { "SYS_kill", 9 }, + { "SYS_lseek", 233 }, + { "SYS_open", 230 }, + { "SYS_read", 231 }, + { "SYS_stat", 15 }, + { "SYS_time", 18 }, + { "SYS_unlink", 7 }, + { "SYS_utime", 17 }, + { "SYS_write", 232 }, +/* end i960 sys target macros */ +#endif +#endif +#ifdef NL_TARGET_m32r +#ifdef sys_defs +/* from syscall.h */ +/* begin m32r sys target macros */ + { "SYS_argv", 13 }, + { "SYS_argvlen", 12 }, + { "SYS_chdir", 14 }, + { "SYS_chmod", 16 }, + { "SYS_close", 3 }, + { "SYS_exit", 1 }, + { "SYS_fstat", 10 }, + { "SYS_getpid", 8 }, + { "SYS_kill", 9 }, + { "SYS_lseek", 6 }, + { "SYS_open", 2 }, + { "SYS_read", 4 }, + { "SYS_stat", 15 }, + { "SYS_time", 18 }, + { "SYS_unlink", 7 }, + { "SYS_utime", 17 }, + { "SYS_write", 5 }, +/* end m32r sys target macros */ +#endif +#endif +#ifdef NL_TARGET_mn10200 +#ifdef sys_defs +/* from syscall.h */ +/* begin mn10200 sys target macros */ + { "SYS_argv", 13 }, + { "SYS_argvlen", 12 }, + { "SYS_chdir", 14 }, + { "SYS_chmod", 16 }, + { "SYS_close", 3 }, + { "SYS_exit", 1 }, + { "SYS_fstat", 10 }, + { "SYS_getpid", 8 }, + { "SYS_kill", 9 }, + { "SYS_lseek", 6 }, + { "SYS_open", 2 }, + { "SYS_read", 4 }, + { "SYS_stat", 15 }, + { "SYS_time", 18 }, + { "SYS_unlink", 7 }, + { "SYS_utime", 17 }, + { "SYS_write", 5 }, +/* end mn10200 sys target macros */ +#endif +#endif +#ifdef NL_TARGET_mn10300 +#ifdef sys_defs +/* from syscall.h */ +/* begin mn10300 sys target macros */ + { "SYS_argv", 13 }, + { "SYS_argvlen", 12 }, + { "SYS_chdir", 14 }, + { "SYS_chmod", 16 }, + { "SYS_close", 3 }, + { "SYS_exit", 1 }, + { "SYS_fstat", 10 }, + { "SYS_getpid", 8 }, + { "SYS_kill", 9 }, + { "SYS_lseek", 6 }, + { "SYS_open", 2 }, + { "SYS_read", 4 }, + { "SYS_stat", 15 }, + { "SYS_time", 18 }, + { "SYS_unlink", 7 }, + { "SYS_utime", 17 }, + { "SYS_write", 5 }, +/* end mn10300 sys target macros */ +#endif +#endif +#ifdef NL_TARGET_sparc +#ifdef sys_defs +/* from syscall.h */ +/* begin sparc sys target macros */ + { "SYS_argv", 13 }, + { "SYS_argvlen", 12 }, + { "SYS_chdir", 14 }, + { "SYS_chmod", 16 }, + { "SYS_close", 3 }, + { "SYS_exit", 1 }, + { "SYS_fstat", 10 }, + { "SYS_getpid", 8 }, + { "SYS_kill", 9 }, + { "SYS_lseek", 6 }, + { "SYS_open", 2 }, + { "SYS_read", 4 }, + { "SYS_stat", 15 }, + { "SYS_time", 18 }, + { "SYS_unlink", 7 }, + { "SYS_utime", 17 }, + { "SYS_write", 5 }, +/* end sparc sys target macros */ +#endif +#endif +#ifdef NL_TARGET_v850 +#ifdef sys_defs +/* from syscall.h */ +/* begin v850 sys target macros */ + { "SYS_ARG", 24 }, + { "SYS_chdir", 12 }, + { "SYS_chmod", 15 }, + { "SYS_chown", 16 }, + { "SYS_close", 6 }, + { "SYS_creat", 8 }, + { "SYS_execv", 11 }, + { "SYS_execve", 59 }, + { "SYS_exit", 1 }, + { "SYS_fork", 2 }, + { "SYS_fstat", 22 }, + { "SYS_getpid", 20 }, + { "SYS_gettimeofday", 116 }, + { "SYS_isatty", 21 }, + { "SYS_link", 9 }, + { "SYS_lseek", 19 }, + { "SYS_mknod", 14 }, + { "SYS_open", 5 }, + { "SYS_pipe", 42 }, + { "SYS_read", 3 }, + { "SYS_stat", 38 }, + { "SYS_time", 23 }, + { "SYS_unlink", 10 }, + { "SYS_utime", 201 }, + { "SYS_wait", 202 }, + { "SYS_wait4", 7 }, + { "SYS_write", 4 }, +/* end v850 sys target macros */ +#endif +#endif diff --git a/sim/common/nrun.c b/sim/common/nrun.c new file mode 100644 index 0000000..42be33e --- /dev/null +++ b/sim/common/nrun.c @@ -0,0 +1,214 @@ +/* New version of run front end support for simulators. + Copyright (C) 1997 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <signal.h> +#include "sim-main.h" + +#include "bfd.h" + +#ifdef HAVE_ENVIRON +extern char **environ; +#endif + +static void usage (void); + +extern host_callback default_callback; + +static char *myname; + +static SIM_DESC sd; + +static RETSIGTYPE +cntrl_c (int sig) +{ + if (! sim_stop (sd)) + { + fprintf (stderr, "Quit!\n"); + exit (1); + } +} + +int +main (int argc, char **argv) +{ + char *name; + char **prog_argv = NULL; + struct _bfd *prog_bfd; + enum sim_stop reason; + int sigrc = 0; + int single_step = 0; + RETSIGTYPE (*prev_sigint) (); + + myname = argv[0] + strlen (argv[0]); + while (myname > argv[0] && myname[-1] != '/') + --myname; + + /* INTERNAL: When MYNAME is `step', single step the simulator + instead of allowing it to run free. The sole purpose of this + HACK is to allow the sim_resume interface's step argument to be + tested without having to build/run gdb. */ + if (strlen (myname) > 4 && strcmp (myname - 4, "step") == 0) + { + single_step = 1; + } + + /* Create an instance of the simulator. */ + default_callback.init (&default_callback); + sd = sim_open (SIM_OPEN_STANDALONE, &default_callback, NULL, argv); + if (sd == 0) + exit (1); + if (STATE_MAGIC (sd) != SIM_MAGIC_NUMBER) + { + fprintf (stderr, "Internal error - bad magic number in simulator struct\n"); + abort (); + } + + /* Was there a program to run? */ + prog_argv = STATE_PROG_ARGV (sd); + prog_bfd = STATE_PROG_BFD (sd); + if (prog_argv == NULL || *prog_argv == NULL) + usage (); + + name = *prog_argv; + + /* For simulators that don't open prog during sim_open() */ + if (prog_bfd == NULL) + { + prog_bfd = bfd_openr (name, 0); + if (prog_bfd == NULL) + { + fprintf (stderr, "%s: can't open \"%s\": %s\n", + myname, name, bfd_errmsg (bfd_get_error ())); + exit (1); + } + if (!bfd_check_format (prog_bfd, bfd_object)) + { + fprintf (stderr, "%s: \"%s\" is not an object file: %s\n", + myname, name, bfd_errmsg (bfd_get_error ())); + exit (1); + } + } + + if (STATE_VERBOSE_P (sd)) + printf ("%s %s\n", myname, name); + + /* Load the program into the simulator. */ + if (sim_load (sd, name, prog_bfd, 0) == SIM_RC_FAIL) + exit (1); + + /* Prepare the program for execution. */ +#ifdef HAVE_ENVIRON + sim_create_inferior (sd, prog_bfd, prog_argv, environ); +#else + sim_create_inferior (sd, prog_bfd, prog_argv, NULL); +#endif + + /* Run/Step the program. */ + if (single_step) + { + do + { + prev_sigint = signal (SIGINT, cntrl_c); + sim_resume (sd, 1/*step*/, 0); + signal (SIGINT, prev_sigint); + sim_stop_reason (sd, &reason, &sigrc); + + if ((reason == sim_stopped) && + (sigrc == sim_signal_to_host (sd, SIM_SIGINT))) + break; /* exit on control-C */ + } + /* remain on breakpoint or signals in oe mode*/ + while (((reason == sim_signalled) && + (sigrc == sim_signal_to_host (sd, SIM_SIGTRAP))) || + ((reason == sim_stopped) && + (STATE_ENVIRONMENT (sd) == OPERATING_ENVIRONMENT))); + } + else do + { +#if defined (HAVE_SIGACTION) && defined (SA_RESTART) + struct sigaction sa, osa; + sa.sa_handler = cntrl_c; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + sigaction (SIGINT, &sa, &osa); + prev_sigint = osa.sa_handler; +#else + prev_sigint = signal (SIGINT, cntrl_c); +#endif + sim_resume (sd, 0, sigrc); + signal (SIGINT, prev_sigint); + sim_stop_reason (sd, &reason, &sigrc); + + if ((reason == sim_stopped) && + (sigrc == sim_signal_to_host (sd, SIM_SIGINT))) + break; /* exit on control-C */ + + /* remain on signals in oe mode */ + } while ((reason == sim_stopped) && + (STATE_ENVIRONMENT (sd) == OPERATING_ENVIRONMENT)); + + /* Print any stats the simulator collected. */ + sim_info (sd, 0); + + /* Shutdown the simulator. */ + sim_close (sd, 0); + + /* If reason is sim_exited, then sigrc holds the exit code which we want + to return. If reason is sim_stopped or sim_signalled, then sigrc holds + the signal that the simulator received; we want to return that to + indicate failure. */ + +#ifdef SIM_H8300 /* FIXME: Ugh. grep for SLEEP in compile.c */ + if (sigrc == SIGILL) + abort (); + sigrc = 0; +#else + /* Why did we stop? */ + switch (reason) + { + case sim_signalled: + case sim_stopped: + if (sigrc != 0) + fprintf (stderr, "program stopped with signal %d.\n", sigrc); + break; + + case sim_exited: + break; + + default: + fprintf (stderr, "program in undefined state (%d:%d)\n", reason, sigrc); + break; + + } +#endif + + return sigrc; +} + +static void +usage () +{ + fprintf (stderr, "Usage: %s [options] program [program args]\n", myname); + fprintf (stderr, "Run `%s --help' for full list of options.\n", myname); + exit (1); +} + + +#ifdef __CYGWIN32__ +/* no-op GUI update hook for standalone sim */ +void (*ui_loop_hook) PARAMS ((int)) = NULL; +#endif diff --git a/sim/common/run.1 b/sim/common/run.1 new file mode 100644 index 0000000..886e20b --- /dev/null +++ b/sim/common/run.1 @@ -0,0 +1,107 @@ +.\" Copyright (c) 1993 Free Software Foundation +.\" See section COPYING for conditions for redistribution +.TH run 1 "13oct1993" "GNU Tools" "GNU Tools" +.de BP +.sp +.ti -.2i +\(** +.. + +.SH NAME +run\(em\&Simulator front-end + +.SH SYNOPSIS +.hy 0 +.na +.TP +.B run +.RB "[\|" \-v "\|]" +." .RB "[\|" \-t "\|]" +.RB "[\|" \-p +.IR freq "\|]" +.RB "[\|" \-m +.IR memory "\|]" +.I program +.ad b +.hy 1 +.SH DESCRIPTION + +Use `\|\c +.BI run " program"\c +\&\|' to execute a binary by interpreting machine instructions on your +host computer. + +.B run +is the same emulator used by GDB's `\|\c +.B target sim\c +\&\|' command. You can run it directly by executing +.B run +if you just want to see your program execute, and do not need any +debugger functionality. You can also use +.B run +to generate profiling information for analysis with +.BR gprof . + +.SH OPTIONS + +.TP +.B \-v +Verbose output. Display the name of the program to run before +execution; after execution, display the number of instructions +executed, the number of machine cycles emulated, the number of +pipeline stalls, the real time taken, the emulated execution time +taken, and a summary of how much profiling information was generated. +." +." .TP +." .B \-t +." `trace', calls a sim_trace routine that does nothing. + +.TP +.BI \-p " freq" +Generate profile information (for use with +.B gprof\c +\&). +.I freq +is the profiling frequency. Write the profiling information to a file called +.BR gmon.out . + +.TP +.BI \-m " memory" +Set the memory size for the emulated machine to two to the power +.IR memory . +The default value is 19, emulating a board with 524288 bytes of memory. + +.PP + +.SH "SEE ALSO" +.RB "`\|" gprof "\|'" +entry in +.B info\c +\&; +.RB "`\|" gdb "\|'" +entry in +.B info\c +\&; +.I +Using GDB: A Guide to the GNU Source-Level Debugger\c +, Richard M. Stallman and Roland H. Pesch. + +.SH COPYING +Copyright (c) 1993 Free Software Foundation, Inc. +.PP +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. +.PP +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. +.PP +Permission is granted to copy and distribute translations of this +manual into another language, under the above conditions for modified +versions, except that this permission notice may be included in +translations approved by the Free Software Foundation instead of in +the original English. + + diff --git a/sim/common/run.c b/sim/common/run.c new file mode 100644 index 0000000..2a701bc --- /dev/null +++ b/sim/common/run.c @@ -0,0 +1,308 @@ +/* run front end support for all the simulators. + Copyright (C) 1992, 93-96, 1997 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Steve Chamberlain sac@cygnus.com, + and others at Cygnus. */ + +#include "config.h" +#include "tconfig.h" + +#include <signal.h> +#include <stdio.h> +#ifdef __STDC__ +#include <stdarg.h> +#else +#include <varargs.h> +#endif + +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif + +#ifdef HAVE_STRING_H +#include <string.h> +#else +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#endif + +#include "libiberty.h" +#include "bfd.h" +#include "callback.h" +#include "remote-sim.h" + +#include "../libiberty/alloca-conf.h" + +static void usage PARAMS ((void)); +extern int optind; +extern char *optarg; + +extern host_callback default_callback; + +static char *myname; + + +/* NOTE: sim_size() and sim_trace() are going away */ +extern int sim_trace PARAMS ((SIM_DESC sd)); + +extern int getopt (); + +static SIM_DESC sd; + +static RETSIGTYPE +cntrl_c (int sig) +{ + if (! sim_stop (sd)) + { + fprintf (stderr, "Quit!\n"); + exit (1); + } +} + +int +main (ac, av) + int ac; + char **av; +{ + RETSIGTYPE (*prev_sigint) (); + bfd *abfd; + int i; + int verbose = 0; + int trace = 0; + char *name; + static char *no_args[4]; + char **sim_argv = &no_args[0]; + char **prog_args; + enum sim_stop reason; + int sigrc; + + myname = av[0] + strlen (av[0]); + while (myname > av[0] && myname[-1] != '/') + --myname; + + /* The first element of sim_open's argv is the program name. */ + no_args[0] = av[0]; +#ifdef SIM_HAVE_BIENDIAN + no_args[1] = "-E"; + no_args[2] = "set-later"; +#endif + + /* FIXME: This is currently being migrated into sim_open. + Simulators that use functions such as sim_size() still require + this. */ + default_callback.init (&default_callback); + sim_set_callbacks (&default_callback); + + /* FIXME: This is currently being rewritten to have each simulator + do all argv processing. */ + +#ifdef SIM_H8300 /* FIXME: quick hack */ + while ((i = getopt (ac, av, "a:c:m:p:s:htv")) != EOF) +#else + while ((i = getopt (ac, av, "a:c:m:p:s:tv")) != EOF) +#endif + switch (i) + { + case 'a': + /* FIXME: Temporary hack. */ + { + int len = strlen (av[0]) + strlen (optarg); + char *argbuf = (char *) alloca (len + 2 + 50); + sprintf (argbuf, "%s %s", av[0], optarg); +#ifdef SIM_HAVE_BIENDIAN + /* The desired endianness must be passed to sim_open. + The value for "set-later" is set when we know what it is. + -E support isn't yet part of the published interface. */ + strcat (argbuf, " -E set-later"); +#endif + sim_argv = buildargv (argbuf); + } + break; +#ifdef SIM_HAVE_SIMCACHE + case 'c': + sim_set_simcache_size (atoi (optarg)); + break; +#endif + case 'm': + /* FIXME: Rename to sim_set_mem_size. */ + sim_size (atoi (optarg)); + break; +#ifdef SIM_HAVE_PROFILE + case 'p': + sim_set_profile (atoi (optarg)); + break; + case 's': + sim_set_profile_size (atoi (optarg)); + break; +#endif + case 't': + trace = 1; + /* FIXME: need to allow specification of what to trace. */ + /* sim_set_trace (1); */ + break; + case 'v': + /* Things that are printed with -v are the kinds of things that + gcc -v prints. This is not meant to include detailed tracing + or debugging information, just summaries. */ + verbose = 1; + /* sim_set_verbose (1); */ + break; + /* FIXME: Quick hack, to be replaced by more general facility. */ +#ifdef SIM_H8300 + case 'h': + set_h8300h (1); + break; +#endif + default: + usage (); + } + + ac -= optind; + av += optind; + if (ac <= 0) + usage (); + + name = *av; + prog_args = av; + + if (verbose) + { + printf ("%s %s\n", myname, name); + } + + abfd = bfd_openr (name, 0); + if (!abfd) + { + fprintf (stderr, "%s: can't open %s: %s\n", + myname, name, bfd_errmsg (bfd_get_error ())); + exit (1); + } + + if (!bfd_check_format (abfd, bfd_object)) + { + fprintf (stderr, "%s: can't load %s: %s\n", + myname, name, bfd_errmsg (bfd_get_error ())); + exit (1); + } + +#ifdef SIM_HAVE_BIENDIAN + /* The endianness must be passed to sim_open because one may wish to + examine/set registers before calling sim_load [which is the other + place where one can determine endianness]. We previously passed the + endianness via global `target_byte_order' but that's not a clean + interface. */ + for (i = 1; sim_argv[i + 1] != NULL; ++i) + continue; + if (bfd_big_endian (abfd)) + sim_argv[i] = "big"; + else + sim_argv[i] = "little"; +#endif + + /* Ensure that any run-time initialisation that needs to be + performed by the simulator can occur. */ + sd = sim_open (SIM_OPEN_STANDALONE, &default_callback, abfd, sim_argv); + if (sd == 0) + exit (1); + + if (sim_load (sd, name, abfd, 0) == SIM_RC_FAIL) + exit (1); + + if (sim_create_inferior (sd, abfd, prog_args, NULL) == SIM_RC_FAIL) + exit (1); + + prev_sigint = signal (SIGINT, cntrl_c); + if (trace) + { + int done = 0; + while (!done) + { + done = sim_trace (sd); + } + } + else + { + sim_resume (sd, 0, 0); + } + signal (SIGINT, prev_sigint); + + if (verbose) + sim_info (sd, 0); + + sim_stop_reason (sd, &reason, &sigrc); + + sim_close (sd, 0); + + /* If reason is sim_exited, then sigrc holds the exit code which we want + to return. If reason is sim_stopped or sim_signalled, then sigrc holds + the signal that the simulator received; we want to return that to + indicate failure. */ + +#ifdef SIM_H8300 /* FIXME: Ugh. grep for SLEEP in compile.c */ + if (sigrc == SIGILL) + abort (); + sigrc = 0; +#else + /* Why did we stop? */ + switch (reason) + { + case sim_signalled: + case sim_stopped: + if (sigrc != 0) + fprintf (stderr, "program stopped with signal %d.\n", sigrc); + break; + + case sim_exited: + break; + + case sim_running: + case sim_polling: /* these indicate a serious problem */ + abort (); + break; + + } +#endif + + return sigrc; +} + +static void +usage () +{ + fprintf (stderr, "Usage: %s [options] program [program args]\n", myname); + fprintf (stderr, "Options:\n"); + fprintf (stderr, "-a args Pass `args' to simulator.\n"); +#ifdef SIM_HAVE_SIMCACHE + fprintf (stderr, "-c size Set simulator cache size to `size'.\n"); +#endif +#ifdef SIM_H8300 + fprintf (stderr, "-h Executable is for h8/300h or h8/300s.\n"); +#endif + fprintf (stderr, "-m size Set memory size of simulator, in bytes.\n"); +#ifdef SIM_HAVE_PROFILE + fprintf (stderr, "-p freq Set profiling frequency.\n"); + fprintf (stderr, "-s size Set profiling size.\n"); +#endif + fprintf (stderr, "-t Perform instruction tracing.\n"); + fprintf (stderr, " Note: Very few simulators support tracing.\n"); + fprintf (stderr, "-v Verbose output.\n"); + fprintf (stderr, "\n"); + fprintf (stderr, "program args Arguments to pass to simulated program.\n"); + fprintf (stderr, " Note: Very few simulators support this.\n"); + exit (1); +} diff --git a/sim/common/sim-abort.c b/sim/common/sim-abort.c new file mode 100644 index 0000000..088bf20 --- /dev/null +++ b/sim/common/sim-abort.c @@ -0,0 +1,60 @@ +/* Generic simulator abort. + Copyright (C) 1997 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <stdio.h> + +#include "sim-main.h" +#include "sim-assert.h" + +/* This is an implementation of sim_engine_abort that does not use + longjmp, instead it just calls sim_io_error. sim_io_error will + jump right out of the simulator. + + It is intended as a holder for simulators that have started to use + sim-core et.al. but are not yet in a position to use sim-engine + (the setjmp/longjmp code). */ + + +void +sim_engine_abort (SIM_DESC sd, + sim_cpu *cpu, + sim_cia cia, + const char *fmt, + ...) +{ + ASSERT (sd == NULL || STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + if (sd != NULL) + { + va_list ap; + va_start(ap, fmt); + sim_io_evprintf (sd, fmt, ap); + va_end(ap); + sim_io_error (sd, "\n"); + } + else + { + va_list ap; + va_start(ap, fmt); + vfprintf (stderr, fmt, ap); + va_end(ap); + fprintf (stderr, "\n"); + abort (); + } +} diff --git a/sim/common/sim-alu.h b/sim/common/sim-alu.h new file mode 100644 index 0000000..49d1018 --- /dev/null +++ b/sim/common/sim-alu.h @@ -0,0 +1,1047 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au> + Copyright (C) 1997, Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef _SIM_ALU_H_ +#define _SIM_ALU_H_ + +#include "symcat.h" + + +/* INTEGER ALU MODULE: + + This module provides an implementation of 2's complement arithmetic + including the recording of carry and overflow status bits. + + + EXAMPLE: + + Code using this module includes it into sim-main.h and then, as a + convention, defines macro's ALU*_END that records the result of any + aritmetic performed. Ex: + + #include "sim-alu.h" + #define ALU32_END(RES) \ + (RES) = ALU32_OVERFLOW_RESULT; \ + carry = ALU32_HAD_CARRY_BORROW; \ + overflow = ALU32_HAD_OVERFLOW + + The macro's are then used vis: + + { + ALU32_BEGIN (GPR[i]); + ALU32_ADDC (GPR[j]); + ALU32_END (GPR[k]); + } + + + NOTES: + + Macros exist for efficiently computing 8, 16, 32 and 64 bit + arithmetic - ALU8_*, ALU16_*, .... In addition, according to + TARGET_WORD_BITSIZE a set of short-hand macros are defined - ALU_* + + Initialization: + + ALU*_BEGIN(ACC): Declare initialize the ALU accumulator with ACC. + + Results: + + The calculation of the final result may be computed a number + of different ways. Three different overflow macro's are + defined, the most efficient one to use depends on which other + outputs from the alu are being used. + + ALU*_RESULT: Generic ALU result output. + + ALU*_HAD_OVERFLOW: Returns a nonzero value if signed overflow + occured. + + ALU*_OVERFLOW_RESULT: If the macro ALU*_HAD_OVERFLOW is being + used this is the most efficient result available. Ex: + + #define ALU16_END(RES) \ + if (ALU16_HAD_OVERFLOW) \ + sim_engine_halt (...); \ + (RES) = ALU16_OVERFLOW_RESULT + + ALU*_HAD_CARRY_BORROW: Returns a nonzero value if unsigned + overflow or underflow (also refered to as carry and borrow) + occured. + + ALU*_CARRY_BORROW_RESULT: If the macro ALU*_HAD_CARRY_BORROW is being + used this is the most efficient result available. Ex: + + #define ALU64_END(RES) \ + State.carry = ALU64_HAD_CARRY_BORROW; \ + (RES) = ALU64_CARRY_BORROW_RESULT + + + Addition: + + ALU*_ADD(VAL): Add VAL to the ALU accumulator. Record any + overflow as well as the final result. + + ALU*_ADDC(VAL): Add VAL to the ALU accumulator. Record any + carry-out or overflow as well as the final result. + + ALU*_ADDC_C(VAL,CI): Add VAL and CI (carry-in). Record any + carry-out or overflow as well as the final result. + + Subtraction: + + ALU*_SUB(VAL): Subtract VAL from the ALU accumulator. Record + any underflow as well as the final result. + + ALU*_SUBC(VAL): Subtract VAL from the ALU accumulator using + negated addition. Record any underflow or carry-out as well + as the final result. + + ALU*_SUBB(VAL): Subtract VAL from the ALU accumulator using + direct subtraction (ACC+~VAL+1). Record any underflow or + borrow-out as well as the final result. + + ALU*_SUBC_X(VAL,CI): Subtract VAL and CI (carry-in) from the + ALU accumulator using extended negated addition (ACC+~VAL+CI). + Record any underflow or carry-out as well as the final result. + + ALU*_SUBB_B(VAL,BI): Subtract VAL and BI (borrow-in) from the + ALU accumulator using direct subtraction. Record any + underflow or borrow-out as well as the final result. + + + */ + + + +/* Twos complement aritmetic - addition/subtraction - carry/borrow + (or you thought you knew the answer to 0-0) + + + + Notation and Properties: + + + Xn denotes the value X stored in N bits. + + MSBn (X): The most significant (sign) bit of X treated as an N bit + value. + + SEXTn (X): The infinite sign extension of X treated as an N bit + value. + + MAXn, MINn: The upper and lower bound of a signed, two's + complement N bit value. + + UMAXn: The upper bound of an unsigned N bit value (the lower + bound is always zero). + + Un: UMAXn + 1. Unsigned arrithmetic is computed `modulo (Un)'. + + X[p]: Is bit P of X. X[0] denotes the least signifant bit. + + ~X[p]: Is the inversion of bit X[p]. Also equal to 1-X[p], + (1+X[p])mod(2). + + + + Addition - Overflow - Introduction: + + + Overflow/Overflow indicates an error in computation of signed + arrithmetic. i.e. given X,Y in [MINn..MAXn]; overflow + indicates that the result X+Y > MAXn or X+Y < MIN_INTx. + + Hardware traditionally implements overflow by computing the XOR of + carry-in/carry-out of the most significant bit of the ALU. Here + other methods need to be found. + + + + Addition - Overflow - method 1: + + + Overflow occures when the sign (most significant bit) of the two N + bit operands is identical but different to the sign of the result: + + Rn = (Xn + Yn) + V = MSBn (~(Xn ^ Yn) & (Rn ^ Xn)) + + + + Addition - Overflow - method 2: + + + The two N bit operands are sign extended to M>N bits and then + added. Overflow occures when SIGN_BIT<n> and SIGN_BIT<m> do not + match. + + Rm = (SEXTn (Xn) + SEXTn (Yn)) + V = MSBn ((Rm >> (M - N)) ^ Rm) + + + + Addition - Overflow - method 3: + + + The two N bit operands are sign extended to M>N bits and then + added. Overflow occures when the result is outside of the sign + extended range [MINn .. MAXn]. + + + + Addition - Overflow - method 4: + + + Given the Result and Carry-out bits, the oVerflow from the addition + of X, Y and carry-In can be computed using the equation: + + Rn = (Xn + Yn) + V = (MSBn ((Xn ^ Yn) ^ Rn)) ^ C) + + As shown in the table below: + + I X Y R C | V | X^Y ^R ^C + ---------------+---+------------- + 0 0 0 0 0 | 0 | 0 0 0 + 0 0 1 1 0 | 0 | 1 0 0 + 0 1 0 1 0 | 0 | 1 0 0 + 0 1 1 0 1 | 1 | 0 0 1 + 1 0 0 1 0 | 1 | 0 1 1 + 1 0 1 0 1 | 0 | 1 1 0 + 1 1 0 0 1 | 0 | 1 1 0 + 1 1 1 1 1 | 0 | 0 1 0 + + + + Addition - Carry - Introduction: + + + Carry (poorly named) indicates that an overflow occured for + unsigned N bit addition. i.e. given X, Y in [0..UMAXn] then + carry indicates X+Y > UMAXn or X+Y >= Un. + + The following table lists the output for all given inputs into a + full-adder. + + I X Y R | C + ------------+--- + 0 0 0 0 | 0 + 0 0 1 1 | 0 + 0 1 0 1 | 0 + 0 1 1 0 | 1 + 1 0 0 1 | 0 + 1 0 1 0 | 1 + 1 1 0 0 | 1 + 1 1 1 1 | 1 + + (carry-In, X, Y, Result, Carry-out): + + + + Addition - Carry - method 1: + + + Looking at the terms X, Y and R we want an equation for C. + + XY\R 0 1 + +------- + 00 | 0 0 + 01 | 1 0 + 11 | 1 1 + 10 | 1 0 + + This giving us the sum-of-prod equation: + + MSBn ((Xn & Yn) | (Xn & ~Rn) | (Yn & ~Rn)) + + Verifying: + + I X Y R | C | X&Y X&~R Y&~R + ------------+---+--------------- + 0 0 0 0 | 0 | 0 0 0 + 0 0 1 1 | 0 | 0 0 0 + 0 1 0 1 | 0 | 0 0 0 + 0 1 1 0 | 1 | 1 1 1 + 1 0 0 1 | 0 | 0 0 0 + 1 0 1 0 | 1 | 0 0 1 + 1 1 0 0 | 1 | 0 1 0 + 1 1 1 1 | 1 | 1 0 0 + + + + Addition - Carry - method 2: + + + Given two signed N bit numbers, a carry can be detected by treating + the numbers as N bit unsigned and adding them using M>N unsigned + arrithmetic. Carry is indicated by bit (1 << N) being set (result + >= 2**N). + + + + Addition - Carry - method 3: + + + Given the oVerflow bit. The carry can be computed from: + + (~R&V) | (R&V) + + + + Addition - Carry - method 4: + + Given two signed numbers. Treating them as unsigned we have: + + 0 <= X < Un, 0 <= Y < Un + ==> X + Y < 2 Un + + Consider Y when carry occures: + + X + Y >= Un, Y < Un + ==> (Un - X) <= Y < Un # re-arange + ==> Un <= X + Y < Un + X < 2 Un # add Xn + ==> 0 <= (X + Y) mod Un < X mod Un + + or when carry as occured: + + (X + Y) mod Un < X mod Un + + Consider Y when carry does not occure: + + X + Y < Un + have X < Un, Y >= 0 + ==> X <= X + Y < Un + ==> X mod Un <= (X + Y) mod Un + + or when carry has not occured: + + ! ( (X + Y) mod Un < X mod Un) + + hence we get carry by computing in N bit unsigned arrithmetic. + + carry <- (Xn + Yn) < Xn + + + + Subtraction - Introduction + + + There are two different ways of computing the signed two's + complement difference of two numbers. The first is based on + negative addition, the second on direct subtraction. + + + + Subtraction - Carry - Introduction - Negated Addition + + + The equation X - Y can be computed using: + + X + (-Y) + ==> X + ~Y + 1 # -Y = ~Y + 1 + + In addition to the result, the equation produces Carry-out. For + succeeding extended prrcision calculations, the more general + equation can be used: + + C[p]:R[p] = X[p] + ~Y[p] + C[p-1] + where C[0]:R[0] = X[0] + ~Y[0] + 1 + + + + Subtraction - Borrow - Introduction - Direct Subtraction + + + The alternative to negative addition is direct subtraction where + `X-Y is computed directly. In addition to the result of the + calculation, a Borrow bit is produced. In general terms: + + B[p]:R[p] = X[p] - Y[p] - B[p-1] + where B[0]:R[0] = X[0] - Y[0] + + The Borrow bit is the complement of the Carry bit produced by + Negated Addition above. A dodgy proof follows: + + Case 0: + C[0]:R[0] = X[0] + ~Y[0] + 1 + ==> C[0]:R[0] = X[0] + 1 - Y[0] + 1 # ~Y[0] = (1 - Y[0])? + ==> C[0]:R[0] = 2 + X[0] - Y[0] + ==> C[0]:R[0] = 2 + B[0]:R[0] + ==> C[0]:R[0] = (1 + B[0]):R[0] + ==> C[0] = ~B[0] # (1 + B[0]) mod 2 = ~B[0]? + + Case P: + C[p]:R[p] = X[p] + ~Y[p] + C[p-1] + ==> C[p]:R[p] = X[p] + 1 - Y[0] + 1 - B[p-1] + ==> C[p]:R[p] = 2 + X[p] - Y[0] - B[p-1] + ==> C[p]:R[p] = 2 + B[p]:R[p] + ==> C[p]:R[p] = (1 + B[p]):R[p] + ==> C[p] = ~B[p] + + The table below lists all possible inputs/outputs for a + full-subtractor: + + X Y I | R B + 0 0 0 | 0 0 + 0 0 1 | 1 1 + 0 1 0 | 1 1 + 0 1 1 | 0 1 + 1 0 0 | 1 0 + 1 0 1 | 0 0 + 1 1 0 | 0 0 + 1 1 1 | 1 1 + + + + Subtraction - Method 1 + + + Treating Xn and Yn as unsigned values then a borrow (unsigned + underflow) occures when: + + B = Xn < Yn + ==> C = Xn >= Yn + + */ + + + +/* 8 bit target expressions: + + Since the host's natural bitsize > 8 bits, carry method 2 and + overflow method 2 are used. */ + +#define ALU8_BEGIN(VAL) \ +unsigned alu8_cr = (unsigned8) (VAL); \ +signed alu8_vr = (signed8) (alu8_cr) + +#define ALU8_SET(VAL) \ +alu8_cr = (unsigned8) (VAL); \ +alu8_vr = (signed8) (alu8_cr) + +#define ALU8_SET_CARRY_BORROW(CARRY) \ +do { \ + if (CARRY) \ + alu8_cr |= ((signed)-1) << 8; \ + else \ + alu8_cr &= 0xff; \ +} while (0) + +#define ALU8_HAD_CARRY_BORROW (alu8_cr & LSBIT32(8)) +#define ALU8_HAD_OVERFLOW (((alu8_vr >> 8) ^ alu8_vr) & LSBIT32 (8-1)) + +#define ALU8_RESULT ((unsigned8) alu8_cr) +#define ALU8_CARRY_BORROW_RESULT ((unsigned8) alu8_cr) +#define ALU8_OVERFLOW_RESULT ((unsigned8) alu8_vr) + +/* #define ALU8_END ????? - target dependant */ + + + +/* 16 bit target expressions: + + Since the host's natural bitsize > 16 bits, carry method 2 and + overflow method 2 are used. */ + +#define ALU16_BEGIN(VAL) \ +signed alu16_cr = (unsigned16) (VAL); \ +unsigned alu16_vr = (signed16) (alu16_cr) + +#define ALU16_SET(VAL) \ +alu16_cr = (unsigned16) (VAL); \ +alu16_vr = (signed16) (alu16_cr) + +#define ALU16_SET_CARRY_BORROW(CARRY) \ +do { \ + if (CARRY) \ + alu16_cr |= ((signed)-1) << 16; \ + else \ + alu16_cr &= 0xffff; \ +} while (0) + +#define ALU16_HAD_CARRY_BORROW (alu16_cr & LSBIT32(16)) +#define ALU16_HAD_OVERFLOW (((alu16_vr >> 16) ^ alu16_vr) & LSBIT32 (16-1)) + +#define ALU16_RESULT ((unsigned16) alu16_cr) +#define ALU16_CARRY_BORROW_RESULT ((unsigned16) alu16_cr) +#define ALU16_OVERFLOW_RESULT ((unsigned16) alu16_vr) + +/* #define ALU16_END ????? - target dependant */ + + + +/* 32 bit target expressions: + + Since most hosts do not support 64 (> 32) bit arrithmetic, carry + method 4 and overflow method 4 are used. */ + +#define ALU32_BEGIN(VAL) \ +unsigned32 alu32_r = (VAL); \ +int alu32_c = 0; \ +int alu32_v = 0 + +#define ALU32_SET(VAL) \ +alu32_r = (VAL); \ +alu32_c = 0; \ +alu32_v = 0 + +#define ALU32_SET_CARRY_BORROW(CARRY) alu32_c = (CARRY) + +#define ALU32_HAD_CARRY_BORROW (alu32_c) +#define ALU32_HAD_OVERFLOW (alu32_v) + +#define ALU32_RESULT (alu32_r) +#define ALU32_CARRY_BORROW_RESULT (alu32_r) +#define ALU32_OVERFLOW_RESULT (alu32_r) + + + +/* 64 bit target expressions: + + Even though the host typically doesn't support native 64 bit + arrithmetic, it is still used. */ + +#define ALU64_BEGIN(VAL) \ +unsigned64 alu64_r = (VAL); \ +int alu64_c = 0; \ +int alu64_v = 0 + +#define ALU64_SET(VAL) \ +alu64_r = (VAL); \ +alu64_c = 0; \ +alu64_v = 0 + +#define ALU64_SET_CARRY_BORROW(CARRY) alu64_c = (CARRY) + +#define ALU64_HAD_CARRY_BORROW (alu64_c) +#define ALU64_HAD_OVERFLOW (alu64_v) + +#define ALU64_RESULT (alu64_r) +#define ALU64_CARRY_BORROW_RESULT (alu64_r) +#define ALU64_OVERFLOW_RESULT (alu64_r) + + + +/* Generic versions of above macros */ + +#define ALU_BEGIN XCONCAT3(ALU,WITH_TARGET_WORD_BITSIZE,_BEGIN) +#define ALU_SET XCONCAT3(ALU,WITH_TARGET_WORD_BITSIZE,_SET) +#define ALU_SET_CARRY XCONCAT3(ALU,WITH_TARGET_WORD_BITSIZE,_SET_CARRY) + +#define ALU_HAD_OVERFLOW XCONCAT3(ALU,WITH_TARGET_WORD_BITSIZE,_HAD_OVERFLOW) +#define ALU_HAD_CARRY XCONCAT3(ALU,WITH_TARGET_WORD_BITSIZE,_HAD_CARRY) + +#define ALU_RESULT XCONCAT3(ALU,WITH_TARGET_WORD_BITSIZE,_RESULT) +#define ALU_OVERFLOW_RESULT XCONCAT3(ALU,WITH_TARGET_WORD_BITSIZE,_OVERFLOW_RESULT) +#define ALU_CARRY_RESULT XCONCAT3(ALU,WITH_TARGET_WORD_BITSIZE,_CARRY_RESULT) + + + +/* Basic operation - add (overflowing) */ + +#define ALU8_ADD(VAL) \ +do { \ + unsigned8 alu8add_val = (VAL); \ + ALU8_ADDC (alu8add_val); \ +} while (0) + +#define ALU16_ADD(VAL) \ +do { \ + unsigned16 alu16add_val = (VAL); \ + ALU16_ADDC (alu8add_val); \ +} while (0) + +#define ALU32_ADD(VAL) \ +do { \ + unsigned32 alu32add_val = (VAL); \ + ALU32_ADDC (alu32add_val); \ +} while (0) + +#define ALU64_ADD(VAL) \ +do { \ + unsigned64 alu64add_val = (unsigned64) (VAL); \ + ALU64_ADDC (alu64add_val); \ +} while (0) + +#define ALU_ADD XCONCAT3(ALU,WITH_TARGET_WORD_BITSIZE,_ADD) + + + +/* Basic operation - add carrying (and overflowing) */ + +#define ALU8_ADDC(VAL) \ +do { \ + unsigned8 alu8addc_val = (VAL); \ + alu8_cr += (unsigned8)(alu8addc_val); \ + alu8_vr += (signed8)(alu8addc_val); \ +} while (0) + +#define ALU16_ADDC(VAL) \ +do { \ + unsigned16 alu16addc_val = (VAL); \ + alu16_cr += (unsigned16)(alu16addc_val); \ + alu16_vr += (signed16)(alu16addc_val); \ +} while (0) + +#define ALU32_ADDC(VAL) \ +do { \ + unsigned32 alu32addc_val = (VAL); \ + unsigned32 alu32addc_sign = alu32addc_val ^ alu32_r; \ + alu32_r += (alu32addc_val); \ + alu32_c = (alu32_r < alu32addc_val); \ + alu32_v = ((alu32addc_sign ^ - (unsigned32)alu32_c) ^ alu32_r) >> 31; \ +} while (0) + +#define ALU64_ADDC(VAL) \ +do { \ + unsigned64 alu64addc_val = (unsigned64) (VAL); \ + unsigned64 alu64addc_sign = alu64addc_val ^ alu64_r; \ + alu64_r += (alu64addc_val); \ + alu64_c = (alu64_r < alu64addc_val); \ + alu64_v = ((alu64addc_sign ^ - (unsigned64)alu64_c) ^ alu64_r) >> 63; \ +} while (0) + +#define ALU_ADDC XCONCAT3(ALU,WITH_TARGET_WORD_BITSIZE,_ADDC) + + + +/* Compound operation - add carrying (and overflowing) with carry-in */ + +#define ALU8_ADDC_C(VAL,C) \ +do { \ + unsigned8 alu8addcc_val = (VAL); \ + unsigned8 alu8addcc_c = (C); \ + alu8_cr += (unsigned)(unsigned8)alu8addcc_val + alu8addcc_c; \ + alu8_vr += (signed)(signed8)(alu8addcc_val) + alu8addcc_c; \ +} while (0) + +#define ALU16_ADDC_C(VAL,C) \ +do { \ + unsigned16 alu16addcc_val = (VAL); \ + unsigned16 alu16addcc_c = (C); \ + alu16_cr += (unsigned)(unsigned16)alu16addcc_val + alu16addcc_c; \ + alu16_vr += (signed)(signed16)(alu16addcc_val) + alu16addcc_c; \ +} while (0) + +#define ALU32_ADDC_C(VAL,C) \ +do { \ + unsigned32 alu32addcc_val = (VAL); \ + unsigned32 alu32addcc_c = (C); \ + unsigned32 alu32addcc_sign = (alu32addcc_val ^ alu32_r); \ + alu32_r += (alu32addcc_val + alu32addcc_c); \ + alu32_c = ((alu32_r < alu32addcc_val) \ + || (alu32addcc_c && alu32_r == alu32addcc_val)); \ + alu32_v = ((alu32addcc_sign ^ - (unsigned32)alu32_c) ^ alu32_r) >> 31;\ +} while (0) + +#define ALU64_ADDC_C(VAL,C) \ +do { \ + unsigned64 alu64addcc_val = (VAL); \ + unsigned64 alu64addcc_c = (C); \ + unsigned64 alu64addcc_sign = (alu64addcc_val ^ alu64_r); \ + alu64_r += (alu64addcc_val + alu64addcc_c); \ + alu64_c = ((alu64_r < alu64addcc_val) \ + || (alu64addcc_c && alu64_r == alu64addcc_val)); \ + alu64_v = ((alu64addcc_sign ^ - (unsigned64)alu64_c) ^ alu64_r) >> 63;\ +} while (0) + +#define ALU_ADDC_C XCONCAT3(ALU,WITH_TARGET_WORD_BITSIZE,_ADDC_C) + + + +/* Basic operation - subtract (overflowing) */ + +#define ALU8_SUB(VAL) \ +do { \ + unsigned8 alu8sub_val = (VAL); \ + ALU8_ADDC_C (~alu8sub_val, 1); \ +} while (0) + +#define ALU16_SUB(VAL) \ +do { \ + unsigned16 alu16sub_val = (VAL); \ + ALU16_ADDC_C (~alu16sub_val, 1); \ +} while (0) + +#define ALU32_SUB(VAL) \ +do { \ + unsigned32 alu32sub_val = (VAL); \ + ALU32_ADDC_C (~alu32sub_val, 1); \ +} while (0) + +#define ALU64_SUB(VAL) \ +do { \ + unsigned64 alu64sub_val = (VAL); \ + ALU64_ADDC_C (~alu64sub_val, 1); \ +} while (0) + +#define ALU_SUB XCONCAT3(ALU,WITH_TARGET_WORD_BITSIZE,_SUB) + + + +/* Basic operation - subtract carrying (and overflowing) */ + +#define ALU8_SUBC(VAL) \ +do { \ + unsigned8 alu8subc_val = (VAL); \ + ALU8_ADDC_C (~alu8subc_val, 1); \ +} while (0) + +#define ALU16_SUBC(VAL) \ +do { \ + unsigned16 alu16subc_val = (VAL); \ + ALU16_ADDC_C (~alu16subc_val, 1); \ +} while (0) + +#define ALU32_SUBC(VAL) \ +do { \ + unsigned32 alu32subc_val = (VAL); \ + ALU32_ADDC_C (~alu32subc_val, 1); \ +} while (0) + +#define ALU64_SUBC(VAL) \ +do { \ + unsigned64 alu64subc_val = (VAL); \ + ALU64_ADDC_C (~alu64subc_val, 1); \ +} while (0) + +#define ALU_SUBC XCONCAT3(ALU,WITH_TARGET_WORD_BITSIZE,_SUBC) + + + +/* Compound operation - subtract carrying (and overflowing), extended */ + +#define ALU8_SUBC_X(VAL,C) \ +do { \ + unsigned8 alu8subcx_val = (VAL); \ + unsigned8 alu8subcx_c = (C); \ + ALU8_ADDC_C (~alu8subcx_val, alu8subcx_c); \ +} while (0) + +#define ALU16_SUBC_X(VAL,C) \ +do { \ + unsigned16 alu16subcx_val = (VAL); \ + unsigned16 alu16subcx_c = (C); \ + ALU16_ADDC_C (~alu16subcx_val, alu16subcx_c); \ +} while (0) + +#define ALU32_SUBC_X(VAL,C) \ +do { \ + unsigned32 alu32subcx_val = (VAL); \ + unsigned32 alu32subcx_c = (C); \ + ALU32_ADDC_C (~alu32subcx_val, alu32subcx_c); \ +} while (0) + +#define ALU64_SUBC_X(VAL,C) \ +do { \ + unsigned64 alu64subcx_val = (VAL); \ + unsigned64 alu64subcx_c = (C); \ + ALU64_ADDC_C (~alu64subcx_val, alu64subcx_c); \ +} while (0) + +#define ALU_SUBC_X XCONCAT3(ALU,WITH_TARGET_WORD_BITSIZE,_SUBC_X) + + + +/* Basic operation - subtract borrowing (and overflowing) */ + +#define ALU8_SUBB(VAL) \ +do { \ + unsigned8 alu8subb_val = (VAL); \ + alu8_cr -= (unsigned)(unsigned8)alu8subb_val; \ + alu8_vr -= (signed)(signed8)alu8subb_val; \ +} while (0) + +#define ALU16_SUBB(VAL) \ +do { \ + unsigned16 alu16subb_val = (VAL); \ + alu16_cr -= (unsigned)(unsigned16)alu16subb_val; \ + alu16_vr -= (signed)(signed16)alu16subb_val; \ +} while (0) + +#define ALU32_SUBB(VAL) \ +do { \ + unsigned32 alu32subb_val = (VAL); \ + unsigned32 alu32subb_sign = alu32subb_val ^ alu32_r; \ + alu32_c = (alu32_r < alu32subb_val); \ + alu32_r -= (alu32subb_val); \ + alu32_v = ((alu32subb_sign ^ - (unsigned32)alu32_c) ^ alu32_r) >> 31; \ +} while (0) + +#define ALU64_SUBB(VAL) \ +do { \ + unsigned64 alu64subb_val = (VAL); \ + unsigned64 alu64subb_sign = alu64subb_val ^ alu64_r; \ + alu64_c = (alu64_r < alu64subb_val); \ + alu64_r -= (alu64subb_val); \ + alu64_v = ((alu64subb_sign ^ - (unsigned64)alu64_c) ^ alu64_r) >> 31; \ +} while (0) + +#define ALU_SUBB XCONCAT3(ALU,WITH_TARGET_WORD_BITSIZE,_SUBB) + + + +/* Compound operation - subtract borrowing (and overflowing) with borrow-in */ + +#define ALU8_SUBB_B(VAL,B) \ +do { \ + unsigned8 alu8subbb_val = (VAL); \ + unsigned8 alu8subbb_b = (B); \ + alu8_cr -= (unsigned)(unsigned8)alu8subbb_val; \ + alu8_cr -= (unsigned)(unsigned8)alu8subbb_b; \ + alu8_vr -= (signed)(signed8)alu8subbb_val + alu8subbb_b; \ +} while (0) + +#define ALU16_SUBB_B(VAL,B) \ +do { \ + unsigned16 alu16subbb_val = (VAL); \ + unsigned16 alu16subbb_b = (B); \ + alu16_cr -= (unsigned)(unsigned16)alu16subbb_val; \ + alu16_cr -= (unsigned)(unsigned16)alu16subbb_b; \ + alu16_vr -= (signed)(signed16)alu16subbb_val + alu16subbb_b; \ +} while (0) + +#define ALU32_SUBB_B(VAL,B) \ +do { \ + unsigned32 alu32subbb_val = (VAL); \ + unsigned32 alu32subbb_b = (B); \ + ALU32_ADDC_C (~alu32subbb_val, !alu32subbb_b); \ + alu32_c = !alu32_c; \ +} while (0) + +#define ALU64_SUBB_B(VAL,B) \ +do { \ + unsigned64 alu64subbb_val = (VAL); \ + unsigned64 alu64subbb_b = (B); \ + ALU64_ADDC_C (~alu64subbb_val, !alu64subbb_b); \ + alu64_c = !alu64_c; \ +} while (0) + +#define ALU_SUBB_B XCONCAT3(ALU,WITH_TARGET_WORD_BITSIZE,_SUBB_B) + + + +/* Basic operation - negate (overflowing) */ + +#define ALU8_NEG() \ +do { \ + signed alu8neg_val = (ALU8_RESULT); \ + ALU8_SET (1); \ + ALU8_ADDC (~alu8neg_val); \ +} while (0) + +#define ALU16_NEG() \ +do { \ + signed alu16neg_val = (ALU16_RESULT); \ + ALU16_SET (1); \ + ALU16_ADDC (~alu16neg_val); \ +} while (0) + +#define ALU32_NEG() \ +do { \ + unsigned32 alu32neg_val = (ALU32_RESULT); \ + ALU32_SET (1); \ + ALU32_ADDC (~alu32neg_val); \ +} while(0) + +#define ALU64_NEG() \ +do { \ + unsigned64 alu64neg_val = (ALU64_RESULT); \ + ALU64_SET (1); \ + ALU64_ADDC (~alu64neg_val); \ +} while (0) + +#define ALU_NEG XCONCAT3(ALU,WITH_TARGET_WORD_BITSIZE,_NEG) + + + + +/* Basic operation - negate carrying (and overflowing) */ + +#define ALU8_NEGC() \ +do { \ + signed alu8negc_val = (ALU8_RESULT); \ + ALU8_SET (1); \ + ALU8_ADDC (~alu8negc_val); \ +} while (0) + +#define ALU16_NEGC() \ +do { \ + signed alu16negc_val = (ALU16_RESULT); \ + ALU16_SET (1); \ + ALU16_ADDC (~alu16negc_val); \ +} while (0) + +#define ALU32_NEGC() \ +do { \ + unsigned32 alu32negc_val = (ALU32_RESULT); \ + ALU32_SET (1); \ + ALU32_ADDC (~alu32negc_val); \ +} while(0) + +#define ALU64_NEGC() \ +do { \ + unsigned64 alu64negc_val = (ALU64_RESULT); \ + ALU64_SET (1); \ + ALU64_ADDC (~alu64negc_val); \ +} while (0) + +#define ALU_NEGC XCONCAT3(ALU,WITH_TARGET_WORD_BITSIZE,_NEGC) + + + + +/* Basic operation - negate borrowing (and overflowing) */ + +#define ALU8_NEGB() \ +do { \ + signed alu8negb_val = (ALU8_RESULT); \ + ALU8_SET (0); \ + ALU8_SUBB (alu8negb_val); \ +} while (0) + +#define ALU16_NEGB() \ +do { \ + signed alu16negb_val = (ALU16_RESULT); \ + ALU16_SET (0); \ + ALU16_SUBB (alu16negb_val); \ +} while (0) + +#define ALU32_NEGB() \ +do { \ + unsigned32 alu32negb_val = (ALU32_RESULT); \ + ALU32_SET (0); \ + ALU32_SUBB (alu32negb_val); \ +} while(0) + +#define ALU64_NEGB() \ +do { \ + unsigned64 alu64negb_val = (ALU64_RESULT); \ + ALU64_SET (0); \ + ALU64_SUBB (alu64negb_val); \ +} while (0) + +#define ALU_NEGB XCONCAT3(ALU,WITH_TARGET_WORD_BITSIZE,_NEGB) + + + + +/* Other */ + +#define ALU8_OR(VAL) \ +do { \ + error("ALU16_OR"); \ +} while (0) + +#define ALU16_OR(VAL) \ +do { \ + error("ALU16_OR"); \ +} while (0) + +#define ALU32_OR(VAL) \ +do { \ + alu32_r |= (VAL); \ + alu32_c = 0; \ + alu32_v = 0; \ +} while (0) + +#define ALU64_OR(VAL) \ +do { \ + alu64_r |= (VAL); \ + alu64_c = 0; \ + alu64_v = 0; \ +} while (0) + +#define ALU_OR(VAL) XCONCAT3(ALU,WITH_TARGET_WORD_BITSIZE,_OR)(VAL) + + + +#define ALU16_XOR(VAL) \ +do { \ + error("ALU16_XOR"); \ +} while (0) + +#define ALU32_XOR(VAL) \ +do { \ + alu32_r ^= (VAL); \ + alu32_c = 0; \ + alu32_v = 0; \ +} while (0) + +#define ALU64_XOR(VAL) \ +do { \ + alu64_r ^= (VAL); \ + alu64_c = 0; \ + alu64_v = 0; \ +} while (0) + +#define ALU_XOR(VAL) XCONCAT3(ALU,WITH_TARGET_WORD_BITSIZE,_XOR)(VAL) + + + + +#define ALU16_AND(VAL) \ +do { \ + error("ALU_AND16"); \ +} while (0) + +#define ALU32_AND(VAL) \ +do { \ + alu32_r &= (VAL); \ + alu32_r = 0; \ + alu32_v = 0; \ +} while (0) + +#define ALU64_AND(VAL) \ +do { \ + alu64_r &= (VAL); \ + alu64_r = 0; \ + alu64_v = 0; \ +} while (0) + +#define ALU_AND(VAL) XCONCAT3(ALU,WITH_TARGET_WORD_BITSIZE,_AND)(VAL) + + + + +#define ALU16_NOT(VAL) \ +do { \ + error("ALU_NOT16"); \ +} while (0) + +#define ALU32_NOT \ +do { \ + alu32_r = ~alu32_r; \ + alu32_c = 0; \ + alu32_v = 0; \ +} while (0) + +#define ALU64_NOT \ +do { \ + alu64_r = ~alu64_r; \ + alu64_c = 0; \ + alu64_v = 0; \ +} while (0) + +#define ALU_NOT XCONCAT3(ALU,WITH_TARGET_WORD_BITSIZE,_NOT) + +#endif diff --git a/sim/common/sim-arange.c b/sim/common/sim-arange.c new file mode 100644 index 0000000..d9955e6 --- /dev/null +++ b/sim/common/sim-arange.c @@ -0,0 +1,301 @@ +/* Address ranges. + Copyright (C) 1998 Free Software Foundation, Inc. + Contributed by Cygnus Solutions. + +This file is part of the GNU Simulators. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Tell sim-arange.h it's us. */ +#define SIM_ARANGE_C + +#include "libiberty.h" +#include "sim-basics.h" +#include "sim-assert.h" + +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif + +#define DEFINE_INLINE_P (! defined (SIM_ARANGE_C_INCLUDED)) +#define DEFINE_NON_INLINE_P defined (SIM_ARANGE_C_INCLUDED) + +#if DEFINE_NON_INLINE_P + +/* Insert a range. */ + +static void +insert_range (ADDR_SUBRANGE **pos, ADDR_SUBRANGE *asr) +{ + asr->next = *pos; + *pos = asr; +} + +/* Delete a range. */ + +static void +delete_range (ADDR_SUBRANGE **thisasrp) +{ + ADDR_SUBRANGE *thisasr; + + thisasr = *thisasrp; + *thisasrp = thisasr->next; + + free (thisasr); +} + +/* Add or delete an address range. + This code was borrowed from linux's locks.c:posix_lock_file(). + ??? Todo: Given our simpler needs this could be simplified + (split into two fns). */ + +static void +frob_range (ADDR_RANGE *ar, address_word start, address_word end, int delete_p) +{ + ADDR_SUBRANGE *asr; + ADDR_SUBRANGE *new_asr, *new_asr2; + ADDR_SUBRANGE *left = NULL; + ADDR_SUBRANGE *right = NULL; + ADDR_SUBRANGE **before; + ADDR_SUBRANGE init_caller; + ADDR_SUBRANGE *caller = &init_caller; + int added_p = 0; + + memset (caller, 0, sizeof (ADDR_SUBRANGE)); + new_asr = ZALLOC (ADDR_SUBRANGE); + new_asr2 = ZALLOC (ADDR_SUBRANGE); + + caller->start = start; + caller->end = end; + before = &ar->ranges; + + while ((asr = *before) != NULL) + { + if (! delete_p) + { + /* Try next range if current range preceeds new one and not + adjacent or overlapping. */ + if (asr->end < caller->start - 1) + goto next_range; + + /* Break out if new range preceeds current one and not + adjacent or overlapping. */ + if (asr->start > caller->end + 1) + break; + + /* If we come here, the new and current ranges are adjacent or + overlapping. Make one range yielding from the lower start address + of both ranges to the higher end address. */ + if (asr->start > caller->start) + asr->start = caller->start; + else + caller->start = asr->start; + if (asr->end < caller->end) + asr->end = caller->end; + else + caller->end = asr->end; + + if (added_p) + { + delete_range (before); + continue; + } + caller = asr; + added_p = 1; + } + else /* deleting a range */ + { + /* Try next range if current range preceeds new one. */ + if (asr->end < caller->start) + goto next_range; + + /* Break out if new range preceeds current one. */ + if (asr->start > caller->end) + break; + + added_p = 1; + + if (asr->start < caller->start) + left = asr; + + /* If the next range in the list has a higher end + address than the new one, insert the new one here. */ + if (asr->end > caller->end) + { + right = asr; + break; + } + if (asr->start >= caller->start) + { + /* The new range completely replaces an old + one (This may happen several times). */ + if (added_p) + { + delete_range (before); + continue; + } + + /* Replace the old range with the new one. */ + asr->start = caller->start; + asr->end = caller->end; + caller = asr; + added_p = 1; + } + } + + /* Go on to next range. */ + next_range: + before = &asr->next; + } + + if (!added_p) + { + if (delete_p) + goto out; + new_asr->start = caller->start; + new_asr->end = caller->end; + insert_range (before, new_asr); + new_asr = NULL; + } + if (right) + { + if (left == right) + { + /* The new range breaks the old one in two pieces, + so we have to use the second new range. */ + new_asr2->start = right->start; + new_asr2->end = right->end; + left = new_asr2; + insert_range (before, left); + new_asr2 = NULL; + } + right->start = caller->end + 1; + } + if (left) + { + left->end = caller->start - 1; + } + + out: + if (new_asr) + free(new_asr); + if (new_asr2) + free(new_asr2); +} + +/* Free T and all subtrees. */ + +static void +free_search_tree (ADDR_RANGE_TREE *t) +{ + if (t != NULL) + { + free_search_tree (t->lower); + free_search_tree (t->higher); + free (t); + } +} + +/* Subroutine of build_search_tree to recursively build a balanced tree. + ??? It's not an optimum tree though. */ + +static ADDR_RANGE_TREE * +build_tree_1 (ADDR_SUBRANGE **asrtab, unsigned int n) +{ + unsigned int mid = n / 2; + ADDR_RANGE_TREE *t; + + if (n == 0) + return NULL; + t = (ADDR_RANGE_TREE *) xmalloc (sizeof (ADDR_RANGE_TREE)); + t->start = asrtab[mid]->start; + t->end = asrtab[mid]->end; + if (mid != 0) + t->lower = build_tree_1 (asrtab, mid); + else + t->lower = NULL; + if (n > mid + 1) + t->higher = build_tree_1 (asrtab + mid + 1, n - mid - 1); + else + t->higher = NULL; + return t; +} + +/* Build a search tree for address range AR. */ + +static void +build_search_tree (ADDR_RANGE *ar) +{ + /* ??? Simple version for now. */ + ADDR_SUBRANGE *asr,**asrtab; + unsigned int i, n; + + for (n = 0, asr = ar->ranges; asr != NULL; ++n, asr = asr->next) + continue; + asrtab = (ADDR_SUBRANGE **) xmalloc (n * sizeof (ADDR_SUBRANGE *)); + for (i = 0, asr = ar->ranges; i < n; ++i, asr = asr->next) + asrtab[i] = asr; + ar->range_tree = build_tree_1 (asrtab, n); + free (asrtab); +} + +void +sim_addr_range_add (ADDR_RANGE *ar, address_word start, address_word end) +{ + frob_range (ar, start, end, 0); + + /* Rebuild the search tree. */ + /* ??? Instead of rebuilding it here it could be done in a module resume + handler, say by first checking for a `changed' flag, assuming of course + this would never be done while the simulation is running. */ + free_search_tree (ar->range_tree); + build_search_tree (ar); +} + +void +sim_addr_range_delete (ADDR_RANGE *ar, address_word start, address_word end) +{ + frob_range (ar, start, end, 1); + + /* Rebuild the search tree. */ + /* ??? Instead of rebuilding it here it could be done in a module resume + handler, say by first checking for a `changed' flag, assuming of course + this would never be done while the simulation is running. */ + free_search_tree (ar->range_tree); + build_search_tree (ar); +} + +#endif /* DEFINE_NON_INLINE_P */ + +#if DEFINE_INLINE_P + +SIM_ARANGE_INLINE int +sim_addr_range_hit_p (ADDR_RANGE *ar, address_word addr) +{ + ADDR_RANGE_TREE *t = ar->range_tree; + + while (t != NULL) + { + if (addr < t->start) + t = t->lower; + else if (addr > t->end) + t = t->higher; + else + return 1; + } + return 0; +} + +#endif /* DEFINE_INLINE_P */ diff --git a/sim/common/sim-arange.h b/sim/common/sim-arange.h new file mode 100644 index 0000000..10ba0f4 --- /dev/null +++ b/sim/common/sim-arange.h @@ -0,0 +1,83 @@ +/* Address ranges. + Copyright (C) 1998 Free Software Foundation, Inc. + Contributed by Cygnus Solutions. + +This file is part of the GNU Simulators. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file is meant to be included by sim-basics.h. */ + +#ifndef SIM_ARANGE_H +#define SIM_ARANGE_H + +/* A list of address ranges. */ + +typedef struct _addr_subrange { + struct _addr_subrange *next; + + /* Range of addresses to be traced is [start,end]. */ + address_word start,end; +} ADDR_SUBRANGE; + +/* For speed, searching is done on a tree. */ + +typedef struct _addr_range_tree { + struct _addr_range_tree *lower; + struct _addr_range_tree *higher; + + /* Range of addresses to be traced is [start,end]. */ + address_word start,end; +} ADDR_RANGE_TREE; + +/* The top level struct. */ + +typedef struct _addr_range { + ADDR_SUBRANGE *ranges; +#define ADDR_RANGE_RANGES(ar) ((ar)->ranges) + ADDR_RANGE_TREE *range_tree; +#define ADDR_RANGE_TREE(ar) ((ar)->range_tree) +} ADDR_RANGE; + +/* Add address range START,END to AR. */ +extern void sim_addr_range_add (ADDR_RANGE * /*ar*/, + address_word /*start*/, + address_word /*end*/); + +/* Delete address range START,END from AR. */ +extern void sim_addr_range_delete (ADDR_RANGE * /*ar*/, + address_word /*start*/, + address_word /*end*/); + +/* Return non-zero if ADDR is in range AR, traversing the entire tree. + If no range is specified, that is defined to mean "everything". */ +extern INLINE int +sim_addr_range_hit_p (ADDR_RANGE * /*ar*/, address_word /*addr*/); +#define ADDR_RANGE_HIT_P(ar, addr) \ + ((ar)->range_tree == NULL || sim_addr_range_hit_p ((ar), (addr))) + +#ifdef HAVE_INLINE +#ifdef SIM_ARANGE_C +#define SIM_ARANGE_INLINE INLINE +#else +#define SIM_ARANGE_INLINE EXTERN_INLINE +#endif +#include "sim-arange.c" +#else +#define SIM_ARANGE_INLINE +#endif +#define SIM_ARANGE_C_INCLUDED + +#endif /* SIM_ARANGE_H */ diff --git a/sim/common/sim-assert.h b/sim/common/sim-assert.h new file mode 100644 index 0000000..0274084 --- /dev/null +++ b/sim/common/sim-assert.h @@ -0,0 +1,90 @@ +/* This file is part of the program GDB. + + Copyright (C) 1997, Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef _SIM_ASSERT_H_ +#define _SIM_ASSERT_H_ + +#define SIM_FILTER_PATH(FILE, PATH) \ +do \ + { \ + /* strip leading path */ \ + const char *p = (PATH); \ + (FILE) = p; \ + while (*p != '\0' && *p != ':') \ + { \ + if (*p == '/') \ + (FILE) = p + 1; \ + p++; \ + } \ + } \ +while (0) + +/* The subtle difference between SIM_ASSERT and ASSERT is that + SIM_ASSERT passes `sd' to sim_io_error for the SIM_DESC, + ASSERT passes NULL. */ + +#if !defined (SIM_ASSERT) +#if defined (WITH_ASSERT) +#define SIM_ASSERT(EXPRESSION) \ +do \ + { \ + if (WITH_ASSERT) \ + { \ + if (!(EXPRESSION)) \ + { \ + /* report the failure */ \ + const char *file; \ + SIM_FILTER_PATH(file, __FILE__); \ + sim_io_error (sd, "%s:%d: assertion failed - %s", \ + file, __LINE__, #EXPRESSION); \ + } \ + } \ + } \ +while (0) +#else +#define SIM_ASSERT(EXPRESSION) do { /*nothing*/; } while (0) +#endif +#endif + +#if !defined (ASSERT) +#if defined (WITH_ASSERT) +#define ASSERT(EXPRESSION) \ +do \ + { \ + if (WITH_ASSERT) \ + { \ + if (!(EXPRESSION)) \ + { \ + /* report the failure */ \ + const char *file; \ + SIM_FILTER_PATH(file, __FILE__); \ + sim_io_error (NULL, "%s:%d: assertion failed - %s", \ + file, __LINE__, #EXPRESSION); \ + } \ + } \ + } \ +while (0) +#else +#define ASSERT(EXPRESSION) do { /*nothing*/; } while (0) +#endif +#endif + +#endif diff --git a/sim/common/sim-base.h b/sim/common/sim-base.h new file mode 100644 index 0000000..3fe01b4 --- /dev/null +++ b/sim/common/sim-base.h @@ -0,0 +1,252 @@ +/* Simulator pseudo baseclass. + Copyright (C) 1997-1998 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +/* Simulator state pseudo baseclass. + + Each simulator is required to have the file ``sim-main.h''. That + file includes ``sim-basics.h'', defines the base type ``sim_cia'' + (the data type that contains complete current instruction address + information), include ``sim-base.h'': + + #include "sim-basics.h" + typedef address_word sim_cia; + /-* If `sim_cia' is not an integral value (e.g. a struct), define + CIA_ADDR to return the integral value. *-/ + /-* #define CIA_ADDR(cia) (...) *-/ + #include "sim-base.h" + + finally, two data types `struct _sim_cpu' and `struct sim_state' + are defined: + + struct _sim_cpu { + ... simulator specific members ... + sim_cpu_base base; + }; + + struct sim_state { + sim_cpu cpu[MAX_NR_PROCESSORS]; + #if (WITH_SMP) + #define STATE_CPU(sd,n) (&(sd)->cpu[n]) + #else + #define STATE_CPU(sd,n) (&(sd)->cpu[0]) + #endif + ... simulator specific members ... + sim_state_base base; + }; + + Note that `base' appears last. This makes `base.magic' appear last + in the entire struct and helps catch miscompilation errors. */ + + +#ifndef SIM_BASE_H +#define SIM_BASE_H + +/* Pre-declare certain types. */ + +/* typedef <target-dependant> sim_cia; */ +#ifndef NULL_CIA +#define NULL_CIA ((sim_cia) 0) +#endif +/* Return the current instruction address as a number. + Some targets treat the current instruction address as a struct + (e.g. for delay slot handling). */ +#ifndef CIA_ADDR +#define CIA_ADDR(cia) (cia) +#endif +#ifndef INVALID_INSTRUCTION_ADDRESS +#define INVALID_INSTRUCTION_ADDRESS ((address_word)0 - 1) +#endif + +typedef struct _sim_cpu sim_cpu; + +#include "sim-module.h" + +#include "sim-trace.h" +#include "sim-core.h" +#include "sim-events.h" +#include "sim-profile.h" +#ifdef SIM_HAVE_MODEL +#include "sim-model.h" +#endif +#include "sim-io.h" +#include "sim-engine.h" +#include "sim-watch.h" +#include "sim-memopt.h" +#ifdef SIM_HAVE_BREAKPOINTS +#include "sim-break.h" +#endif +#include "sim-cpu.h" + +/* Global pointer to current state while sim_resume is running. + On a machine with lots of registers, it might be possible to reserve + one of them for current_state. However on a machine with few registers + current_state can't permanently live in one and indirecting through it + will be slower [in which case one can have sim_resume set globals from + current_state for faster access]. + If CURRENT_STATE_REG is defined, it means current_state is living in + a global register. */ + + +#ifdef CURRENT_STATE_REG +/* FIXME: wip */ +#else +extern struct sim_state *current_state; +#endif + + +/* The simulator may provide different (and faster) definition. */ +#ifndef CURRENT_STATE +#define CURRENT_STATE current_state +#endif + + +typedef struct { + + /* Simulator's argv[0]. */ + const char *my_name; +#define STATE_MY_NAME(sd) ((sd)->base.my_name) + + /* Who opened the simulator. */ + SIM_OPEN_KIND open_kind; +#define STATE_OPEN_KIND(sd) ((sd)->base.open_kind) + + /* The host callbacks. */ + struct host_callback_struct *callback; +#define STATE_CALLBACK(sd) ((sd)->base.callback) + + /* The type of simulation environment (user/operating). */ + enum sim_environment environment; +#define STATE_ENVIRONMENT(sd) ((sd)->base.environment) + +#if 0 /* FIXME: Not ready yet. */ + /* Stuff defined in sim-config.h. */ + struct sim_config config; +#define STATE_CONFIG(sd) ((sd)->base.config) +#endif + + /* List of installed module `init' handlers. */ + struct module_list *modules; +#define STATE_MODULES(sd) ((sd)->base.modules) + + /* Supported options. */ + struct option_list *options; +#define STATE_OPTIONS(sd) ((sd)->base.options) + + /* Non-zero if -v specified. */ + int verbose_p; +#define STATE_VERBOSE_P(sd) ((sd)->base.verbose_p) + + /* Non cpu-specific trace data. See sim-trace.h. */ + TRACE_DATA trace_data; +#define STATE_TRACE_DATA(sd) (& (sd)->base.trace_data) + + /* If non NULL, the BFD architecture specified on the command line */ + const struct bfd_arch_info *architecture; +#define STATE_ARCHITECTURE(sd) ((sd)->base.architecture) + + /* If non NULL, the bfd target specified on the command line */ + const char *target; +#define STATE_TARGET(sd) ((sd)->base.target) + + /* In standalone simulator, this is the program's arguments passed + on the command line. */ + char **prog_argv; +#define STATE_PROG_ARGV(sd) ((sd)->base.prog_argv) + + /* The program's bfd. */ + struct _bfd *prog_bfd; +#define STATE_PROG_BFD(sd) ((sd)->base.prog_bfd) + + /* Symbol table for prog_bfd */ + struct symbol_cache_entry **prog_syms; +#define STATE_PROG_SYMS(sd) ((sd)->base.prog_syms) + + /* The program's text section. */ + struct sec *text_section; + /* Starting and ending text section addresses from the bfd. */ + SIM_ADDR text_start, text_end; +#define STATE_TEXT_SECTION(sd) ((sd)->base.text_section) +#define STATE_TEXT_START(sd) ((sd)->base.text_start) +#define STATE_TEXT_END(sd) ((sd)->base.text_end) + + /* Start address, set when the program is loaded from the bfd. */ + SIM_ADDR start_addr; +#define STATE_START_ADDR(sd) ((sd)->base.start_addr) + + /* Size of the simulator's cache, if any. + This is not the target's cache. It is the cache the simulator uses + to process instructions. */ + unsigned int scache_size; +#define STATE_SCACHE_SIZE(sd) ((sd)->base.scache_size) + + /* FIXME: Move to top level sim_state struct (as some struct)? */ +#ifdef SIM_HAVE_FLATMEM + unsigned int mem_size; +#define STATE_MEM_SIZE(sd) ((sd)->base.mem_size) + unsigned int mem_base; +#define STATE_MEM_BASE(sd) ((sd)->base.mem_base) + unsigned char *memory; +#define STATE_MEMORY(sd) ((sd)->base.memory) +#endif + + /* core memory bus */ +#define STATE_CORE(sd) (&(sd)->base.core) + sim_core core; + + /* Record of memory sections added via the memory-options interface. */ +#define STATE_MEMOPT(sd) ((sd)->base.memopt) + sim_memopt *memopt; + + /* event handler */ +#define STATE_EVENTS(sd) (&(sd)->base.events) + sim_events events; + + /* generic halt/resume engine */ + sim_engine engine; +#define STATE_ENGINE(sd) (&(sd)->base.engine) + + /* generic watchpoint support */ + sim_watchpoints watchpoints; +#define STATE_WATCHPOINTS(sd) (&(sd)->base.watchpoints) + + /* Pointer to list of breakpoints */ + struct sim_breakpoint *breakpoints; +#define STATE_BREAKPOINTS(sd) ((sd)->base.breakpoints) + +#if WITH_HW + struct sim_hw *hw; +#define STATE_HW(sd) ((sd)->base.hw) +#endif + + + /* Marker for those wanting to do sanity checks. + This should remain the last member of this struct to help catch + miscompilation errors. */ + int magic; +#define SIM_MAGIC_NUMBER 0x4242 +#define STATE_MAGIC(sd) ((sd)->base.magic) +} sim_state_base; + +/* Functions for allocating/freeing a sim_state. */ +SIM_DESC sim_state_alloc PARAMS ((SIM_OPEN_KIND kind, host_callback *callback)); +void sim_state_free PARAMS ((SIM_DESC)); + +#endif /* SIM_BASE_H */ diff --git a/sim/common/sim-basics.h b/sim/common/sim-basics.h new file mode 100644 index 0000000..fc34b21 --- /dev/null +++ b/sim/common/sim-basics.h @@ -0,0 +1,154 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au> + Copyright (C) 1997, 1998, Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef _SIM_BASICS_H_ +#define _SIM_BASICS_H_ + + +/* Basic configuration */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* Basic host dependant mess - hopefully <stdio.h> + <stdarg.h> will + bring potential conflicts out in the open */ + +#include <stdarg.h> +#include <stdio.h> +#include <setjmp.h> + +#ifdef __CYGWIN32__ +extern int vasprintf (char **result, const char *format, va_list args); +extern int asprintf (char **result, const char *format, ...); +#endif + + +#ifndef NULL +#define NULL 0 +#endif + + + +/* Some versions of GCC include an attribute operator, define it */ + +#if !defined (__attribute__) +#if (!defined(__GNUC__) || (__GNUC__ < 2) || (__GNUC__ == 2 && __GNUC_MINOR__ < 6)) +#define __attribute__(arg) +#endif +#endif + + +/* Global types that code manipulates */ + +typedef struct _device device; +struct hw; +struct _sim_fpu; + + +/* Generic address space (maps) and access attributes */ + +enum { + read_map = 0, + write_map = 1, + exec_map = 2, + io_map = 3, + nr_maps = 32, /* something small */ +}; + +enum { + access_invalid = 0, + access_read = 1 << read_map, + access_write = 1 << write_map, + access_exec = 1 << exec_map, + access_io = 1 << io_map, +}; + +enum { + access_read_write = (access_read | access_write), + access_read_exec = (access_read | access_exec), + access_write_exec = (access_write | access_exec), + access_read_write_exec = (access_read | access_write | access_exec), + access_read_io = (access_read | access_io), + access_write_io = (access_write | access_io), + access_read_write_io = (access_read | access_write | access_io), + access_exec_io = (access_exec | access_io), + access_read_exec_io = (access_read | access_exec | access_io), + access_write_exec_io = (access_write | access_exec | access_io), + access_read_write_exec_io = (access_read | access_write | access_exec | access_io), +}; + + +/* disposition of an object when things are reset */ + +typedef enum { + permenant_object, + temporary_object, +} object_disposition; + + +/* Memory transfer types */ + +typedef enum _transfer_type { + read_transfer, + write_transfer, +} transfer_type; + + +/* directions */ + +typedef enum { + bidirect_port, + input_port, + output_port, +} port_direction; + + + +/* Basic definitions - ordered so that nothing calls what comes after it. */ + +/* FIXME: conditionalizing tconfig.h on HAVE_CONFIG_H seems wrong. */ +#ifdef HAVE_CONFIG_H +#include "tconfig.h" +#endif + +#include "ansidecl.h" +#include "callback.h" +#include "remote-sim.h" + +#include "sim-config.h" + +#include "sim-inline.h" + +#include "sim-types.h" +#include "sim-bits.h" +#include "sim-endian.h" +#include "sim-signal.h" +#include "sim-arange.h" + +#include "sim-utils.h" + +/* Note: Only the simpler interfaces are defined here. More heavy + weight objects, such as core and events, are defined in the more + serious sim-base.h header. */ + +#endif /* _SIM_BASICS_H_ */ diff --git a/sim/common/sim-bits.c b/sim/common/sim-bits.c new file mode 100644 index 0000000..ecfb73b --- /dev/null +++ b/sim/common/sim-bits.c @@ -0,0 +1,208 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef _SIM_BITS_C_ +#define _SIM_BITS_C_ + +#include "sim-basics.h" +#include "sim-assert.h" +#include "sim-io.h" + + +INLINE_SIM_BITS\ +(unsigned_word) +LSMASKED (unsigned_word val, + int start, + int stop) +{ + /* NOTE - start, stop can wrap */ + val &= LSMASK (start, stop); + return val; +} + + +INLINE_SIM_BITS\ +(unsigned_word) +MSMASKED (unsigned_word val, + int start, + int stop) +{ + /* NOTE - start, stop can wrap */ + val &= MSMASK (start, stop); + return val; +} + + +INLINE_SIM_BITS\ +(unsigned_word) +LSEXTRACTED (unsigned_word val, + int start, + int stop) +{ + ASSERT (start >= stop); +#if (WITH_TARGET_WORD_BITSIZE == 64) + return LSEXTRACTED64 (val, start, stop); +#endif +#if (WITH_TARGET_WORD_BITSIZE == 32) + if (stop >= 32) + return 0; + else + { + if (start < 32) + val &= LSMASK (start, 0); + val >>= stop; + return val; + } +#endif +} + + +INLINE_SIM_BITS\ +(unsigned_word) +MSEXTRACTED (unsigned_word val, + int start, + int stop) +{ + ASSERT (start <= stop); +#if (WITH_TARGET_WORD_BITSIZE == 64) + return MSEXTRACTED64 (val, start, stop); +#endif +#if (WITH_TARGET_WORD_BITSIZE == 32) + if (stop < 32) + return 0; + else + { + if (start >= 32) + val &= MSMASK (start, 64 - 1); + val >>= (64 - stop - 1); + return val; + } +#endif +} + + +INLINE_SIM_BITS\ +(unsigned_word) +LSINSERTED (unsigned_word val, + int start, + int stop) +{ + ASSERT (start >= stop); +#if (WITH_TARGET_WORD_BITSIZE == 64) + return LSINSERTED64 (val, start, stop); +#endif +#if (WITH_TARGET_WORD_BITSIZE == 32) + /* Bit numbers are 63..0, even for 32 bit targets. + On 32 bit targets we ignore 63..32 */ + if (stop >= 32) + return 0; + else + { + val <<= stop; + val &= LSMASK (start, stop); + return val; + } +#endif +} + +INLINE_SIM_BITS\ +(unsigned_word) +MSINSERTED (unsigned_word val, + int start, + int stop) +{ + ASSERT (start <= stop); +#if (WITH_TARGET_WORD_BITSIZE == 64) + return MSINSERTED64 (val, start, stop); +#endif +#if (WITH_TARGET_WORD_BITSIZE == 32) + /* Bit numbers are 0..63, even for 32 bit targets. + On 32 bit targets we ignore 0..31. */ + if (stop < 32) + return 0; + else + { + val <<= ((64 - 1) - stop); + val &= MSMASK (start, stop); + return val; + } +#endif +} + + + +INLINE_SIM_BITS\ +(unsigned_word) +LSSEXT (signed_word val, + int sign_bit) +{ + ASSERT (sign_bit < 64); +#if (WITH_TARGET_WORD_BITSIZE == 64) + return LSSEXT64 (val, sign_bit); +#endif +#if (WITH_TARGET_WORD_BITSIZE == 32) + if (sign_bit >= 32) + return val; + else { + val = LSSEXT32 (val, sign_bit); + return val; + } +#endif +} + +INLINE_SIM_BITS\ +(unsigned_word) +MSSEXT (signed_word val, + int sign_bit) +{ + ASSERT (sign_bit < 64); +#if (WITH_TARGET_WORD_BITSIZE == 64) + return MSSEXT64 (val, sign_bit); +#endif +#if (WITH_TARGET_WORD_BITSIZE == 32) + if (sign_bit < 32) + return val; + else { + val = MSSEXT32 (val, sign_bit - 32); + return val; + } +#endif +} + + + +#define N 8 +#include "sim-n-bits.h" +#undef N + +#define N 16 +#include "sim-n-bits.h" +#undef N + +#define N 32 +#include "sim-n-bits.h" +#undef N + +#define N 64 +#include "sim-n-bits.h" +#undef N + +#endif /* _SIM_BITS_C_ */ diff --git a/sim/common/sim-bits.h b/sim/common/sim-bits.h new file mode 100644 index 0000000..d111bcd --- /dev/null +++ b/sim/common/sim-bits.h @@ -0,0 +1,564 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au> + Copyright (C) 1997, Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef _SIM_BITS_H_ +#define _SIM_BITS_H_ + + +/* Bit manipulation routines: + + Bit numbering: The bits are numbered according to the target ISA's + convention. That being controlled by WITH_TARGET_WORD_MSB. For + the PowerPC (WITH_TARGET_WORD_MSB == 0) the numbering is 0..31 + while for the MIPS (WITH_TARGET_WORD_MSB == 31) it is 31..0. + + Size convention: Each macro is in three forms - <MACRO>32 which + operates in 32bit quantity (bits are numbered 0..31); <MACRO>64 + which operates using 64bit quantites (and bits are numbered 0..63); + and <MACRO> which operates using the bit size of the target + architecture (bits are still numbered 0..63), with 32bit + architectures ignoring the first 32bits leaving bit 32 as the most + significant. + + NB: Use EXTRACTED, MSEXTRACTED and LSEXTRACTED as a guideline for + naming. LSMASK and LSMASKED are wrong. + + BIT*(POS): `*' bit constant with just 1 bit set. + + LSBIT*(OFFSET): `*' bit constant with just 1 bit set - LS bit is + zero. + + MSBIT*(OFFSET): `*' bit constant with just 1 bit set - MS bit is + zero. + + MASK*(FIRST, LAST): `*' bit constant with bits [FIRST .. LAST] + set. The <MACRO> (no size) version permits FIRST >= LAST and + generates a wrapped bit mask vis ([0..LAST] | [FIRST..LSB]). + + LSMASK*(FIRST, LAST): Like MASK - LS bit is zero. + + MSMASK*(FIRST, LAST): Like MASK - LS bit is zero. + + MASKED*(VALUE, FIRST, LAST): Masks out all but bits [FIRST + .. LAST]. + + LSMASKED*(VALUE, FIRST, LAST): Like MASKED - LS bit is zero. + + MSMASKED*(VALUE, FIRST, LAST): Like MASKED - MS bit is zero. + + EXTRACTED*(VALUE, FIRST, LAST): Masks out bits [FIRST .. LAST] but + also right shifts the masked value so that bit LAST becomes the + least significant (right most). + + LSEXTRACTED*(VALUE, FIRST, LAST): Same as extracted - LS bit is + zero. + + MSEXTRACTED*(VALUE, FIRST, LAST): Same as extracted - MS bit is + zero. + + SHUFFLED**(VALUE, OLD, NEW): Mask then move a single bit from OLD + new NEW. + + MOVED**(VALUE, OLD_FIRST, OLD_LAST, NEW_FIRST, NEW_LAST): Moves + things around so that bits OLD_FIRST..OLD_LAST are masked then + moved to NEW_FIRST..NEW_LAST. + + INSERTED*(VALUE, FIRST, LAST): Takes VALUE and `inserts' the (LAST + - FIRST + 1) least significant bits into bit positions [ FIRST + .. LAST ]. This is almost the complement to EXTRACTED. + + IEA_MASKED(SHOULD_MASK, ADDR): Convert the address to the targets + natural size. If in 32bit mode, discard the high 32bits. + + EXTEND*(VALUE): Convert the `*' bit value to the targets natural + word size. Sign extend the value if needed. + + ALIGN_*(VALUE): Round the value upwards so that it is aligned to a + `_*' byte boundary. + + FLOOR_*(VALUE): Truncate the value so that it is aligned to a `_*' + byte boundary. + + ROT*(VALUE, NR_BITS): Return the `*' bit VALUE rotated by NR_BITS + right (positive) or left (negative). + + ROTL*(VALUE, NR_BITS): Return the `*' bit value rotated by NR_BITS + left. 0 <= NR_BITS <= `*'. + + ROTR*(VALUE, NR_BITS): Return the `*' bit value rotated by NR_BITS + right. 0 <= NR_BITS <= N. + + SEXT*(VALUE, SIGN_BIT): Treat SIGN_BIT as VALUEs sign, extend it ti + `*' bits. + + Note: Only the BIT* and MASK* macros return a constant that can be + used in variable declarations. + + */ + + +/* compute the number of bits between START and STOP */ + +#if (WITH_TARGET_WORD_MSB == 0) +#define _MAKE_WIDTH(START, STOP) (STOP - START + 1) +#else +#define _MAKE_WIDTH(START, STOP) (START - STOP + 1) +#endif + + + +/* compute the number shifts required to move a bit between LSB (MSB) + and POS */ + +#if (WITH_TARGET_WORD_MSB == 0) +#define _LSB_SHIFT(WIDTH, POS) (WIDTH - 1 - POS) +#else +#define _LSB_SHIFT(WIDTH, POS) (POS) +#endif + +#if (WITH_TARGET_WORD_MSB == 0) +#define _MSB_SHIFT(WIDTH, POS) (POS) +#else +#define _MSB_SHIFT(WIDTH, POS) (WIDTH - 1 - POS) +#endif + + +/* compute the absolute bit position given the OFFSET from the MSB(LSB) + NB: _MAKE_xxx_POS (WIDTH, _MAKE_xxx_SHIFT (WIDTH, POS)) == POS */ + +#if (WITH_TARGET_WORD_MSB == 0) +#define _MSB_POS(WIDTH, SHIFT) (SHIFT) +#else +#define _MSB_POS(WIDTH, SHIFT) (WIDTH - 1 - SHIFT) +#endif + +#if (WITH_TARGET_WORD_MSB == 0) +#define _LSB_POS(WIDTH, SHIFT) (WIDTH - 1 - SHIFT) +#else +#define _LSB_POS(WIDTH, SHIFT) (SHIFT) +#endif + + +/* convert a 64 bit position into a corresponding 32bit position. MSB + pos handles the posibility that the bit lies beyond the 32bit + boundary */ + +#if (WITH_TARGET_WORD_MSB == 0) +#define _MSB_32(START, STOP) (START <= STOP \ + ? (START < 32 ? 0 : START - 32) \ + : (STOP < 32 ? 0 : STOP - 32)) +#else +#define _MSB_32(START, STOP) (START >= STOP \ + ? (START >= 32 ? 31 : START) \ + : (STOP >= 32 ? 31 : STOP)) +#endif + +#if (WITH_TARGET_WORD_MSB == 0) +#define _LSB_32(START, STOP) (START <= STOP \ + ? (STOP < 32 ? 0 : STOP - 32) \ + : (START < 32 ? 0 : START - 32)) +#else +#define _LSB_32(START, STOP) (START >= STOP \ + ? (STOP >= 32 ? 31 : STOP) \ + : (START >= 32 ? 31 : START)) +#endif + +#if (WITH_TARGET_WORD_MSB == 0) +#define _MSB(START, STOP) (START <= STOP ? START : STOP) +#else +#define _MSB(START, STOP) (START >= STOP ? START : STOP) +#endif + +#if (WITH_TARGET_WORD_MSB == 0) +#define _LSB(START, STOP) (START <= STOP ? STOP : START) +#else +#define _LSB(START, STOP) (START >= STOP ? STOP : START) +#endif + + +/* LS/MS Bit operations */ + +#define LSBIT8(POS) ((unsigned8) 1 << (POS)) +#define LSBIT16(POS) ((unsigned16)1 << (POS)) +#define LSBIT32(POS) ((unsigned32)1 << (POS)) +#define LSBIT64(POS) ((unsigned64)1 << (POS)) + +#if (WITH_TARGET_WORD_BITSIZE == 64) +#define LSBIT(POS) LSBIT64 (POS) +#else +#define LSBIT(POS) ((unsigned32)((POS) >= 32 \ + ? 0 \ + : (1 << ((POS) >= 32 ? 0 : (POS))))) +#endif + + +#define MSBIT8(POS) ((unsigned8) 1 << ( 8 - 1 - (POS))) +#define MSBIT16(POS) ((unsigned16)1 << (16 - 1 - (POS))) +#define MSBIT32(POS) ((unsigned32)1 << (32 - 1 - (POS))) +#define MSBIT64(POS) ((unsigned64)1 << (64 - 1 - (POS))) + +#if (WITH_TARGET_WORD_BITSIZE == 64) +#define MSBIT(POS) MSBIT64 (POS) +#else +#define MSBIT(POS) ((unsigned32)((POS) < 32 \ + ? 0 \ + : (1 << ((POS) < 32 ? 0 : (64 - 1) - (POS))))) +#endif + + +/* Bit operations */ + +#define BIT4(POS) (1 << _LSB_SHIFT (4, (POS))) +#define BIT5(POS) (1 << _LSB_SHIFT (5, (POS))) +#define BIT10(POS) (1 << _LSB_SHIFT (10, (POS))) + +#if (WITH_TARGET_WORD_MSB == 0) +#define BIT8 MSBIT8 +#define BIT16 MSBIT16 +#define BIT32 MSBIT32 +#define BIT64 MSBIT64 +#define BIT MSBIT +#else +#define BIT8 LSBIT8 +#define BIT16 LSBIT16 +#define BIT32 LSBIT32 +#define BIT64 LSBIT64 +#define BIT LSBIT +#endif + + + +/* multi bit mask */ + +/* 111111 -> mmll11 -> mm11ll */ +#define _MASKn(WIDTH, START, STOP) (((unsigned##WIDTH)(-1) \ + >> (_MSB_SHIFT (WIDTH, START) \ + + _LSB_SHIFT (WIDTH, STOP))) \ + << _LSB_SHIFT (WIDTH, STOP)) + +#if (WITH_TARGET_WORD_MSB == 0) +#define _POS_LE(START, STOP) (START <= STOP) +#else +#define _POS_LE(START, STOP) (STOP <= START) +#endif + +#if (WITH_TARGET_WORD_BITSIZE == 64) +#define MASK(START, STOP) \ + (_POS_LE ((START), (STOP)) \ + ? _MASKn(64, \ + _MSB ((START), (STOP)), \ + _LSB ((START), (STOP)) ) \ + : (_MASKn(64, _MSB_POS (64, 0), (STOP)) \ + | _MASKn(64, (START), _LSB_POS (64, 0)))) +#endif +#if (WITH_TARGET_WORD_BITSIZE == 32) +#define MASK(START, STOP) \ + (_POS_LE ((START), (STOP)) \ + ? (_POS_LE ((STOP), _MSB_POS (64, 31)) \ + ? 0 \ + : _MASKn (32, \ + _MSB_32 ((START), (STOP)), \ + _LSB_32 ((START), (STOP)))) \ + : (_MASKn (32, \ + _LSB_32 ((START), (STOP)), \ + _LSB_POS (32, 0)) \ + | (_POS_LE ((STOP), _MSB_POS (64, 31)) \ + ? 0 \ + : _MASKn (32, \ + _MSB_POS (32, 0), \ + _MSB_32 ((START), (STOP)))))) +#endif +#if !defined (MASK) +#error "MASK never undefined" +#endif + + +/* Multi-bit mask on least significant bits */ + +#define _LSMASKn(WIDTH, FIRST, LAST) _MASKn (WIDTH, \ + _LSB_POS (WIDTH, FIRST), \ + _LSB_POS (WIDTH, LAST)) + +#define LSMASK8(FIRST, LAST) _LSMASKn ( 8, (FIRST), (LAST)) +#define LSMASK16(FIRST, LAST) _LSMASKn (16, (FIRST), (LAST)) +#define LSMASK32(FIRST, LAST) _LSMASKn (32, (FIRST), (LAST)) +#define LSMASK64(FIRST, LAST) _LSMASKn (64, (FIRST), (LAST)) + +#define LSMASK(FIRST, LAST) (MASK (_LSB_POS (64, FIRST), _LSB_POS (64, LAST))) + + +/* Multi-bit mask on most significant bits */ + +#define _MSMASKn(WIDTH, FIRST, LAST) _MASKn (WIDTH, \ + _MSB_POS (WIDTH, FIRST), \ + _MSB_POS (WIDTH, LAST)) + +#define MSMASK8(FIRST, LAST) _MSMASKn ( 8, (FIRST), (LAST)) +#define MSMASK16(FIRST, LAST) _MSMASKn (16, (FIRST), (LAST)) +#define MSMASK32(FIRST, LAST) _MSMASKn (32, (FIRST), (LAST)) +#define MSMASK64(FIRST, LAST) _MSMASKn (64, (FIRST), (LAST)) + +#define MSMASK(FIRST, LAST) (MASK (_MSB_POS (64, FIRST), _MSB_POS (64, LAST))) + + + +#if (WITH_TARGET_WORD_MSB == 0) +#define MASK8 MSMASK8 +#define MASK16 MSMASK16 +#define MASK32 MSMASK32 +#define MASK64 MSMASK64 +#else +#define MASK8 LSMASK8 +#define MASK16 LSMASK16 +#define MASK32 LSMASK32 +#define MASK64 LSMASK64 +#endif + + + +/* mask the required bits, leaving them in place */ + +INLINE_SIM_BITS(unsigned8) LSMASKED8 (unsigned8 word, int first, int last); +INLINE_SIM_BITS(unsigned16) LSMASKED16 (unsigned16 word, int first, int last); +INLINE_SIM_BITS(unsigned32) LSMASKED32 (unsigned32 word, int first, int last); +INLINE_SIM_BITS(unsigned64) LSMASKED64 (unsigned64 word, int first, int last); + +INLINE_SIM_BITS(unsigned_word) LSMASKED (unsigned_word word, int first, int last); + +INLINE_SIM_BITS(unsigned8) MSMASKED8 (unsigned8 word, int first, int last); +INLINE_SIM_BITS(unsigned16) MSMASKED16 (unsigned16 word, int first, int last); +INLINE_SIM_BITS(unsigned32) MSMASKED32 (unsigned32 word, int first, int last); +INLINE_SIM_BITS(unsigned64) MSMASKED64 (unsigned64 word, int first, int last); + +INLINE_SIM_BITS(unsigned_word) MSMASKED (unsigned_word word, int first, int last); + +#if (WITH_TARGET_WORD_MSB == 0) +#define MASKED8 MSMASKED8 +#define MASKED16 MSMASKED16 +#define MASKED32 MSMASKED32 +#define MASKED64 MSMASKED64 +#define MASKED MSMASKED +#else +#define MASKED8 LSMASKED8 +#define MASKED16 LSMASKED16 +#define MASKED32 LSMASKED32 +#define MASKED64 LSMASKED64 +#define MASKED LSMASKED +#endif + + + +/* extract the required bits aligning them with the lsb */ + +INLINE_SIM_BITS(unsigned8) LSEXTRACTED8 (unsigned8 val, int start, int stop); +INLINE_SIM_BITS(unsigned16) LSEXTRACTED16 (unsigned16 val, int start, int stop); +INLINE_SIM_BITS(unsigned32) LSEXTRACTED32 (unsigned32 val, int start, int stop); +INLINE_SIM_BITS(unsigned64) LSEXTRACTED64 (unsigned64 val, int start, int stop); + +INLINE_SIM_BITS(unsigned_word) LSEXTRACTED (unsigned_word val, int start, int stop); + +INLINE_SIM_BITS(unsigned8) MSEXTRACTED8 (unsigned8 val, int start, int stop); +INLINE_SIM_BITS(unsigned16) MSEXTRACTED16 (unsigned16 val, int start, int stop); +INLINE_SIM_BITS(unsigned32) MSEXTRACTED32 (unsigned32 val, int start, int stop); +INLINE_SIM_BITS(unsigned64) MSEXTRACTED64 (unsigned64 val, int start, int stop); + +INLINE_SIM_BITS(unsigned_word) MSEXTRACTED (unsigned_word val, int start, int stop); + +#if (WITH_TARGET_WORD_MSB == 0) +#define EXTRACTED8 MSEXTRACTED8 +#define EXTRACTED16 MSEXTRACTED16 +#define EXTRACTED32 MSEXTRACTED32 +#define EXTRACTED64 MSEXTRACTED64 +#define EXTRACTED MSEXTRACTED +#else +#define EXTRACTED8 LSEXTRACTED8 +#define EXTRACTED16 LSEXTRACTED16 +#define EXTRACTED32 LSEXTRACTED32 +#define EXTRACTED64 LSEXTRACTED64 +#define EXTRACTED LSEXTRACTED +#endif + + + +/* move a single bit around */ +/* NB: the wierdness (N>O?N-O:0) is to stop a warning from GCC */ +#define _SHUFFLEDn(N, WORD, OLD, NEW) \ +((OLD) < (NEW) \ + ? (((unsigned##N)(WORD) \ + >> (((NEW) > (OLD)) ? ((NEW) - (OLD)) : 0)) \ + & MASK32((NEW), (NEW))) \ + : (((unsigned##N)(WORD) \ + << (((OLD) > (NEW)) ? ((OLD) - (NEW)) : 0)) \ + & MASK32((NEW), (NEW)))) + +#define SHUFFLED32(WORD, OLD, NEW) _SHUFFLEDn (32, WORD, OLD, NEW) +#define SHUFFLED64(WORD, OLD, NEW) _SHUFFLEDn (64, WORD, OLD, NEW) + +#define SHUFFLED(WORD, OLD, NEW) _SHUFFLEDn (_word, WORD, OLD, NEW) + + +/* Insert a group of bits into a bit position */ + +INLINE_SIM_BITS(unsigned8) LSINSERTED8 (unsigned8 val, int start, int stop); +INLINE_SIM_BITS(unsigned16) LSINSERTED16 (unsigned16 val, int start, int stop); +INLINE_SIM_BITS(unsigned32) LSINSERTED32 (unsigned32 val, int start, int stop); +INLINE_SIM_BITS(unsigned64) LSINSERTED64 (unsigned64 val, int start, int stop); +INLINE_SIM_BITS(unsigned_word) LSINSERTED (unsigned_word val, int start, int stop); + +INLINE_SIM_BITS(unsigned8) MSINSERTED8 (unsigned8 val, int start, int stop); +INLINE_SIM_BITS(unsigned16) MSINSERTED16 (unsigned16 val, int start, int stop); +INLINE_SIM_BITS(unsigned32) MSINSERTED32 (unsigned32 val, int start, int stop); +INLINE_SIM_BITS(unsigned64) MSINSERTED64 (unsigned64 val, int start, int stop); +INLINE_SIM_BITS(unsigned_word) MSINSERTED (unsigned_word val, int start, int stop); + +#if (WITH_TARGET_WORD_MSB == 0) +#define INSERTED8 MSINSERTED8 +#define INSERTED16 MSINSERTED16 +#define INSERTED32 MSINSERTED32 +#define INSERTED64 MSINSERTED64 +#define INSERTED MSINSERTED +#else +#define INSERTED8 LSINSERTED8 +#define INSERTED16 LSINSERTED16 +#define INSERTED32 LSINSERTED32 +#define INSERTED64 LSINSERTED64 +#define INSERTED LSINSERTED +#endif + + + +/* MOVE bits from one loc to another (combination of extract/insert) */ + +#define MOVED8(VAL,OH,OL,NH,NL) INSERTED8 (EXTRACTED8 ((VAL), OH, OL), NH, NL) +#define MOVED16(VAL,OH,OL,NH,NL) INSERTED16(EXTRACTED16((VAL), OH, OL), NH, NL) +#define MOVED32(VAL,OH,OL,NH,NL) INSERTED32(EXTRACTED32((VAL), OH, OL), NH, NL) +#define MOVED64(VAL,OH,OL,NH,NL) INSERTED64(EXTRACTED64((VAL), OH, OL), NH, NL) +#define MOVED(VAL,OH,OL,NH,NL) INSERTED (EXTRACTED ((VAL), OH, OL), NH, NL) + + + +/* Sign extend the quantity to the targets natural word size */ + +#define EXTEND4(X) (LSSEXT ((X), 3)) +#define EXTEND5(X) (LSSEXT ((X), 4)) +#define EXTEND8(X) ((signed_word)(signed8)(X)) +#define EXTEND11(X) (LSSEXT ((X), 10)) +#define EXTEND15(X) (LSSEXT ((X), 14)) +#define EXTEND16(X) ((signed_word)(signed16)(X)) +#define EXTEND24(X) (LSSEXT ((X), 23)) +#define EXTEND32(X) ((signed_word)(signed32)(X)) +#define EXTEND64(X) ((signed_word)(signed64)(X)) + +/* depending on MODE return a 64bit or 32bit (sign extended) value */ +#if (WITH_TARGET_WORD_BITSIZE == 64) +#define EXTENDED(X) ((signed64)(signed32)(X)) +#endif +#if (WITH_TARGET_WORD_BITSIZE == 32) +#define EXTENDED(X) (X) +#endif + + +/* memory alignment macro's */ +#define _ALIGNa(A,X) (((X) + ((A) - 1)) & ~((A) - 1)) +#define _FLOORa(A,X) ((X) & ~((A) - 1)) + +#define ALIGN_8(X) _ALIGNa (8, X) +#define ALIGN_16(X) _ALIGNa (16, X) + +#define ALIGN_PAGE(X) _ALIGNa (0x1000, X) +#define FLOOR_PAGE(X) ((X) & ~(0x1000 - 1)) + + +/* bit bliting macro's */ +#define BLIT32(V, POS, BIT) \ +do { \ + if (BIT) \ + V |= BIT32 (POS); \ + else \ + V &= ~BIT32 (POS); \ +} while (0) +#define MBLIT32(V, LO, HI, VAL) \ +do { \ + (V) = (((V) & ~MASK32 ((LO), (HI))) \ + | INSERTED32 (VAL, LO, HI)); \ +} while (0) + + + +/* some rotate functions. The generic macro's ROT, ROTL, ROTR are + intentionally omited. */ + + +INLINE_SIM_BITS(unsigned8) ROT8 (unsigned8 val, int shift); +INLINE_SIM_BITS(unsigned16) ROT16 (unsigned16 val, int shift); +INLINE_SIM_BITS(unsigned32) ROT32 (unsigned32 val, int shift); +INLINE_SIM_BITS(unsigned64) ROT64 (unsigned64 val, int shift); + + +INLINE_SIM_BITS(unsigned8) ROTL8 (unsigned8 val, int shift); +INLINE_SIM_BITS(unsigned16) ROTL16 (unsigned16 val, int shift); +INLINE_SIM_BITS(unsigned32) ROTL32 (unsigned32 val, int shift); +INLINE_SIM_BITS(unsigned64) ROTL64 (unsigned64 val, int shift); + + +INLINE_SIM_BITS(unsigned8) ROTR8 (unsigned8 val, int shift); +INLINE_SIM_BITS(unsigned16) ROTR16 (unsigned16 val, int shift); +INLINE_SIM_BITS(unsigned32) ROTR32 (unsigned32 val, int shift); +INLINE_SIM_BITS(unsigned64) ROTR64 (unsigned64 val, int shift); + + + +/* Sign extension operations */ + +INLINE_SIM_BITS(unsigned8) LSSEXT8 (signed8 val, int sign_bit); +INLINE_SIM_BITS(unsigned16) LSSEXT16 (signed16 val, int sign_bit); +INLINE_SIM_BITS(unsigned32) LSSEXT32 (signed32 val, int sign_bit); +INLINE_SIM_BITS(unsigned64) LSSEXT64 (signed64 val, int sign_bit); +INLINE_SIM_BITS(unsigned_word) LSSEXT (signed_word val, int sign_bit); + +INLINE_SIM_BITS(unsigned8) MSSEXT8 (signed8 val, int sign_bit); +INLINE_SIM_BITS(unsigned16) MSSEXT16 (signed16 val, int sign_bit); +INLINE_SIM_BITS(unsigned32) MSSEXT32 (signed32 val, int sign_bit); +INLINE_SIM_BITS(unsigned64) MSSEXT64 (signed64 val, int sign_bit); +INLINE_SIM_BITS(unsigned_word) MSSEXT (signed_word val, int sign_bit); + +#if (WITH_TARGET_WORD_MSB == 0) +#define SEXT8 MSSEXT8 +#define SEXT16 MSSEXT16 +#define SEXT32 MSSEXT32 +#define SEXT64 MSSEXT64 +#define SEXT MSSEXT +#else +#define SEXT8 LSSEXT8 +#define SEXT16 LSSEXT16 +#define SEXT32 LSSEXT32 +#define SEXT64 LSSEXT64 +#define SEXT LSSEXT +#endif + + + +#if H_REVEALS_MODULE_P (SIM_BITS_INLINE) +#include "sim-bits.c" +#endif + +#endif /* _SIM_BITS_H_ */ diff --git a/sim/common/sim-break.c b/sim/common/sim-break.c new file mode 100644 index 0000000..3b89560 --- /dev/null +++ b/sim/common/sim-break.c @@ -0,0 +1,278 @@ +/* Simulator breakpoint support. + Copyright (C) 1997 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <stdio.h> + +#include "sim-main.h" +#include "sim-assert.h" +#include "sim-break.h" + +#ifndef SIM_BREAKPOINT +#define SIM_BREAKPOINT {0x00} +#define SIM_BREAKPOINT_SIZE (1) +#endif + +struct +sim_breakpoint +{ + struct sim_breakpoint *next; + SIM_ADDR addr; /* Address of this breakpoint */ + int flags; + unsigned char loc_contents[SIM_BREAKPOINT_SIZE]; /* Contents of addr while + BP is enabled */ +}; + +#define SIM_BREAK_INSERTED 0x1 /* Breakpoint has been inserted */ +#define SIM_BREAK_DISABLED 0x2 /* Breakpoint is disabled */ + +static unsigned char sim_breakpoint [] = SIM_BREAKPOINT; + +static void insert_breakpoint PARAMS ((SIM_DESC sd, + struct sim_breakpoint *bp)); +static void remove_breakpoint PARAMS ((SIM_DESC sd, + struct sim_breakpoint *bp)); +static SIM_RC resume_handler PARAMS ((SIM_DESC sd)); +static SIM_RC suspend_handler PARAMS ((SIM_DESC sd)); + + +/* Do the actual work of inserting a breakpoint into the instruction + stream. */ + +static void +insert_breakpoint (sd, bp) + SIM_DESC sd; + struct sim_breakpoint *bp; +{ + if (bp->flags & (SIM_BREAK_INSERTED | SIM_BREAK_DISABLED)) + return; + + sim_core_read_buffer (sd, NULL, exec_map, bp->loc_contents, + bp->addr, SIM_BREAKPOINT_SIZE); + sim_core_write_buffer (sd, NULL, exec_map, sim_breakpoint, + bp->addr, SIM_BREAKPOINT_SIZE); + bp->flags |= SIM_BREAK_INSERTED; +} + +/* Do the actual work of removing a breakpoint. */ + +static void +remove_breakpoint (sd, bp) + SIM_DESC sd; + struct sim_breakpoint *bp; +{ + if (!(bp->flags & SIM_BREAK_INSERTED)) + return; + + sim_core_write_buffer (sd, NULL, exec_map, bp->loc_contents, + bp->addr, SIM_BREAKPOINT_SIZE); + bp->flags &= ~SIM_BREAK_INSERTED; +} + +/* Come here when a breakpoint insn is hit. If it's really a breakpoint, we + halt things, and never return. If it's a false hit, we return to let the + caller handle things. */ + +void +sim_handle_breakpoint (sd, cpu, cia) + SIM_DESC sd; + sim_cpu *cpu; + sim_cia cia; +{ + struct sim_breakpoint *bp; + + for (bp = STATE_BREAKPOINTS (sd); bp; bp = bp->next) + if (bp->addr == CIA_ADDR (cia)) + break; + + if (!bp || !(bp->flags & SIM_BREAK_INSERTED)) + return; + + sim_engine_halt (sd, STATE_CPU (sd, 0), NULL, cia, sim_stopped, SIM_SIGTRAP); +} + +/* Handler functions for simulator resume and suspend events. */ + +static SIM_RC +resume_handler (sd) + SIM_DESC sd; +{ + struct sim_breakpoint *bp; + + for (bp = STATE_BREAKPOINTS (sd); bp; bp = bp->next) + insert_breakpoint (sd, bp); + + return SIM_RC_OK; +} + +static SIM_RC +suspend_handler (sd) + SIM_DESC sd; +{ + struct sim_breakpoint *bp; + + for (bp = STATE_BREAKPOINTS (sd); bp; bp = bp->next) + remove_breakpoint (sd, bp); + + return SIM_RC_OK; +} + +/* Called from simulator module initialization. */ + +SIM_RC +sim_break_install (sd) + SIM_DESC sd; +{ + sim_module_add_resume_fn (sd, resume_handler); + sim_module_add_suspend_fn (sd, suspend_handler); + + return SIM_RC_OK; +} + +/* Install a breakpoint. This is a user-function. The breakpoint isn't + actually installed here. We just record it. Resume_handler does the + actual work. +*/ + +SIM_RC +sim_set_breakpoint (sd, addr) + SIM_DESC sd; + SIM_ADDR addr; +{ + struct sim_breakpoint *bp; + + for (bp = STATE_BREAKPOINTS (sd); bp; bp = bp->next) + if (bp->addr == addr) + return SIM_RC_DUPLICATE_BREAKPOINT; /* Already there */ + else + break; /* FIXME: why not scan all bp's? */ + + bp = ZALLOC (struct sim_breakpoint); + + bp->addr = addr; + bp->next = STATE_BREAKPOINTS (sd); + bp->flags = 0; + STATE_BREAKPOINTS (sd) = bp; + + return SIM_RC_OK; +} + +/* Delete a breakpoint. All knowlege of the breakpoint is removed from the + simulator. +*/ + +SIM_RC +sim_clear_breakpoint (sd, addr) + SIM_DESC sd; + SIM_ADDR addr; +{ + struct sim_breakpoint *bp, *bpprev; + + for (bp = STATE_BREAKPOINTS (sd), bpprev = NULL; + bp; + bpprev = bp, bp = bp->next) + if (bp->addr == addr) + break; + + if (!bp) + return SIM_RC_UNKNOWN_BREAKPOINT; + + remove_breakpoint (sd, bp); + + if (bpprev) + bpprev->next = bp->next; + else + STATE_BREAKPOINTS (sd) = NULL; + + zfree (bp); + + return SIM_RC_OK; +} + +SIM_RC +sim_clear_all_breakpoints (sd) + SIM_DESC sd; +{ + while (STATE_BREAKPOINTS (sd)) + sim_clear_breakpoint (sd, STATE_BREAKPOINTS (sd)->addr); + + return SIM_RC_OK; +} + +SIM_RC +sim_enable_breakpoint (sd, addr) + SIM_DESC sd; + SIM_ADDR addr; +{ + struct sim_breakpoint *bp; + + for (bp = STATE_BREAKPOINTS (sd); bp; bp = bp->next) + if (bp->addr == addr) + break; + + if (!bp) + return SIM_RC_UNKNOWN_BREAKPOINT; + + bp->flags &= ~SIM_BREAK_DISABLED; + + return SIM_RC_OK; +} + +SIM_RC +sim_disable_breakpoint (sd, addr) + SIM_DESC sd; + SIM_ADDR addr; +{ + struct sim_breakpoint *bp; + + for (bp = STATE_BREAKPOINTS (sd); bp; bp = bp->next) + if (bp->addr == addr) + break; + + if (!bp) + return SIM_RC_UNKNOWN_BREAKPOINT; + + bp->flags |= SIM_BREAK_DISABLED; + + return SIM_RC_OK; +} + +SIM_RC +sim_enable_all_breakpoints (sd) + SIM_DESC sd; +{ + struct sim_breakpoint *bp; + + for (bp = STATE_BREAKPOINTS (sd); bp; bp = bp->next) + bp->flags &= ~SIM_BREAK_DISABLED; + + return SIM_RC_OK; +} + +SIM_RC +sim_disable_all_breakpoints (sd) + SIM_DESC sd; +{ + struct sim_breakpoint *bp; + + for (bp = STATE_BREAKPOINTS (sd); bp; bp = bp->next) + bp->flags |= SIM_BREAK_DISABLED; + + return SIM_RC_OK; +} diff --git a/sim/common/sim-break.h b/sim/common/sim-break.h new file mode 100644 index 0000000..8b0338f --- /dev/null +++ b/sim/common/sim-break.h @@ -0,0 +1,38 @@ +/* Simulator breakpoint support. + Copyright (C) 1997 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +#ifndef SIM_BREAK_H +#define SIM_BREAK_H + +/* Call this to install the resume and suspend handlers for the breakpoint + module. */ + +MODULE_INSTALL_FN sim_break_install; + +/* Call this inside the simulator when we execute the potential + breakpoint insn. If the breakpoint system knows about it, the + breakpoint is handled, and this routine never returns. If this + isn't really a breakpoint, then it returns to allow the caller to + handle things. */ + +void sim_handle_breakpoint PARAMS ((SIM_DESC sd, sim_cpu *cpu, sim_cia cia)); + +#endif /* SIM_BREAK_H */ diff --git a/sim/common/sim-config.c b/sim/common/sim-config.c new file mode 100644 index 0000000..10a19aa --- /dev/null +++ b/sim/common/sim-config.c @@ -0,0 +1,377 @@ +/* This file is part of the GNU simulators. + + Copyright (C) 1994-1995,1997, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#include "sim-main.h" +#include "sim-assert.h" +#include "bfd.h" + + +int current_host_byte_order; +int current_target_byte_order; +int current_stdio; + +enum sim_alignments current_alignment; + +#if defined (WITH_FLOATING_POINT) +int current_floating_point; +#endif + + + +/* map a byte order onto a textual string */ + +static const char * +config_byte_order_to_a (int byte_order) +{ + switch (byte_order) + { + case LITTLE_ENDIAN: + return "LITTLE_ENDIAN"; + case BIG_ENDIAN: + return "BIG_ENDIAN"; + case 0: + return "0"; + } + return "UNKNOWN"; +} + + +static const char * +config_stdio_to_a (int stdio) +{ + switch (stdio) + { + case DONT_USE_STDIO: + return "DONT_USE_STDIO"; + case DO_USE_STDIO: + return "DO_USE_STDIO"; + case 0: + return "0"; + } + return "UNKNOWN"; +} + + +static const char * +config_environment_to_a (enum sim_environment environment) +{ + switch (environment) + { + case ALL_ENVIRONMENT: + return "ALL_ENVIRONMENT"; + case USER_ENVIRONMENT: + return "USER_ENVIRONMENT"; + case VIRTUAL_ENVIRONMENT: + return "VIRTUAL_ENVIRONMENT"; + case OPERATING_ENVIRONMENT: + return "OPERATING_ENVIRONMENT"; + } + return "UNKNOWN"; +} + + +static const char * +config_alignment_to_a (enum sim_alignments alignment) +{ + switch (alignment) + { + case MIXED_ALIGNMENT: + return "MIXED_ALIGNMENT"; + case NONSTRICT_ALIGNMENT: + return "NONSTRICT_ALIGNMENT"; + case STRICT_ALIGNMENT: + return "STRICT_ALIGNMENT"; + case FORCED_ALIGNMENT: + return "FORCED_ALIGNMENT"; + } + return "UNKNOWN"; +} + + +#if defined (WITH_FLOATING_POINT) +static const char * +config_floating_point_to_a (int floating_point) +{ + switch (floating_point) + { + case SOFT_FLOATING_POINT: + return "SOFT_FLOATING_POINT"; + case HARD_FLOATING_POINT: + return "HARD_FLOATING_POINT"; + case 0: + return "0"; + } + return "UNKNOWN"; +} +#endif + +/* Set the default environment, prior to parsing argv. */ + +void +sim_config_default (SIM_DESC sd) +{ + /* Set the current environment to ALL_ENVIRONMENT to indicate none has been + selected yet. This is so that after parsing argv, we know whether the + environment was explicitly specified or not. */ + STATE_ENVIRONMENT (sd) = ALL_ENVIRONMENT; +} + +/* Complete and verify the simulation environment. */ + +SIM_RC +sim_config (SIM_DESC sd) +{ + int prefered_target_byte_order; + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + + /* extract all relevant information */ + if (STATE_PROG_BFD (sd) == NULL) + prefered_target_byte_order = 0; + else + prefered_target_byte_order = (bfd_little_endian(STATE_PROG_BFD (sd)) + ? LITTLE_ENDIAN + : BIG_ENDIAN); + + /* set the host byte order */ + current_host_byte_order = 1; + if (*(char*)(¤t_host_byte_order)) + current_host_byte_order = LITTLE_ENDIAN; + else + current_host_byte_order = BIG_ENDIAN; + + /* verify the host byte order */ + if (CURRENT_HOST_BYTE_ORDER != current_host_byte_order) + { + sim_io_eprintf (sd, "host (%s) and configured (%s) byte order in conflict", + config_byte_order_to_a (current_host_byte_order), + config_byte_order_to_a (CURRENT_HOST_BYTE_ORDER)); + return SIM_RC_FAIL; + } + + + /* set the target byte order */ +#if (WITH_TREE_PROPERTIES) + if (current_target_byte_order == 0) + current_target_byte_order + = (tree_find_boolean_property (root, "/options/little-endian?") + ? LITTLE_ENDIAN + : BIG_ENDIAN); +#endif + if (current_target_byte_order == 0 + && prefered_target_byte_order != 0) + current_target_byte_order = prefered_target_byte_order; + if (current_target_byte_order == 0) + current_target_byte_order = WITH_TARGET_BYTE_ORDER; + if (current_target_byte_order == 0) + current_target_byte_order = WITH_DEFAULT_TARGET_BYTE_ORDER; + + /* verify the target byte order */ + if (CURRENT_TARGET_BYTE_ORDER == 0) + { + sim_io_eprintf (sd, "Target byte order unspecified\n"); + return SIM_RC_FAIL; + } + if (CURRENT_TARGET_BYTE_ORDER != current_target_byte_order) + sim_io_eprintf (sd, "Target (%s) and configured (%s) byte order in conflict\n", + config_byte_order_to_a (current_target_byte_order), + config_byte_order_to_a (CURRENT_TARGET_BYTE_ORDER)); + if (prefered_target_byte_order != 0 + && CURRENT_TARGET_BYTE_ORDER != prefered_target_byte_order) + sim_io_eprintf (sd, "Target (%s) and specified (%s) byte order in conflict\n", + config_byte_order_to_a (CURRENT_TARGET_BYTE_ORDER), + config_byte_order_to_a (prefered_target_byte_order)); + + + /* set the stdio */ + if (current_stdio == 0) + current_stdio = WITH_STDIO; + if (current_stdio == 0) + current_stdio = DO_USE_STDIO; + + /* verify the stdio */ + if (CURRENT_STDIO == 0) + { + sim_io_eprintf (sd, "Target standard IO unspecified\n"); + return SIM_RC_FAIL; + } + if (CURRENT_STDIO != current_stdio) + { + sim_io_eprintf (sd, "Target (%s) and configured (%s) standard IO in conflict\n", + config_stdio_to_a (CURRENT_STDIO), + config_stdio_to_a (current_stdio)); + return SIM_RC_FAIL; + } + + + /* check the value of MSB */ + if (WITH_TARGET_WORD_MSB != 0 + && WITH_TARGET_WORD_MSB != (WITH_TARGET_WORD_BITSIZE - 1)) + { + sim_io_eprintf (sd, "Target bitsize (%d) contradicts target most significant bit (%d)\n", + WITH_TARGET_WORD_BITSIZE, WITH_TARGET_WORD_MSB); + return SIM_RC_FAIL; + } + + + /* set the environment */ +#if (WITH_TREE_PROPERTIES) + if (STATE_ENVIRONMENT (sd) == ALL_ENVIRONMENT) + { + const char *env = + tree_find_string_property(root, "/openprom/options/env"); + STATE_ENVIRONMENT (sd) = ((strcmp(env, "user") == 0 + || strcmp(env, "uea") == 0) + ? USER_ENVIRONMENT + : (strcmp(env, "virtual") == 0 + || strcmp(env, "vea") == 0) + ? VIRTUAL_ENVIRONMENT + : (strcmp(env, "operating") == 0 + || strcmp(env, "oea") == 0) + ? OPERATING_ENVIRONMENT + : ALL_ENVIRONMENT); + } +#endif + if (STATE_ENVIRONMENT (sd) == ALL_ENVIRONMENT) + STATE_ENVIRONMENT (sd) = DEFAULT_ENVIRONMENT; + + + /* set the alignment */ +#if (WITH_TREE_PROPERTIES) + if (current_alignment == 0) + current_alignment = + (tree_find_boolean_property(root, "/openprom/options/strict-alignment?") + ? STRICT_ALIGNMENT + : NONSTRICT_ALIGNMENT); +#endif + if (current_alignment == 0) + current_alignment = WITH_ALIGNMENT; + if (current_alignment == 0) + current_alignment = WITH_DEFAULT_ALIGNMENT; + + /* verify the alignment */ + if (CURRENT_ALIGNMENT == 0) + { + sim_io_eprintf (sd, "Target alignment unspecified\n"); + return SIM_RC_FAIL; + } + if (CURRENT_ALIGNMENT != current_alignment) + { + sim_io_eprintf (sd, "Target (%s) and configured (%s) alignment in conflict\n", + config_alignment_to_a (CURRENT_ALIGNMENT), + config_alignment_to_a (current_alignment)); + return SIM_RC_FAIL; + } + +#if defined (WITH_FLOATING_POINT) + + /* set the floating point */ + if (current_floating_point == 0) + current_floating_point = WITH_FLOATING_POINT; + + /* verify the floating point */ + if (CURRENT_FLOATING_POINT == 0) + { + sim_io_eprintf (sd, "Target floating-point unspecified\n"); + return SIM_RC_FAIL; + } + if (CURRENT_FLOATING_POINT != current_floating_point) + { + sim_io_eprintf (sd, "Target (%s) and configured (%s) floating-point in conflict\n", + config_alignment_to_a (CURRENT_FLOATING_POINT), + config_alignment_to_a (current_floating_point)); + return SIM_RC_FAIL; + } + +#endif + return SIM_RC_OK; +} + + +void +print_sim_config (SIM_DESC sd) +{ +#if defined (__GNUC__) && defined (__VERSION__) + sim_io_printf (sd, "Compiled by GCC %s on %s %s\n", + __VERSION__, __DATE__, __TIME__); +#else + sim_io_printf (sd, "Compiled on %s %s\n", __DATE__, __TIME__); +#endif + + sim_io_printf (sd, "WITH_TARGET_BYTE_ORDER = %s\n", + config_byte_order_to_a (WITH_TARGET_BYTE_ORDER)); + + sim_io_printf (sd, "WITH_DEFAULT_TARGET_BYTE_ORDER = %s\n", + config_byte_order_to_a (WITH_DEFAULT_TARGET_BYTE_ORDER)); + + sim_io_printf (sd, "WITH_HOST_BYTE_ORDER = %s\n", + config_byte_order_to_a (WITH_HOST_BYTE_ORDER)); + + sim_io_printf (sd, "WITH_STDIO = %s\n", + config_stdio_to_a (WITH_STDIO)); + + sim_io_printf (sd, "WITH_TARGET_WORD_MSB = %d\n", + WITH_TARGET_WORD_MSB); + + sim_io_printf (sd, "WITH_TARGET_WORD_BITSIZE = %d\n", + WITH_TARGET_WORD_BITSIZE); + + sim_io_printf (sd, "WITH_TARGET_ADDRESS_BITSIZE = %d\n", + WITH_TARGET_ADDRESS_BITSIZE); + + sim_io_printf (sd, "WITH_TARGET_CELL_BITSIZE = %d\n", + WITH_TARGET_CELL_BITSIZE); + + sim_io_printf (sd, "WITH_TARGET_FLOATING_POINT_BITSIZE = %d\n", + WITH_TARGET_FLOATING_POINT_BITSIZE); + + sim_io_printf (sd, "WITH_ENVIRONMENT = %s\n", + config_environment_to_a (WITH_ENVIRONMENT)); + + sim_io_printf (sd, "WITH_ALIGNMENT = %s\n", + config_alignment_to_a (WITH_ALIGNMENT)); + +#if defined (WITH_DEFAULT_ALIGNMENT) + sim_io_printf (sd, "WITH_DEFAULT_ALIGNMENT = %s\n", + config_alignment_to_a (WITH_DEFAULT_ALIGNMENT)); +#endif + +#if defined (WITH_XOR_ENDIAN) + sim_io_printf (sd, "WITH_XOR_ENDIAN = %d\n", WITH_XOR_ENDIAN); +#endif + +#if defined (WITH_FLOATING_POINT) + sim_io_printf (sd, "WITH_FLOATING_POINT = %s\n", + config_floating_point_to_a (WITH_FLOATING_POINT)); +#endif + +#if defined (WITH_SMP) + sim_io_printf (sd, "WITH_SMP = %d\n", WITH_SMP); +#endif + +#if defined (WITH_RESERVED_BITS) + sim_io_printf (sd, "WITH_RESERVED_BITS = %d\n", WITH_RESERVED_BITS); +#endif + +#if defined (WITH_PROFILE) + sim_io_printf (sd, "WITH_PROFILE = %d\n", WITH_PROFILE); +#endif + +} diff --git a/sim/common/sim-config.h b/sim/common/sim-config.h new file mode 100644 index 0000000..9720712 --- /dev/null +++ b/sim/common/sim-config.h @@ -0,0 +1,594 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef SIM_CONFIG_H +#define SIM_CONFIG_H + + +/* Host dependant: + + The CPP below defines information about the compilation host. In + particular it defines the macro's: + + WITH_HOST_BYTE_ORDER The byte order of the host. Could + be any of LITTLE_ENDIAN, BIG_ENDIAN + or 0 (unknown). Those macro's also + need to be defined. + + */ + + +/* NetBSD: + + NetBSD is easy, everything you could ever want is in a header file + (well almost :-) */ + +#if defined(__NetBSD__) +# include <machine/endian.h> +# if (WITH_HOST_BYTE_ORDER == 0) +# undef WITH_HOST_BYTE_ORDER +# define WITH_HOST_BYTE_ORDER BYTE_ORDER +# endif +# if (BYTE_ORDER != WITH_HOST_BYTE_ORDER) +# error "host endian incorrectly configured, check config.h" +# endif +#endif + +/* Linux is similarly easy. */ + +#if defined(__linux__) +# include <endian.h> +# if defined(__LITTLE_ENDIAN) && !defined(LITTLE_ENDIAN) +# define LITTLE_ENDIAN __LITTLE_ENDIAN +# endif +# if defined(__BIG_ENDIAN) && !defined(BIG_ENDIAN) +# define BIG_ENDIAN __BIG_ENDIAN +# endif +# if defined(__BYTE_ORDER) && !defined(BYTE_ORDER) +# define BYTE_ORDER __BYTE_ORDER +# endif +# if (WITH_HOST_BYTE_ORDER == 0) +# undef WITH_HOST_BYTE_ORDER +# define WITH_HOST_BYTE_ORDER BYTE_ORDER +# endif +# if (BYTE_ORDER != WITH_HOST_BYTE_ORDER) +# error "host endian incorrectly configured, check config.h" +# endif +#endif + +/* INSERT HERE - hosts that have available LITTLE_ENDIAN and + BIG_ENDIAN macro's */ + + +/* Some hosts don't define LITTLE_ENDIAN or BIG_ENDIAN, help them out */ + +#ifndef LITTLE_ENDIAN +#define LITTLE_ENDIAN 1234 +#endif +#ifndef BIG_ENDIAN +#define BIG_ENDIAN 4321 +#endif + + +/* SunOS on SPARC: + + Big endian last time I looked */ + +#if defined(sparc) || defined(__sparc__) +# if (WITH_HOST_BYTE_ORDER == 0) +# undef WITH_HOST_BYTE_ORDER +# define WITH_HOST_BYTE_ORDER BIG_ENDIAN +# endif +# if (WITH_HOST_BYTE_ORDER != BIG_ENDIAN) +# error "sun was big endian last time I looked ..." +# endif +#endif + + +/* Random x86 + + Little endian last time I looked */ + +#if defined(i386) || defined(i486) || defined(i586) || defined (i686) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined (__i686__) +# if (WITH_HOST_BYTE_ORDER == 0) +# undef WITH_HOST_BYTE_ORDER +# define WITH_HOST_BYTE_ORDER LITTLE_ENDIAN +# endif +# if (WITH_HOST_BYTE_ORDER != LITTLE_ENDIAN) +# error "x86 was little endian last time I looked ..." +# endif +#endif + +#if (defined (__i486__) || defined (__i586__) || defined (__i686__)) && defined(__GNUC__) && WITH_BSWAP +#undef htonl +#undef ntohl +#define htonl(IN) __extension__ ({ int _out; __asm__ ("bswap %0" : "=r" (_out) : "0" (IN)); _out; }) +#define ntohl(IN) __extension__ ({ int _out; __asm__ ("bswap %0" : "=r" (_out) : "0" (IN)); _out; }) +#endif + +/* Power or PowerPC running AIX */ +#if defined(_POWER) && defined(_AIX) +# if (WITH_HOST_BYTE_ORDER == 0) +# undef WITH_HOST_BYTE_ORDER +# define WITH_HOST_BYTE_ORDER BIG_ENDIAN +# endif +# if (WITH_HOST_BYTE_ORDER != BIG_ENDIAN) +# error "Power/PowerPC AIX was big endian last time I looked ..." +# endif +#endif + +/* Solaris running PowerPC */ +#if defined(__PPC) && defined(__sun__) +# if (WITH_HOST_BYTE_ORDER == 0) +# undef WITH_HOST_BYTE_ORDER +# define WITH_HOST_BYTE_ORDER LITTLE_ENDIAN +# endif +# if (WITH_HOST_BYTE_ORDER != LITTLE_ENDIAN) +# error "Solaris on PowerPCs was little endian last time I looked ..." +# endif +#endif + +/* HP/PA */ +#if defined(__hppa__) +# if (WITH_HOST_BYTE_ORDER == 0) +# undef WITH_HOST_BYTE_ORDER +# define WITH_HOST_BYTE_ORDER BIG_ENDIAN +# endif +# if (WITH_HOST_BYTE_ORDER != BIG_ENDIAN) +# error "HP/PA was big endian last time I looked ..." +# endif +#endif + +/* Big endian MIPS */ +#if defined(__MIPSEB__) +# if (WITH_HOST_BYTE_ORDER == 0) +# undef WITH_HOST_BYTE_ORDER +# define WITH_HOST_BYTE_ORDER BIG_ENDIAN +# endif +# if (WITH_HOST_BYTE_ORDER != BIG_ENDIAN) +# error "MIPSEB was big endian last time I looked ..." +# endif +#endif + +/* Little endian MIPS */ +#if defined(__MIPSEL__) +# if (WITH_HOST_BYTE_ORDER == 0) +# undef WITH_HOST_BYTE_ORDER +# define WITH_HOST_BYTE_ORDER LITTLE_ENDIAN +# endif +# if (WITH_HOST_BYTE_ORDER != LITTLE_ENDIAN) +# error "MIPSEL was little endian last time I looked ..." +# endif +#endif + +/* Windows NT */ +#if defined(__WIN32__) +# if (WITH_HOST_BYTE_ORDER == 0) +# undef WITH_HOST_BYTE_ORDER +# define WITH_HOST_BYTE_ORDER LITTLE_ENDIAN +# endif +# if (WITH_HOST_BYTE_ORDER != LITTLE_ENDIAN) +# error "Windows NT was little endian last time I looked ..." +# endif +#endif + +/* Alpha running DEC unix */ +#if defined(__osf__) && defined(__alpha__) +# if (WITH_HOST_BYTE_ORDER == 0) +# undef WITH_HOST_BYTE_ORDER +# define WITH_HOST_BYTE_ORDER LITTLE_ENDIAN +# endif +# if (WITH_HOST_BYTE_ORDER != LITTLE_ENDIAN) +# error "AXP running DEC unix was little endian last time I looked ..." +# endif +#endif + + +/* INSERT HERE - additional hosts that do not have LITTLE_ENDIAN and + BIG_ENDIAN definitions available. */ + +/* Until devices and tree properties are sorted out, tell sim-config.c + not to call the tree_find_foo fns. */ +#define WITH_TREE_PROPERTIES 0 + + +/* endianness of the host/target: + + If the build process is aware (at compile time) of the endianness + of the host/target it is able to eliminate slower generic endian + handling code. + + Possible values are 0 (unknown), LITTLE_ENDIAN, BIG_ENDIAN */ + +#ifndef WITH_HOST_BYTE_ORDER +#define WITH_HOST_BYTE_ORDER 0 /*unknown*/ +#endif + +#ifndef WITH_TARGET_BYTE_ORDER +#define WITH_TARGET_BYTE_ORDER 0 /*unknown*/ +#endif + +#ifndef WITH_DEFAULT_TARGET_BYTE_ORDER +#define WITH_DEFAULT_TARGET_BYTE_ORDER 0 /* fatal */ +#endif + +extern int current_host_byte_order; +#define CURRENT_HOST_BYTE_ORDER (WITH_HOST_BYTE_ORDER \ + ? WITH_HOST_BYTE_ORDER \ + : current_host_byte_order) +extern int current_target_byte_order; +#define CURRENT_TARGET_BYTE_ORDER (WITH_TARGET_BYTE_ORDER \ + ? WITH_TARGET_BYTE_ORDER \ + : current_target_byte_order) + + + +/* XOR endian. + + In addition to the above, the simulator can support the horrible + XOR endian mode (as found in the PowerPC and MIPS ISA). See + sim-core for more information. + + If WITH_XOR_ENDIAN is non-zero, it specifies the number of bytes + potentially involved in the XOR munge. A typical value is 8. */ + +#ifndef WITH_XOR_ENDIAN +#define WITH_XOR_ENDIAN 0 +#endif + + + +/* Intel host BSWAP support: + + Whether to use bswap on the 486 and pentiums rather than the 386 + sequence that uses xchgb/rorl/xchgb */ +#ifndef WITH_BSWAP +#define WITH_BSWAP 0 +#endif + + + +/* SMP support: + + Sets a limit on the number of processors that can be simulated. If + WITH_SMP is set to zero (0), the simulator is restricted to + suporting only one processor (and as a consequence leaves the SMP + code out of the build process). + + The actual number of processors is taken from the device + /options/smp@<nr-cpu> */ + +#if defined (WITH_SMP) && (WITH_SMP > 0) +#define MAX_NR_PROCESSORS WITH_SMP +#endif + +#ifndef MAX_NR_PROCESSORS +#define MAX_NR_PROCESSORS 1 +#endif + + +/* Size of target word, address and OpenFirmware Cell: + + The target word size is determined by the natural size of its + reginsters. + + On most hosts, the address and cell are the same size as a target + word. */ + +#ifndef WITH_TARGET_WORD_BITSIZE +#define WITH_TARGET_WORD_BITSIZE 32 +#endif + +#ifndef WITH_TARGET_ADDRESS_BITSIZE +#define WITH_TARGET_ADDRESS_BITSIZE WITH_TARGET_WORD_BITSIZE +#endif + +#ifndef WITH_TARGET_CELL_BITSIZE +#define WITH_TARGET_CELL_BITSIZE WITH_TARGET_WORD_BITSIZE +#endif + +#ifndef WITH_TARGET_FLOATING_POINT_BITSIZE +#define WITH_TARGET_FLOATING_POINT_BITSIZE 64 +#endif + + + +/* Most significant bit of target: + + Set this according to your target's bit numbering convention. For + the PowerPC it is zero, for many other targets it is 31 or 63. + + For targets that can both have either 32 or 64 bit words and number + MSB as 31, 63. Define this to be (WITH_TARGET_WORD_BITSIZE - 1) */ + +#ifndef WITH_TARGET_WORD_MSB +#define WITH_TARGET_WORD_MSB 0 +#endif + + + +/* Program environment: + + Three environments are available - UEA (user), VEA (virtual) and + OEA (perating). The former two are environment that users would + expect to see (VEA includes things like coherency and the time + base) while OEA is what an operating system expects to see. By + setting these to specific values, the build process is able to + eliminate non relevent environment code. + + STATE_ENVIRONMENT(sd) specifies which of vea or oea is required for + the current runtime. + + ALL_ENVIRONMENT is used during configuration as a value for + WITH_ENVIRONMENT to indicate the choice is runtime selectable. + The default is then USER_ENVIRONMENT [since allowing the user to choose + the default at configure time seems like featuritis and since people using + OPERATING_ENVIRONMENT have more to worry about than selecting the + default]. + ALL_ENVIRONMENT is also used to set STATE_ENVIRONMENT to the + "uninitialized" state. */ + +enum sim_environment { + ALL_ENVIRONMENT, + USER_ENVIRONMENT, + VIRTUAL_ENVIRONMENT, + OPERATING_ENVIRONMENT +}; + +/* If the simulator specified SIM_AC_OPTION_ENVIRONMENT, indicate so. */ +#ifdef WITH_ENVIRONMENT +#define SIM_HAVE_ENVIRONMENT +#endif + +/* If the simulator doesn't specify SIM_AC_OPTION_ENVIRONMENT in its + configure.in, the only supported environment is the user environment. */ +#ifndef WITH_ENVIRONMENT +#define WITH_ENVIRONMENT USER_ENVIRONMENT +#endif + +#define DEFAULT_ENVIRONMENT (WITH_ENVIRONMENT != ALL_ENVIRONMENT \ + ? WITH_ENVIRONMENT \ + : USER_ENVIRONMENT) + + +/* Callback & Modulo Memory. + + Core includes a builtin memory type (raw_memory) that is + implemented using an array. raw_memory does not require any + additional functions etc. + + Callback memory is where the core calls a core device for the data + it requires. Callback memory can be layered using priorities. + + Modulo memory is a variation on raw_memory where ADDRESS & (MODULO + - 1) is used as the index into the memory array. + + The OEA model uses callback memory for devices. + + The VEA model uses callback memory to capture `page faults'. + + BTW, while raw_memory could have been implemented as a callback, + profiling has shown that there is a biger win (at least for the + x86) in eliminating a function call for the most common + (raw_memory) case. */ + +#ifndef WITH_CALLBACK_MEMORY +#define WITH_CALLBACK_MEMORY 1 +#endif + +#ifndef WITH_MODULO_MEMORY +#define WITH_MODULO_MEMORY 0 +#endif + + + +/* Alignment: + + A processor architecture may or may not handle miss aligned + transfers. + + As alternatives: both little and big endian modes take an exception + (STRICT_ALIGNMENT); big and little endian models handle mis aligned + transfers (NONSTRICT_ALIGNMENT); or the address is forced into + alignment using a mask (FORCED_ALIGNMENT). + + Mixed alignment should be specified when the simulator needs to be + able to change the alignment requirements on the fly (eg for + bi-endian support). */ + +enum sim_alignments { + MIXED_ALIGNMENT, + NONSTRICT_ALIGNMENT, + STRICT_ALIGNMENT, + FORCED_ALIGNMENT, +}; + +extern enum sim_alignments current_alignment; + +#if !defined (WITH_ALIGNMENT) +#define WITH_ALIGNMENT 0 +#endif + +#if !defined (WITH_DEFAULT_ALIGNMENT) +#define WITH_DEFAULT_ALIGNMENT 0 /* fatal */ +#endif + + + + +#define CURRENT_ALIGNMENT (WITH_ALIGNMENT \ + ? WITH_ALIGNMENT \ + : current_alignment) + + + +/* Floating point suport: + + Should the processor trap for all floating point instructions (as + if the hardware wasn't implemented) or implement the floating point + instructions directly. */ + +#if defined (WITH_FLOATING_POINT) + +#define SOFT_FLOATING_POINT 1 +#define HARD_FLOATING_POINT 2 + +extern int current_floating_point; +#define CURRENT_FLOATING_POINT (WITH_FLOATING_POINT \ + ? WITH_FLOATING_POINT \ + : current_floating_point) + +#endif + + + +/* Engine module. + + Use the common start/stop/restart framework (sim-engine). + Simulators using the other modules but not the engine should define + WITH_ENGINE=0. */ + +#ifndef WITH_ENGINE +#define WITH_ENGINE 1 +#endif + + + +/* Debugging: + + Control the inclusion of debugging code. + Debugging is only turned on in rare circumstances [say during development] + and is not intended to be turned on otherwise. */ + +#ifndef WITH_DEBUG +#define WITH_DEBUG 0 +#endif + +/* Include the tracing code. Disabling this eliminates all tracing + code */ + +#ifndef WITH_TRACE +#define WITH_TRACE (-1) +#endif + +/* Include the profiling code. Disabling this eliminates all profiling + code. */ + +#ifndef WITH_PROFILE +#define WITH_PROFILE (-1) +#endif + + +/* include code that checks assertions scattered through out the + program */ + +#ifndef WITH_ASSERT +#define WITH_ASSERT 1 +#endif + + +/* Whether to check instructions for reserved bits being set */ + +/* #define WITH_RESERVED_BITS 1 */ + + + +/* include monitoring code */ + +#define MONITOR_INSTRUCTION_ISSUE 1 +#define MONITOR_LOAD_STORE_UNIT 2 +/* do not define WITH_MON by default */ +#define DEFAULT_WITH_MON (MONITOR_LOAD_STORE_UNIT \ + | MONITOR_INSTRUCTION_ISSUE) + + +/* Current CPU model (models are in the generated models.h include file) */ +#ifndef WITH_MODEL +#define WITH_MODEL 0 +#endif + +#define CURRENT_MODEL (WITH_MODEL \ + ? WITH_MODEL \ + : current_model) + +#ifndef WITH_DEFAULT_MODEL +#define WITH_DEFAULT_MODEL DEFAULT_MODEL +#endif + +#define MODEL_ISSUE_IGNORE (-1) +#define MODEL_ISSUE_PROCESS 1 + +#ifndef WITH_MODEL_ISSUE +#define WITH_MODEL_ISSUE 0 +#endif + +extern int current_model_issue; +#define CURRENT_MODEL_ISSUE (WITH_MODEL_ISSUE \ + ? WITH_MODEL_ISSUE \ + : current_model_issue) + + + +/* Whether or not input/output just uses stdio, or uses printf_filtered for + output, and polling input for input. */ + +#define DONT_USE_STDIO 2 +#define DO_USE_STDIO 1 + +#ifndef WITH_STDIO +#define WITH_STDIO 0 +#endif + +extern int current_stdio; +#define CURRENT_STDIO (WITH_STDIO \ + ? WITH_STDIO \ + : current_stdio) + + + +/* Specify that configured calls pass parameters in registers when the + convention is that they are placed on the stack */ + +#ifndef WITH_REGPARM +#define WITH_REGPARM 0 +#endif + +/* Specify that configured calls use an alternative calling mechanism */ + +#ifndef WITH_STDCALL +#define WITH_STDCALL 0 +#endif + + +/* Set the default state configuration, before parsing argv. */ + +extern void sim_config_default (SIM_DESC sd); + +/* Complete and verify the simulator configuration. */ + +extern SIM_RC sim_config (SIM_DESC sd); + +/* Print the simulator configuration. */ + +extern void print_sim_config (SIM_DESC sd); + + +#endif diff --git a/sim/common/sim-core.c b/sim/common/sim-core.c new file mode 100644 index 0000000..36627a2 --- /dev/null +++ b/sim/common/sim-core.c @@ -0,0 +1,839 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef SIM_CORE_C +#define SIM_CORE_C + +#include "sim-main.h" +#include "sim-assert.h" + +#if (WITH_HW) +#include "sim-hw.h" +#endif + +#if (WITH_DEVICES) +/* TODO: create sim/common/device.h */ +void device_error (device *me, char* message, ...); +int device_io_read_buffer(device *me, void *dest, int space, address_word addr, unsigned nr_bytes, sim_cpu *processor, sim_cia cia); +int device_io_write_buffer(device *me, const void *source, int space, address_word addr, unsigned nr_bytes, sim_cpu *processor, sim_cia cia); +#endif + +/* "core" module install handler. + + This is called via sim_module_install to install the "core" + subsystem into the simulator. */ + +#if EXTERN_SIM_CORE_P +static MODULE_INIT_FN sim_core_init; +static MODULE_UNINSTALL_FN sim_core_uninstall; +#endif + +#if EXTERN_SIM_CORE_P +SIM_RC +sim_core_install (SIM_DESC sd) +{ + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + + /* establish the other handlers */ + sim_module_add_uninstall_fn (sd, sim_core_uninstall); + sim_module_add_init_fn (sd, sim_core_init); + + /* establish any initial data structures - none */ + return SIM_RC_OK; +} +#endif + + +/* Uninstall the "core" subsystem from the simulator. */ + +#if EXTERN_SIM_CORE_P +static void +sim_core_uninstall (SIM_DESC sd) +{ + sim_core *core = STATE_CORE(sd); + unsigned map; + /* blow away any mappings */ + for (map = 0; map < nr_maps; map++) { + sim_core_mapping *curr = core->common.map[map].first; + while (curr != NULL) { + sim_core_mapping *tbd = curr; + curr = curr->next; + if (tbd->free_buffer != NULL) { + SIM_ASSERT(tbd->buffer != NULL); + zfree(tbd->free_buffer); + } + zfree(tbd); + } + core->common.map[map].first = NULL; + } +} +#endif + + +#if EXTERN_SIM_CORE_P +static SIM_RC +sim_core_init (SIM_DESC sd) +{ + /* Nothing to do */ + return SIM_RC_OK; +} +#endif + + + +#ifndef SIM_CORE_SIGNAL +#define SIM_CORE_SIGNAL(SD,CPU,CIA,MAP,NR_BYTES,ADDR,TRANSFER,ERROR) \ +sim_core_signal ((SD), (CPU), (CIA), (MAP), (NR_BYTES), (ADDR), (TRANSFER), (ERROR)) +#endif + +#if EXTERN_SIM_CORE_P +void +sim_core_signal (SIM_DESC sd, + sim_cpu *cpu, + sim_cia cia, + unsigned map, + int nr_bytes, + address_word addr, + transfer_type transfer, + sim_core_signals sig) +{ + const char *copy = (transfer == read_transfer ? "read" : "write"); + address_word ip = CIA_ADDR (cia); + switch (sig) + { + case sim_core_unmapped_signal: + sim_io_eprintf (sd, "core: %d byte %s to unmapped address 0x%lx at 0x%lx\n", + nr_bytes, copy, (unsigned long) addr, (unsigned long) ip); + sim_engine_halt (sd, cpu, NULL, cia, sim_stopped, SIM_SIGSEGV); + break; + case sim_core_unaligned_signal: + sim_io_eprintf (sd, "core: %d byte misaligned %s to address 0x%lx at 0x%lx\n", + nr_bytes, copy, (unsigned long) addr, (unsigned long) ip); + sim_engine_halt (sd, cpu, NULL, cia, sim_stopped, SIM_SIGBUS); + break; + default: + sim_engine_abort (sd, cpu, cia, + "sim_core_signal - internal error - bad switch"); + } +} +#endif + + +#if EXTERN_SIM_CORE_P +static sim_core_mapping * +new_sim_core_mapping (SIM_DESC sd, + int level, + int space, + address_word addr, + address_word nr_bytes, + unsigned modulo, +#if WITH_HW + struct hw *device, +#else + device *device, +#endif + void *buffer, + void *free_buffer) +{ + sim_core_mapping *new_mapping = ZALLOC(sim_core_mapping); + /* common */ + new_mapping->level = level; + new_mapping->space = space; + new_mapping->base = addr; + new_mapping->nr_bytes = nr_bytes; + new_mapping->bound = addr + (nr_bytes - 1); + if (modulo == 0) + new_mapping->mask = (unsigned) 0 - 1; + else + new_mapping->mask = modulo - 1; + new_mapping->buffer = buffer; + new_mapping->free_buffer = free_buffer; + new_mapping->device = device; + return new_mapping; +} +#endif + + +#if EXTERN_SIM_CORE_P +static void +sim_core_map_attach (SIM_DESC sd, + sim_core_map *access_map, + int level, + int space, + address_word addr, + address_word nr_bytes, + unsigned modulo, +#if WITH_HW + struct hw *client, /*callback/default*/ +#else + device *client, /*callback/default*/ +#endif + void *buffer, /*raw_memory*/ + void *free_buffer) /*raw_memory*/ +{ + /* find the insertion point for this additional mapping and then + insert */ + sim_core_mapping *next_mapping; + sim_core_mapping **last_mapping; + + SIM_ASSERT ((client == NULL) != (buffer == NULL)); + SIM_ASSERT ((client == NULL) >= (free_buffer != NULL)); + + /* actually do occasionally get a zero size map */ + if (nr_bytes == 0) + { +#if (WITH_DEVICES) + device_error(client, "called on sim_core_map_attach with size zero"); +#endif +#if (WITH_HW) + sim_hw_abort (sd, client, "called on sim_core_map_attach with size zero"); +#endif + sim_io_error (sd, "called on sim_core_map_attach with size zero"); + } + + /* find the insertion point (between last/next) */ + next_mapping = access_map->first; + last_mapping = &access_map->first; + while(next_mapping != NULL + && (next_mapping->level < level + || (next_mapping->level == level + && next_mapping->bound < addr))) + { + /* provided levels are the same */ + /* assert: next_mapping->base > all bases before next_mapping */ + /* assert: next_mapping->bound >= all bounds before next_mapping */ + last_mapping = &next_mapping->next; + next_mapping = next_mapping->next; + } + + /* check insertion point correct */ + SIM_ASSERT (next_mapping == NULL || next_mapping->level >= level); + if (next_mapping != NULL && next_mapping->level == level + && next_mapping->base < (addr + (nr_bytes - 1))) + { +#if (WITH_DEVICES) + device_error (client, "memory map %d:0x%lx..0x%lx (%ld bytes) overlaps %d:0x%lx..0x%lx (%ld bytes)", + space, + (long) addr, + (long) nr_bytes, + (long) (addr + (nr_bytes - 1)), + next_mapping->space, + (long) next_mapping->base, + (long) next_mapping->bound, + (long) next_mapping->nr_bytes); +#endif +#if WITH_HW + sim_hw_abort (sd, client, "memory map %d:0x%lx..0x%lx (%ld bytes) overlaps %d:0x%lx..0x%lx (%ld bytes)", + space, + (long) addr, + (long) nr_bytes, + (long) (addr + (nr_bytes - 1)), + next_mapping->space, + (long) next_mapping->base, + (long) next_mapping->bound, + (long) next_mapping->nr_bytes); +#endif + sim_io_error (sd, "memory map %d:0x%lx..0x%lx (%ld bytes) overlaps %d:0x%lx..0x%lx (%ld bytes)", + space, + (long) addr, + (long) nr_bytes, + (long) (addr + (nr_bytes - 1)), + next_mapping->space, + (long) next_mapping->base, + (long) next_mapping->bound, + (long) next_mapping->nr_bytes); + } + + /* create/insert the new mapping */ + *last_mapping = new_sim_core_mapping(sd, + level, + space, addr, nr_bytes, modulo, + client, buffer, free_buffer); + (*last_mapping)->next = next_mapping; +} +#endif + + +/* Attach memory or a memory mapped device to the simulator. + See sim-core.h for a full description. */ + +#if EXTERN_SIM_CORE_P +void +sim_core_attach (SIM_DESC sd, + sim_cpu *cpu, + int level, + unsigned mapmask, + int space, + address_word addr, + address_word nr_bytes, + unsigned modulo, +#if WITH_HW + struct hw *client, +#else + device *client, +#endif + void *optional_buffer) +{ + sim_core *memory = STATE_CORE(sd); + unsigned map; + void *buffer; + void *free_buffer; + + /* check for for attempt to use unimplemented per-processor core map */ + if (cpu != NULL) + sim_io_error (sd, "sim_core_map_attach - processor specific memory map not yet supported"); + + /* verify modulo memory */ + if (!WITH_MODULO_MEMORY && modulo != 0) + { +#if (WITH_DEVICES) + device_error (client, "sim_core_attach - internal error - modulo memory disabled"); +#endif +#if (WITH_HW) + sim_hw_abort (sd, client, "sim_core_attach - internal error - modulo memory disabled"); +#endif + sim_io_error (sd, "sim_core_attach - internal error - modulo memory disabled"); + } + if (client != NULL && modulo != 0) + { +#if (WITH_DEVICES) + device_error (client, "sim_core_attach - internal error - modulo and callback memory conflict"); +#endif +#if (WITH_HW) + sim_hw_abort (sd, client, "sim_core_attach - internal error - modulo and callback memory conflict"); +#endif + sim_io_error (sd, "sim_core_attach - internal error - modulo and callback memory conflict"); + } + if (modulo != 0) + { + unsigned mask = modulo - 1; + /* any zero bits */ + while (mask >= sizeof (unsigned64)) /* minimum modulo */ + { + if ((mask & 1) == 0) + mask = 0; + else + mask >>= 1; + } + if (mask != sizeof (unsigned64) - 1) + { +#if (WITH_DEVICES) + device_error (client, "sim_core_attach - internal error - modulo %lx not power of two", (long) modulo); +#endif +#if (WITH_HW) + sim_hw_abort (sd, client, "sim_core_attach - internal error - modulo %lx not power of two", (long) modulo); +#endif + sim_io_error (sd, "sim_core_attach - internal error - modulo %lx not power of two", (long) modulo); + } + } + + /* verify consistency between device and buffer */ + if (client != NULL && optional_buffer != NULL) + { +#if (WITH_DEVICES) + device_error (client, "sim_core_attach - internal error - conflicting buffer and attach arguments"); +#endif +#if (WITH_HW) + sim_hw_abort (sd, client, "sim_core_attach - internal error - conflicting buffer and attach arguments"); +#endif + sim_io_error (sd, "sim_core_attach - internal error - conflicting buffer and attach arguments"); + } + if (client == NULL) + { + if (optional_buffer == NULL) + { + int padding = (addr % sizeof (unsigned64)); + unsigned long bytes = (modulo == 0 ? nr_bytes : modulo) + padding; + free_buffer = zalloc (bytes); + buffer = (char*) free_buffer + padding; + } + else + { + buffer = optional_buffer; + free_buffer = NULL; + } + } + else + { + /* a device */ + buffer = NULL; + free_buffer = NULL; + } + + /* attach the region to all applicable access maps */ + for (map = 0; + map < nr_maps; + map++) + { + if (mapmask & (1 << map)) + { + sim_core_map_attach (sd, &memory->common.map[map], + level, space, addr, nr_bytes, modulo, + client, buffer, free_buffer); + free_buffer = NULL; + } + } + + /* Just copy this map to each of the processor specific data structures. + FIXME - later this will be replaced by true processor specific + maps. */ + { + int i; + for (i = 0; i < MAX_NR_PROCESSORS; i++) + { + CPU_CORE (STATE_CPU (sd, i))->common = STATE_CORE (sd)->common; + } + } +} +#endif + + +/* Remove any memory reference related to this address */ +#if EXTERN_SIM_CORE_P +static void +sim_core_map_detach (SIM_DESC sd, + sim_core_map *access_map, + int level, + int space, + address_word addr) +{ + sim_core_mapping **entry; + for (entry = &access_map->first; + (*entry) != NULL; + entry = &(*entry)->next) + { + if ((*entry)->base == addr + && (*entry)->level == level + && (*entry)->space == space) + { + sim_core_mapping *dead = (*entry); + (*entry) = dead->next; + if (dead->free_buffer != NULL) + zfree (dead->free_buffer); + zfree (dead); + return; + } + } +} +#endif + +#if EXTERN_SIM_CORE_P +void +sim_core_detach (SIM_DESC sd, + sim_cpu *cpu, + int level, + int address_space, + address_word addr) +{ + sim_core *memory = STATE_CORE (sd); + unsigned map; + for (map = 0; map < nr_maps; map++) + { + sim_core_map_detach (sd, &memory->common.map[map], + level, address_space, addr); + } + /* Just copy this update to each of the processor specific data + structures. FIXME - later this will be replaced by true + processor specific maps. */ + { + int i; + for (i = 0; i < MAX_NR_PROCESSORS; i++) + { + CPU_CORE (STATE_CPU (sd, i))->common = STATE_CORE (sd)->common; + } + } +} +#endif + + +STATIC_INLINE_SIM_CORE\ +(sim_core_mapping *) +sim_core_find_mapping(sim_core_common *core, + unsigned map, + address_word addr, + unsigned nr_bytes, + transfer_type transfer, + int abort, /*either 0 or 1 - hint to inline/-O */ + sim_cpu *cpu, /* abort => cpu != NULL */ + sim_cia cia) +{ + sim_core_mapping *mapping = core->map[map].first; + ASSERT ((addr & (nr_bytes - 1)) == 0); /* must be aligned */ + ASSERT ((addr + (nr_bytes - 1)) >= addr); /* must not wrap */ + ASSERT (!abort || cpu != NULL); /* abort needs a non null CPU */ + while (mapping != NULL) + { + if (addr >= mapping->base + && (addr + (nr_bytes - 1)) <= mapping->bound) + return mapping; + mapping = mapping->next; + } + if (abort) + { + SIM_CORE_SIGNAL (CPU_STATE (cpu), cpu, cia, map, nr_bytes, addr, transfer, + sim_core_unmapped_signal); + } + return NULL; +} + + +STATIC_INLINE_SIM_CORE\ +(void *) +sim_core_translate (sim_core_mapping *mapping, + address_word addr) +{ + if (WITH_MODULO_MEMORY) + return (void *)((unsigned8 *) mapping->buffer + + ((addr - mapping->base) & mapping->mask)); + else + return (void *)((unsigned8 *) mapping->buffer + + addr - mapping->base); +} + + +#if EXTERN_SIM_CORE_P +unsigned +sim_core_read_buffer (SIM_DESC sd, + sim_cpu *cpu, + unsigned map, + void *buffer, + address_word addr, + unsigned len) +{ + sim_core_common *core = (cpu == NULL ? &STATE_CORE (sd)->common : &CPU_CORE (cpu)->common); + unsigned count = 0; + while (count < len) + { + unsigned_word raddr = addr + count; + sim_core_mapping *mapping = + sim_core_find_mapping (core, map, + raddr, /*nr-bytes*/1, + read_transfer, + 0 /*dont-abort*/, NULL, NULL_CIA); + if (mapping == NULL) + break; +#if (WITH_DEVICES) + if (mapping->device != NULL) + { + int nr_bytes = len - count; + if (raddr + nr_bytes - 1> mapping->bound) + nr_bytes = mapping->bound - raddr + 1; + if (device_io_read_buffer (mapping->device, + (unsigned_1*)buffer + count, + mapping->space, + raddr, + nr_bytes, + cpu, + CIA_GET (cpu)) != nr_bytes) + break; + count += nr_bytes; + continue; + } +#endif +#if (WITH_HW) + if (mapping->device != NULL) + { + int nr_bytes = len - count; + if (raddr + nr_bytes - 1> mapping->bound) + nr_bytes = mapping->bound - raddr + 1; + if (sim_hw_io_read_buffer (sd, mapping->device, + (unsigned_1*)buffer + count, + mapping->space, + raddr, + nr_bytes) != nr_bytes) + break; + count += nr_bytes; + continue; + } +#endif + ((unsigned_1*)buffer)[count] = + *(unsigned_1*)sim_core_translate(mapping, raddr); + count += 1; + } + return count; +} +#endif + + +#if EXTERN_SIM_CORE_P +unsigned +sim_core_write_buffer (SIM_DESC sd, + sim_cpu *cpu, + unsigned map, + const void *buffer, + address_word addr, + unsigned len) +{ + sim_core_common *core = (cpu == NULL ? &STATE_CORE (sd)->common : &CPU_CORE (cpu)->common); + unsigned count = 0; + while (count < len) + { + unsigned_word raddr = addr + count; + sim_core_mapping *mapping = + sim_core_find_mapping (core, map, + raddr, /*nr-bytes*/1, + write_transfer, + 0 /*dont-abort*/, NULL, NULL_CIA); + if (mapping == NULL) + break; +#if (WITH_DEVICES) + if (WITH_CALLBACK_MEMORY + && mapping->device != NULL) + { + int nr_bytes = len - count; + if (raddr + nr_bytes - 1 > mapping->bound) + nr_bytes = mapping->bound - raddr + 1; + if (device_io_write_buffer (mapping->device, + (unsigned_1*)buffer + count, + mapping->space, + raddr, + nr_bytes, + cpu, + CIA_GET(cpu)) != nr_bytes) + break; + count += nr_bytes; + continue; + } +#endif +#if (WITH_HW) + if (WITH_CALLBACK_MEMORY + && mapping->device != NULL) + { + int nr_bytes = len - count; + if (raddr + nr_bytes - 1 > mapping->bound) + nr_bytes = mapping->bound - raddr + 1; + if (sim_hw_io_write_buffer (sd, mapping->device, + (unsigned_1*)buffer + count, + mapping->space, + raddr, + nr_bytes) != nr_bytes) + break; + count += nr_bytes; + continue; + } +#endif + *(unsigned_1*)sim_core_translate(mapping, raddr) = + ((unsigned_1*)buffer)[count]; + count += 1; + } + return count; +} +#endif + + +#if EXTERN_SIM_CORE_P +void +sim_core_set_xor (SIM_DESC sd, + sim_cpu *cpu, + int is_xor) +{ + /* set up the XOR map if required. */ + if (WITH_XOR_ENDIAN) { + { + sim_core *core = STATE_CORE (sd); + sim_cpu_core *cpu_core = (cpu != NULL ? CPU_CORE (cpu) : NULL); + if (cpu_core != NULL) + { + int i = 1; + unsigned mask; + if (is_xor) + mask = WITH_XOR_ENDIAN - 1; + else + mask = 0; + while (i - 1 < WITH_XOR_ENDIAN) + { + cpu_core->xor[i-1] = mask; + mask = (mask << 1) & (WITH_XOR_ENDIAN - 1); + i = (i << 1); + } + } + else + { + if (is_xor) + core->byte_xor = WITH_XOR_ENDIAN - 1; + else + core->byte_xor = 0; + } + } + } + else { + if (is_xor) + sim_engine_abort (sd, NULL, NULL_CIA, + "Attempted to enable xor-endian mode when permenantly disabled."); + } +} +#endif + + +#if EXTERN_SIM_CORE_P +static void +reverse_n (unsigned_1 *dest, + const unsigned_1 *src, + int nr_bytes) +{ + int i; + for (i = 0; i < nr_bytes; i++) + { + dest [nr_bytes - i - 1] = src [i]; + } +} +#endif + + +#if EXTERN_SIM_CORE_P +unsigned +sim_core_xor_read_buffer (SIM_DESC sd, + sim_cpu *cpu, + unsigned map, + void *buffer, + address_word addr, + unsigned nr_bytes) +{ + address_word byte_xor = (cpu == NULL ? STATE_CORE (sd)->byte_xor : CPU_CORE (cpu)->xor[0]); + if (!WITH_XOR_ENDIAN || !byte_xor) + return sim_core_read_buffer (sd, cpu, map, buffer, addr, nr_bytes); + else + /* only break up transfers when xor-endian is both selected and enabled */ + { + unsigned_1 x[WITH_XOR_ENDIAN + 1]; /* +1 to avoid zero-sized array */ + unsigned nr_transfered = 0; + address_word start = addr; + unsigned nr_this_transfer = (WITH_XOR_ENDIAN - (addr & ~(WITH_XOR_ENDIAN - 1))); + address_word stop; + /* initial and intermediate transfers are broken when they cross + an XOR endian boundary */ + while (nr_transfered + nr_this_transfer < nr_bytes) + /* initial/intermediate transfers */ + { + /* since xor-endian is enabled stop^xor defines the start + address of the transfer */ + stop = start + nr_this_transfer - 1; + SIM_ASSERT (start <= stop); + SIM_ASSERT ((stop ^ byte_xor) <= (start ^ byte_xor)); + if (sim_core_read_buffer (sd, cpu, map, x, stop ^ byte_xor, nr_this_transfer) + != nr_this_transfer) + return nr_transfered; + reverse_n (&((unsigned_1*)buffer)[nr_transfered], x, nr_this_transfer); + nr_transfered += nr_this_transfer; + nr_this_transfer = WITH_XOR_ENDIAN; + start = stop + 1; + } + /* final transfer */ + nr_this_transfer = nr_bytes - nr_transfered; + stop = start + nr_this_transfer - 1; + SIM_ASSERT (stop == (addr + nr_bytes - 1)); + if (sim_core_read_buffer (sd, cpu, map, x, stop ^ byte_xor, nr_this_transfer) + != nr_this_transfer) + return nr_transfered; + reverse_n (&((unsigned_1*)buffer)[nr_transfered], x, nr_this_transfer); + return nr_bytes; + } +} +#endif + + +#if EXTERN_SIM_CORE_P +unsigned +sim_core_xor_write_buffer (SIM_DESC sd, + sim_cpu *cpu, + unsigned map, + const void *buffer, + address_word addr, + unsigned nr_bytes) +{ + address_word byte_xor = (cpu == NULL ? STATE_CORE (sd)->byte_xor : CPU_CORE (cpu)->xor[0]); + if (!WITH_XOR_ENDIAN || !byte_xor) + return sim_core_write_buffer (sd, cpu, map, buffer, addr, nr_bytes); + else + /* only break up transfers when xor-endian is both selected and enabled */ + { + unsigned_1 x[WITH_XOR_ENDIAN + 1]; /* +1 to avoid zero sized array */ + unsigned nr_transfered = 0; + address_word start = addr; + unsigned nr_this_transfer = (WITH_XOR_ENDIAN - (addr & ~(WITH_XOR_ENDIAN - 1))); + address_word stop; + /* initial and intermediate transfers are broken when they cross + an XOR endian boundary */ + while (nr_transfered + nr_this_transfer < nr_bytes) + /* initial/intermediate transfers */ + { + /* since xor-endian is enabled stop^xor defines the start + address of the transfer */ + stop = start + nr_this_transfer - 1; + SIM_ASSERT (start <= stop); + SIM_ASSERT ((stop ^ byte_xor) <= (start ^ byte_xor)); + reverse_n (x, &((unsigned_1*)buffer)[nr_transfered], nr_this_transfer); + if (sim_core_read_buffer (sd, cpu, map, x, stop ^ byte_xor, nr_this_transfer) + != nr_this_transfer) + return nr_transfered; + nr_transfered += nr_this_transfer; + nr_this_transfer = WITH_XOR_ENDIAN; + start = stop + 1; + } + /* final transfer */ + nr_this_transfer = nr_bytes - nr_transfered; + stop = start + nr_this_transfer - 1; + SIM_ASSERT (stop == (addr + nr_bytes - 1)); + reverse_n (x, &((unsigned_1*)buffer)[nr_transfered], nr_this_transfer); + if (sim_core_read_buffer (sd, cpu, map, x, stop ^ byte_xor, nr_this_transfer) + != nr_this_transfer) + return nr_transfered; + return nr_bytes; + } +} +#endif + + + +/* define the read/write 1/2/4/8/16/word functions */ + +#define N 16 +#include "sim-n-core.h" + +#define N 8 +#include "sim-n-core.h" + +#define N 7 +#define M 8 +#include "sim-n-core.h" + +#define N 6 +#define M 8 +#include "sim-n-core.h" + +#define N 5 +#define M 8 +#include "sim-n-core.h" + +#define N 4 +#include "sim-n-core.h" + +#define N 3 +#define M 4 +#include "sim-n-core.h" + +#define N 2 +#include "sim-n-core.h" + +#define N 1 +#include "sim-n-core.h" + +#endif diff --git a/sim/common/sim-core.h b/sim/common/sim-core.h new file mode 100644 index 0000000..7bf15a3 --- /dev/null +++ b/sim/common/sim-core.h @@ -0,0 +1,343 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef SIM_CORE_H +#define SIM_CORE_H + + +/* core signals (error conditions) + Define SIM_CORE_SIGNAL to catch these signals - see sim-core.c for + details. */ + +typedef enum { + sim_core_unmapped_signal, + sim_core_unaligned_signal, + nr_sim_core_signals, +} sim_core_signals; + +/* Type of SIM_CORE_SIGNAL handler. */ +typedef void (SIM_CORE_SIGNAL_FN) + (SIM_DESC sd, sim_cpu *cpu, sim_cia cia, unsigned map, int nr_bytes, + address_word addr, transfer_type transfer, sim_core_signals sig); + +extern SIM_CORE_SIGNAL_FN sim_core_signal; + + +/* basic types */ + +typedef struct _sim_core_mapping sim_core_mapping; +struct _sim_core_mapping { + /* common */ + int level; + int space; + unsigned_word base; + unsigned_word bound; + unsigned_word nr_bytes; + unsigned mask; + /* memory map */ + void *free_buffer; + void *buffer; + /* callback map */ +#if (WITH_HW) + struct hw *device; +#else + device *device; +#endif + /* tracing */ + int trace; + /* growth */ + sim_core_mapping *next; +}; + +typedef struct _sim_core_map sim_core_map; +struct _sim_core_map { + sim_core_mapping *first; +}; + + +typedef struct _sim_core_common { + sim_core_map map[nr_maps]; +} sim_core_common; + + +/* Main core structure */ + +typedef struct _sim_core sim_core; +struct _sim_core { + sim_core_common common; + address_word byte_xor; /* apply xor universally */ +}; + + +/* Per CPU distributed component of the core. At present this is + mostly a clone of the global core data structure. */ + +typedef struct _sim_cpu_core { + sim_core_common common; + address_word xor[WITH_XOR_ENDIAN + 1]; /* +1 to avoid zero-sized array */ +} sim_cpu_core; + + +/* Install the "core" module. */ + +extern SIM_RC sim_core_install (SIM_DESC sd); + + + +/* Create a memory region within the core. + + CPU - when non NULL, specifes the single processor that the memory + space is to be attached to. (INIMPLEMENTED). + + LEVEL - specifies the ordering of the memory region. Lower regions + are searched first. Within a level, memory regions can not + overlap. + + MAPMASK - Bitmask specifying the memory maps that the region is to + be attached to. Typically the enums sim-basics.h:access_* are used. + + ADDRESS_SPACE - For device regions, a MAP:ADDRESS pair is + translated into ADDRESS_SPACE:OFFSET before being passed to the + client device. + + MODULO - when the simulator has been configured WITH_MODULO support + and is greater than zero, specifies that accesses to the region + [ADDR .. ADDR+NR_BYTES) should be mapped onto the sub region [ADDR + .. ADDR+MODULO). The modulo value must be a power of two. + + DEVICE - When non NULL, indicates that this is a callback memory + space and specified device's memory callback handler should be + called. + + OPTIONAL_BUFFER - when non NULL, specifies the buffer to use for + data read & written to the region. Normally a more efficient + internal structure is used. It is assumed that buffer is allocated + such that the byte alignmed of OPTIONAL_BUFFER matches ADDR vis + (OPTIONAL_BUFFER % 8) == (ADDR % 8)). It is defined to be a sub-optimal + hook that allows clients to do nasty things that the interface doesn't + accomodate. */ + +extern void sim_core_attach +(SIM_DESC sd, + sim_cpu *cpu, + int level, + unsigned mapmask, + int address_space, + address_word addr, + address_word nr_bytes, + unsigned modulo, +#if (WITH_HW) + struct hw *client, +#else + device *client, +#endif + void *optional_buffer); + + +/* Delete a memory section within the core. + + */ + +extern void sim_core_detach +(SIM_DESC sd, + sim_cpu *cpu, + int level, + int address_space, + address_word addr); + + +/* Variable sized read/write + + Transfer a variable sized block of raw data between the host and + target. Should any problems occure, the number of bytes + successfully transfered is returned. + + No host/target byte endian conversion is performed. No xor-endian + conversion is performed. + + If CPU argument, when non NULL, specifies the processor specific + address map that is to be used in the transfer. */ + + +extern unsigned sim_core_read_buffer +(SIM_DESC sd, + sim_cpu *cpu, + unsigned map, + void *buffer, + address_word addr, + unsigned nr_bytes); + +extern unsigned sim_core_write_buffer +(SIM_DESC sd, + sim_cpu *cpu, + unsigned map, + const void *buffer, + address_word addr, + unsigned nr_bytes); + + + +/* Configure the core's XOR endian transfer mode. Only applicable + when WITH_XOR_ENDIAN is enabled. + + Targets suporting XOR endian, shall notify the core of any changes + in state via this call. + + The CPU argument, when non NULL, specifes the single processor that + the xor-endian configuration is to be applied to. */ + +extern void sim_core_set_xor +(SIM_DESC sd, + sim_cpu *cpu, + int is_xor); + + +/* XOR version of variable sized read/write. + + Transfer a variable sized block of raw data between the host and + target. Should any problems occure, the number of bytes + successfully transfered is returned. + + No host/target byte endian conversion is performed. If applicable + (WITH_XOR_ENDIAN and xor-endian set), xor-endian conversion *is* + performed. + + If CPU argument, when non NULL, specifies the processor specific + address map that is to be used in the transfer. */ + +extern unsigned sim_core_xor_read_buffer +(SIM_DESC sd, + sim_cpu *cpu, + unsigned map, + void *buffer, + address_word addr, + unsigned nr_bytes); + +extern unsigned sim_core_xor_write_buffer +(SIM_DESC sd, + sim_cpu *cpu, + unsigned map, + const void *buffer, + address_word addr, + unsigned nr_bytes); + + + +/* Fixed sized, processor oriented, read/write. + + Transfer a fixed amout of memory between the host and target. The + data transfered is translated from/to host to/from target byte + order (including xor endian). Should the transfer fail, the + operation shall abort (no return). + + ALIGNED assumes yhat the specified ADDRESS is correctly alligned + for an N byte transfer (no alignment checks are made). Passing an + incorrectly aligned ADDRESS is erroneous. + + UNALIGNED checks/modifies the ADDRESS according to the requirements + of an N byte transfer. Action, as defined by WITH_ALIGNMENT, being + taken should the check fail. + + MISSALIGNED transfers the data regardless. + + Misaligned xor-endian accesses are broken into a sequence of + transfers each <= WITH_XOR_ENDIAN bytes */ + + +#define DECLARE_SIM_CORE_WRITE_N(ALIGNMENT,N,M) \ +INLINE_SIM_CORE\ +(void) sim_core_write_##ALIGNMENT##_##N \ +(sim_cpu *cpu, \ + sim_cia cia, \ + unsigned map, \ + address_word addr, \ + unsigned_##M val); + +DECLARE_SIM_CORE_WRITE_N(aligned,1,1) +DECLARE_SIM_CORE_WRITE_N(aligned,2,2) +DECLARE_SIM_CORE_WRITE_N(aligned,4,4) +DECLARE_SIM_CORE_WRITE_N(aligned,8,8) +DECLARE_SIM_CORE_WRITE_N(aligned,16,16) + +#define sim_core_write_unaligned_1 sim_core_write_aligned_1 +DECLARE_SIM_CORE_WRITE_N(unaligned,2,2) +DECLARE_SIM_CORE_WRITE_N(unaligned,4,4) +DECLARE_SIM_CORE_WRITE_N(unaligned,8,8) +DECLARE_SIM_CORE_WRITE_N(unaligned,16,16) + +DECLARE_SIM_CORE_WRITE_N(misaligned,3,4) +DECLARE_SIM_CORE_WRITE_N(misaligned,5,8) +DECLARE_SIM_CORE_WRITE_N(misaligned,6,8) +DECLARE_SIM_CORE_WRITE_N(misaligned,7,8) + +#define sim_core_write_1 sim_core_write_aligned_1 +#define sim_core_write_2 sim_core_write_aligned_2 +#define sim_core_write_4 sim_core_write_aligned_4 +#define sim_core_write_8 sim_core_write_aligned_8 +#define sim_core_write_16 sim_core_write_aligned_16 + +#define sim_core_write_unaligned_word XCONCAT2(sim_core_write_unaligned_,WITH_TARGET_WORD_BITSIZE) +#define sim_core_write_aligned_word XCONCAT2(sim_core_write_aligned_,WITH_TARGET_WORD_BITSIZE) +#define sim_core_write_word XCONCAT2(sim_core_write_,WITH_TARGET_WORD_BITSIZE) + +#undef DECLARE_SIM_CORE_WRITE_N + + +#define DECLARE_SIM_CORE_READ_N(ALIGNMENT,N,M) \ +INLINE_SIM_CORE\ +(unsigned_##M) sim_core_read_##ALIGNMENT##_##N \ +(sim_cpu *cpu, \ + sim_cia cia, \ + unsigned map, \ + address_word addr); + +DECLARE_SIM_CORE_READ_N(aligned,1,1) +DECLARE_SIM_CORE_READ_N(aligned,2,2) +DECLARE_SIM_CORE_READ_N(aligned,4,4) +DECLARE_SIM_CORE_READ_N(aligned,8,8) +DECLARE_SIM_CORE_READ_N(aligned,16,16) + +#define sim_core_read_unaligned_1 sim_core_read_aligned_1 +DECLARE_SIM_CORE_READ_N(unaligned,2,2) +DECLARE_SIM_CORE_READ_N(unaligned,4,4) +DECLARE_SIM_CORE_READ_N(unaligned,8,8) +DECLARE_SIM_CORE_READ_N(unaligned,16,16) + +DECLARE_SIM_CORE_READ_N(misaligned,3,4) +DECLARE_SIM_CORE_READ_N(misaligned,5,8) +DECLARE_SIM_CORE_READ_N(misaligned,6,8) +DECLARE_SIM_CORE_READ_N(misaligned,7,8) + + +#define sim_core_read_1 sim_core_read_aligned_1 +#define sim_core_read_2 sim_core_read_aligned_2 +#define sim_core_read_4 sim_core_read_aligned_4 +#define sim_core_read_8 sim_core_read_aligned_8 +#define sim_core_read_16 sim_core_read_aligned_16 + +#define sim_core_read_unaligned_word XCONCAT2(sim_core_read_unaligned_,WITH_TARGET_WORD_BITSIZE) +#define sim_core_read_aligned_word XCONCAT2(sim_core_read_aligned_,WITH_TARGET_WORD_BITSIZE) +#define sim_core_read_word XCONCAT2(sim_core_read_,WITH_TARGET_WORD_BITSIZE) + +#undef DECLARE_SIM_CORE_READ_N + + +#endif diff --git a/sim/common/sim-cpu.c b/sim/common/sim-cpu.c new file mode 100644 index 0000000..0e6d52c --- /dev/null +++ b/sim/common/sim-cpu.c @@ -0,0 +1,80 @@ +/* CPU support. + Copyright (C) 1998 Free Software Foundation, Inc. + Contributed by Cygnus Solutions. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "sim-main.h" +#include "bfd.h" + +/* Allocate space for all cpus in the simulator. + Space for the cpu must currently exist prior to parsing ARGV. + EXTRA_BYTES is additional space to allocate for the sim_cpu struct. */ +/* ??? wip. better solution must wait. */ + +SIM_RC +sim_cpu_alloc_all (SIM_DESC sd, int ncpus, int extra_bytes) +{ + int c; + + for (c = 0; c < ncpus; ++c) + STATE_CPU (sd, c) = sim_cpu_alloc (sd, extra_bytes); + return SIM_RC_OK; +} + +/* Allocate space for a cpu object. + EXTRA_BYTES is additional space to allocate for the sim_cpu struct. */ + +sim_cpu * +sim_cpu_alloc (SIM_DESC sd, int extra_bytes) +{ + return zalloc (sizeof (sim_cpu) + extra_bytes); +} + +/* Free all resources held by all cpus. */ + +void +sim_cpu_free_all (SIM_DESC sd) +{ + int c; + + for (c = 0; c < MAX_NR_PROCESSORS; ++c) + if (STATE_CPU (sd, c)) + sim_cpu_free (STATE_CPU (sd, c)); +} + +/* Free all resources used by CPU. */ + +void +sim_cpu_free (sim_cpu *cpu) +{ + zfree (cpu); +} + +/* PC utilities. */ + +sim_cia +sim_pc_get (sim_cpu *cpu) +{ + return (* CPU_PC_FETCH (cpu)) (cpu); +} + +void +sim_pc_set (sim_cpu *cpu, sim_cia newval) +{ + (* CPU_PC_STORE (cpu)) (cpu, newval); +} diff --git a/sim/common/sim-cpu.h b/sim/common/sim-cpu.h new file mode 100644 index 0000000..069fead --- /dev/null +++ b/sim/common/sim-cpu.h @@ -0,0 +1,152 @@ +/* CPU support. + Copyright (C) 1998 Free Software Foundation, Inc. + Contributed by Cygnus Solutions. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file is intended to be included by sim-base.h. + + This file provides an interface between the simulator framework and + the selected cpu. */ + +#ifndef SIM_CPU_H +#define SIM_CPU_H + +/* Type of function to return an insn name. */ +typedef const char * (CPU_INSN_NAME_FN) (sim_cpu *, int); + +/* Types for register access functions. + These routines implement the sim_{fetch,store}_register interface. */ +typedef int (CPUREG_FETCH_FN) (sim_cpu *, int, unsigned char *, int); +typedef int (CPUREG_STORE_FN) (sim_cpu *, int, unsigned char *, int); + +/* Types for PC access functions. + Some simulators require a functional interface to access the program + counter [a macro is insufficient as the PC is kept in a cpu-specific part + of the sim_cpu struct]. */ +typedef sim_cia (PC_FETCH_FN) (sim_cpu *); +typedef void (PC_STORE_FN) (sim_cpu *, sim_cia); + +/* Pseudo baseclass for each cpu. */ + +typedef struct { + + /* Backlink to main state struct. */ + SIM_DESC state; +#define CPU_STATE(cpu) ((cpu)->base.state) + + /* Processor index within the SD_DESC */ + int index; +#define CPU_INDEX(cpu) ((cpu)->base.index) + + /* The name of the cpu. */ + const char *name; +#define CPU_NAME(cpu) ((cpu)->base.name) + + /* Options specific to this cpu. */ + struct option_list *options; +#define CPU_OPTIONS(cpu) ((cpu)->base.options) + + /* Processor specific core data */ + sim_cpu_core core; +#define CPU_CORE(cpu) (& (cpu)->base.core) + + /* Number of instructions (used to iterate over CPU_INSN_NAME). */ + unsigned int max_insns; +#define CPU_MAX_INSNS(cpu) ((cpu)->base.max_insns) + + /* Function to return the name of an insn. */ + CPU_INSN_NAME_FN *insn_name; +#define CPU_INSN_NAME(cpu) ((cpu)->base.insn_name) + + /* Trace data. See sim-trace.h. */ + TRACE_DATA trace_data; +#define CPU_TRACE_DATA(cpu) (& (cpu)->base.trace_data) + + /* Maximum number of debuggable entities. + This debugging is not intended for normal use. + It is only enabled when the simulator is configured with --with-debug + which shouldn't normally be specified. */ +#ifndef MAX_DEBUG_VALUES +#define MAX_DEBUG_VALUES 4 +#endif + + /* Boolean array of specified debugging flags. */ + char debug_flags[MAX_DEBUG_VALUES]; +#define CPU_DEBUG_FLAGS(cpu) ((cpu)->base.debug_flags) + /* Standard values. */ +#define DEBUG_INSN_IDX 0 +#define DEBUG_NEXT_IDX 2 /* simulator specific debug bits begin here */ + + /* Debugging output goes to this or stderr if NULL. + We can't store `stderr' here as stderr goes through a callback. */ + FILE *debug_file; +#define CPU_DEBUG_FILE(cpu) ((cpu)->base.debug_file) + + /* Profile data. See sim-profile.h. */ + PROFILE_DATA profile_data; +#define CPU_PROFILE_DATA(cpu) (& (cpu)->base.profile_data) + +#ifdef SIM_HAVE_MODEL + /* Machine tables for this cpu. See sim-model.h. */ + const MACH *mach; +#define CPU_MACH(cpu) ((cpu)->base.mach) + /* The selected model. */ + const MODEL *model; +#define CPU_MODEL(cpu) ((cpu)->base.model) + /* Model data (profiling state, etc.). */ + void *model_data; +#define CPU_MODEL_DATA(cpu) ((cpu)->base.model_data) +#endif + + /* Routines to fetch/store registers. */ + CPUREG_FETCH_FN *reg_fetch; +#define CPU_REG_FETCH(c) ((c)->base.reg_fetch) + CPUREG_STORE_FN *reg_store; +#define CPU_REG_STORE(c) ((c)->base.reg_store) + PC_FETCH_FN *pc_fetch; +#define CPU_PC_FETCH(c) ((c)->base.pc_fetch) + PC_STORE_FN *pc_store; +#define CPU_PC_STORE(c) ((c)->base.pc_store) + +} sim_cpu_base; + +/* Create all cpus. */ +extern SIM_RC sim_cpu_alloc_all (SIM_DESC, int, int); +/* Create a cpu. */ +extern sim_cpu *sim_cpu_alloc (SIM_DESC, int); +/* Release resources held by all cpus. */ +extern void sim_cpu_free_all (SIM_DESC); +/* Release resources held by a cpu. */ +extern void sim_cpu_free (sim_cpu *); + +/* Return a pointer to the cpu data for CPU_NAME, or NULL if not found. */ +extern sim_cpu *sim_cpu_lookup (SIM_DESC, const char *); + +/* Return prefix to use in cpu specific messages. */ +extern const char *sim_cpu_msg_prefix (sim_cpu *); +/* Cover fn to sim_io_eprintf. */ +extern void sim_io_eprintf_cpu (sim_cpu *, const char *, ...); + +/* Get/set a pc value. */ +#define CPU_PC_GET(cpu) ((* CPU_PC_FETCH (cpu)) (cpu)) +#define CPU_PC_SET(cpu,newval) ((* CPU_PC_STORE (cpu)) ((cpu), (newval))) +/* External interface to accessing the pc. */ +sim_cia sim_pc_get (sim_cpu *); +void sim_pc_set (sim_cpu *, sim_cia); + +#endif /* SIM_CPU_H */ diff --git a/sim/common/sim-endian.c b/sim/common/sim-endian.c new file mode 100644 index 0000000..3682028 --- /dev/null +++ b/sim/common/sim-endian.c @@ -0,0 +1,128 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef _SIM_ENDIAN_C_ +#define _SIM_ENDIAN_C_ + +#include "sim-basics.h" +#include "sim-assert.h" +#include "sim-io.h" + + +#if !defined(_SWAP_1) +#define _SWAP_1(SET,RAW) SET (RAW) +#endif + +#if !defined(_SWAP_2) && (WITH_HOST_BYTE_ORDER == LITTLE_ENDIAN) && defined(htons) +#define _SWAP_2(SET,RAW) SET htons (RAW) +#endif + +#ifndef _SWAP_2 +#define _SWAP_2(SET,RAW) SET (((RAW) >> 8) | ((RAW) << 8)) +#endif + +#if !defined(_SWAP_4) && (WITH_HOST_BYTE_ORDER == LITTLE_ENDIAN) && defined(htonl) +#define _SWAP_4(SET,RAW) SET htonl (RAW) +#endif + +#ifndef _SWAP_4 +#define _SWAP_4(SET,RAW) SET (((RAW) << 24) | (((RAW) & 0xff00) << 8) | (((RAW) & 0xff0000) >> 8) | ((RAW) >> 24)) +#endif + +#ifndef _SWAP_8 +#define _SWAP_8(SET,RAW) \ + union { unsigned_8 dword; unsigned_4 words[2]; } in, out; \ + in.dword = RAW; \ + _SWAP_4 (out.words[0] =, in.words[1]); \ + _SWAP_4 (out.words[1] =, in.words[0]); \ + SET out.dword; +#endif + +#ifndef _SWAP_16 +#define _SWAP_16(SET,RAW) \ + union { unsigned_16 word; unsigned_4 words[4]; } in, out; \ + in.word = (RAW); \ + _SWAP_4 (out.words[0] =, in.words[3]); \ + _SWAP_4 (out.words[1] =, in.words[2]); \ + _SWAP_4 (out.words[2] =, in.words[1]); \ + _SWAP_4 (out.words[3] =, in.words[0]); \ + SET out.word; +#endif + + +#define N 1 +#include "sim-n-endian.h" +#undef N + +#define N 2 +#include "sim-n-endian.h" +#undef N + +#define N 4 +#include "sim-n-endian.h" +#undef N + +#define N 8 +#include "sim-n-endian.h" +#undef N + +#define N 16 +#include "sim-n-endian.h" +#undef N + + +INLINE_SIM_ENDIAN\ +(unsigned_8) +sim_endian_split_16 (unsigned_16 word, int w) +{ + if (CURRENT_HOST_BYTE_ORDER == LITTLE_ENDIAN) + { + return word.a[1 - w]; + } + else + { + return word.a[w]; + } +} + + +INLINE_SIM_ENDIAN\ +(unsigned_16) +sim_endian_join_16 (unsigned_8 h, unsigned_8 l) + +{ + unsigned_16 word; + if (CURRENT_HOST_BYTE_ORDER == LITTLE_ENDIAN) + { + word.a[0] = l; + word.a[1] = h; + } + else + { + word.a[0] = h; + word.a[1] = l; + } + return word; +} + + + +#endif /* _SIM_ENDIAN_C_ */ diff --git a/sim/common/sim-endian.h b/sim/common/sim-endian.h new file mode 100644 index 0000000..d733c82 --- /dev/null +++ b/sim/common/sim-endian.h @@ -0,0 +1,414 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au> + Copyright (C) 1997, Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef _SIM_ENDIAN_H_ +#define _SIM_ENDIAN_H_ + + +/* C byte conversion functions */ + +INLINE_SIM_ENDIAN(unsigned_1) endian_h2t_1(unsigned_1 x); +INLINE_SIM_ENDIAN(unsigned_2) endian_h2t_2(unsigned_2 x); +INLINE_SIM_ENDIAN(unsigned_4) endian_h2t_4(unsigned_4 x); +INLINE_SIM_ENDIAN(unsigned_8) endian_h2t_8(unsigned_8 x); +INLINE_SIM_ENDIAN(unsigned_16) endian_h2t_16(unsigned_16 x); + +INLINE_SIM_ENDIAN(unsigned_1) endian_t2h_1(unsigned_1 x); +INLINE_SIM_ENDIAN(unsigned_2) endian_t2h_2(unsigned_2 x); +INLINE_SIM_ENDIAN(unsigned_4) endian_t2h_4(unsigned_4 x); +INLINE_SIM_ENDIAN(unsigned_8) endian_t2h_8(unsigned_8 x); +INLINE_SIM_ENDIAN(unsigned_16) endian_t2h_16(unsigned_16 x); + +INLINE_SIM_ENDIAN(unsigned_1) swap_1(unsigned_1 x); +INLINE_SIM_ENDIAN(unsigned_2) swap_2(unsigned_2 x); +INLINE_SIM_ENDIAN(unsigned_4) swap_4(unsigned_4 x); +INLINE_SIM_ENDIAN(unsigned_8) swap_8(unsigned_8 x); +INLINE_SIM_ENDIAN(unsigned_16) swap_16(unsigned_16 x); + +INLINE_SIM_ENDIAN(unsigned_1) endian_h2be_1(unsigned_1 x); +INLINE_SIM_ENDIAN(unsigned_2) endian_h2be_2(unsigned_2 x); +INLINE_SIM_ENDIAN(unsigned_4) endian_h2be_4(unsigned_4 x); +INLINE_SIM_ENDIAN(unsigned_8) endian_h2be_8(unsigned_8 x); +INLINE_SIM_ENDIAN(unsigned_16) endian_h2be_16(unsigned_16 x); + +INLINE_SIM_ENDIAN(unsigned_1) endian_be2h_1(unsigned_1 x); +INLINE_SIM_ENDIAN(unsigned_2) endian_be2h_2(unsigned_2 x); +INLINE_SIM_ENDIAN(unsigned_4) endian_be2h_4(unsigned_4 x); +INLINE_SIM_ENDIAN(unsigned_8) endian_be2h_8(unsigned_8 x); +INLINE_SIM_ENDIAN(unsigned_16) endian_be2h_16(unsigned_16 x); + +INLINE_SIM_ENDIAN(unsigned_1) endian_h2le_1(unsigned_1 x); +INLINE_SIM_ENDIAN(unsigned_2) endian_h2le_2(unsigned_2 x); +INLINE_SIM_ENDIAN(unsigned_4) endian_h2le_4(unsigned_4 x); +INLINE_SIM_ENDIAN(unsigned_8) endian_h2le_8(unsigned_8 x); +INLINE_SIM_ENDIAN(unsigned_16) endian_h2le_16(unsigned_16 x); + +INLINE_SIM_ENDIAN(unsigned_1) endian_le2h_1(unsigned_1 x); +INLINE_SIM_ENDIAN(unsigned_2) endian_le2h_2(unsigned_2 x); +INLINE_SIM_ENDIAN(unsigned_4) endian_le2h_4(unsigned_4 x); +INLINE_SIM_ENDIAN(unsigned_8) endian_le2h_8(unsigned_8 x); +INLINE_SIM_ENDIAN(unsigned_16) endian_le2h_16(unsigned_16 x); + +INLINE_SIM_ENDIAN(void*) offset_1(unsigned_1 *x, unsigned ws, unsigned w); +INLINE_SIM_ENDIAN(void*) offset_2(unsigned_2 *x, unsigned ws, unsigned w); +INLINE_SIM_ENDIAN(void*) offset_4(unsigned_4 *x, unsigned ws, unsigned w); +INLINE_SIM_ENDIAN(void*) offset_8(unsigned_8 *x, unsigned ws, unsigned w); +INLINE_SIM_ENDIAN(void*) offset_16(unsigned_16 *x, unsigned ws, unsigned w); + +INLINE_SIM_ENDIAN(unsigned_16) sim_endian_join_16 (unsigned_8 h, unsigned_8 l); +INLINE_SIM_ENDIAN(unsigned_8) sim_endian_split_16 (unsigned_16 word, int w); + + +/* SWAP */ + +#define SWAP_1(X) swap_1(X) +#define SWAP_2(X) swap_2(X) +#define SWAP_4(X) swap_4(X) +#define SWAP_8(X) swap_8(X) +#define SWAP_16(X) swap_16(X) + + +/* HOST to BE */ + +#define H2BE_1(X) endian_h2be_1(X) +#define H2BE_2(X) endian_h2be_2(X) +#define H2BE_4(X) endian_h2be_4(X) +#define H2BE_8(X) endian_h2be_8(X) +#define H2BE_16(X) endian_h2be_16(X) +#define BE2H_1(X) endian_be2h_1(X) +#define BE2H_2(X) endian_be2h_2(X) +#define BE2H_4(X) endian_be2h_4(X) +#define BE2H_8(X) endian_be2h_8(X) +#define BE2H_16(X) endian_be2h_16(X) + + +/* HOST to LE */ + +#define H2LE_1(X) endian_h2le_1(X) +#define H2LE_2(X) endian_h2le_2(X) +#define H2LE_4(X) endian_h2le_4(X) +#define H2LE_8(X) endian_h2le_8(X) +#define H2LE_16(X) endian_h2le_16(X) +#define LE2H_1(X) endian_le2h_1(X) +#define LE2H_2(X) endian_le2h_2(X) +#define LE2H_4(X) endian_le2h_4(X) +#define LE2H_8(X) endian_le2h_8(X) +#define LE2H_16(X) endian_le2h_16(X) + + +/* HOST to TARGET */ + +#define H2T_1(X) endian_h2t_1(X) +#define H2T_2(X) endian_h2t_2(X) +#define H2T_4(X) endian_h2t_4(X) +#define H2T_8(X) endian_h2t_8(X) +#define H2T_16(X) endian_h2t_16(X) +#define T2H_1(X) endian_t2h_1(X) +#define T2H_2(X) endian_t2h_2(X) +#define T2H_4(X) endian_t2h_4(X) +#define T2H_8(X) endian_t2h_8(X) +#define T2H_16(X) endian_t2h_16(X) + + +/* CONVERT IN PLACE + + These macros, given an argument of unknown size, swap its value in + place if a host/target conversion is required. */ + +#define H2T(VARIABLE) \ +do { \ + void *vp = &(VARIABLE); \ + switch (sizeof (VARIABLE)) { \ + case 1: *(unsigned_1*)vp = H2T_1(*(unsigned_1*)vp); break; \ + case 2: *(unsigned_2*)vp = H2T_2(*(unsigned_2*)vp); break; \ + case 4: *(unsigned_4*)vp = H2T_4(*(unsigned_4*)vp); break; \ + case 8: *(unsigned_8*)vp = H2T_8(*(unsigned_8*)vp); break; \ + case 16: *(unsigned_16*)vp = H2T_16(*(unsigned_16*)vp); break; \ + } \ +} while (0) + +#define T2H(VARIABLE) \ +do { \ + switch (sizeof(VARIABLE)) { \ + case 1: VARIABLE = T2H_1(VARIABLE); break; \ + case 2: VARIABLE = T2H_2(VARIABLE); break; \ + case 4: VARIABLE = T2H_4(VARIABLE); break; \ + case 8: VARIABLE = T2H_8(VARIABLE); break; \ + /*case 16: VARIABLE = T2H_16(VARIABLE); break;*/ \ + } \ +} while (0) + +#define SWAP(VARIABLE) \ +do { \ + switch (sizeof(VARIABLE)) { \ + case 1: VARIABLE = SWAP_1(VARIABLE); break; \ + case 2: VARIABLE = SWAP_2(VARIABLE); break; \ + case 4: VARIABLE = SWAP_4(VARIABLE); break; \ + case 8: VARIABLE = SWAP_8(VARIABLE); break; \ + /*case 16: VARIABLE = SWAP_16(VARIABLE); break;*/ \ + } \ +} while (0) + +#define H2BE(VARIABLE) \ +do { \ + switch (sizeof(VARIABLE)) { \ + case 1: VARIABLE = H2BE_1(VARIABLE); break; \ + case 2: VARIABLE = H2BE_2(VARIABLE); break; \ + case 4: VARIABLE = H2BE_4(VARIABLE); break; \ + case 8: VARIABLE = H2BE_8(VARIABLE); break; \ + /*case 16: VARIABLE = H2BE_16(VARIABLE); break;*/ \ + } \ +} while (0) + +#define BE2H(VARIABLE) \ +do { \ + switch (sizeof(VARIABLE)) { \ + case 1: VARIABLE = BE2H_1(VARIABLE); break; \ + case 2: VARIABLE = BE2H_2(VARIABLE); break; \ + case 4: VARIABLE = BE2H_4(VARIABLE); break; \ + case 8: VARIABLE = BE2H_8(VARIABLE); break; \ + /*case 16: VARIABLE = BE2H_16(VARIABLE); break;*/ \ + } \ +} while (0) + +#define H2LE(VARIABLE) \ +do { \ + switch (sizeof(VARIABLE)) { \ + case 1: VARIABLE = H2LE_1(VARIABLE); break; \ + case 2: VARIABLE = H2LE_2(VARIABLE); break; \ + case 4: VARIABLE = H2LE_4(VARIABLE); break; \ + case 8: VARIABLE = H2LE_8(VARIABLE); break; \ + /*case 16: VARIABLE = H2LE_16(VARIABLE); break;*/ \ + } \ +} while (0) + +#define LE2H(VARIABLE) \ +do { \ + switch (sizeof(VARIABLE)) { \ + case 1: VARIABLE = LE2H_1(VARIABLE); break; \ + case 2: VARIABLE = LE2H_2(VARIABLE); break; \ + case 4: VARIABLE = LE2H_4(VARIABLE); break; \ + case 8: VARIABLE = LE2H_8(VARIABLE); break; \ + /*case 16: VARIABLE = LE2H_16(VARIABLE); break;*/ \ + } \ +} while (0) + + + +/* TARGET WORD: + + Byte swap a quantity the size of the targets word */ + +#if (WITH_TARGET_WORD_BITSIZE == 64) +#define H2T_word(X) H2T_8(X) +#define T2H_word(X) T2H_8(X) +#define H2BE_word(X) H2BE_8(X) +#define BE2H_word(X) BE2H_8(X) +#define H2LE_word(X) H2LE_8(X) +#define LE2H_word(X) LE2H_8(X) +#define SWAP_word(X) SWAP_8(X) +#endif +#if (WITH_TARGET_WORD_BITSIZE == 32) +#define H2T_word(X) H2T_4(X) +#define T2H_word(X) T2H_4(X) +#define H2BE_word(X) H2BE_4(X) +#define BE2H_word(X) BE2H_4(X) +#define H2LE_word(X) H2LE_4(X) +#define LE2H_word(X) LE2H_4(X) +#define SWAP_word(X) SWAP_4(X) +#endif + + + +/* TARGET CELL: + + Byte swap a quantity the size of the targets IEEE 1275 memory cell */ + +#define H2T_cell(X) H2T_4(X) +#define T2H_cell(X) T2H_4(X) +#define H2BE_cell(X) H2BE_4(X) +#define BE2H_cell(X) BE2H_4(X) +#define H2LE_cell(X) H2LE_4(X) +#define LE2H_cell(X) LE2H_4(X) +#define SWAP_cell(X) SWAP_4(X) + + + +/* HOST Offsets: + + Address of high/low sub-word within a host word quantity. + + Address of sub-word N within a host word quantity. NOTE: Numbering + is BIG endian always. */ + +#define AH1_2(X) (unsigned_1*)offset_2((X), 1, 0) +#define AL1_2(X) (unsigned_1*)offset_2((X), 1, 1) + +#define AH2_4(X) (unsigned_2*)offset_4((X), 2, 0) +#define AL2_4(X) (unsigned_2*)offset_4((X), 2, 1) + +#define AH4_8(X) (unsigned_4*)offset_8((X), 4, 0) +#define AL4_8(X) (unsigned_4*)offset_8((X), 4, 1) + +#define AH8_16(X) (unsigned_8*)offset_16((X), 8, 0) +#define AL8_16(X) (unsigned_8*)offset_16((X), 8, 1) + +#if (WITH_TARGET_WORD_BITSIZE == 64) +#define AH_word(X) AH4_8(X) +#define AL_word(X) AL4_8(X) +#endif +#if (WITH_TARGET_WORD_BITSIZE == 32) +#define AH_word(X) AH2_4(X) +#define AL_word(X) AL2_4(X) +#endif + + +#define A1_2(X,N) (unsigned_1*)offset_2((X), 1, (N)) + +#define A1_4(X,N) (unsigned_1*)offset_4((X), 1, (N)) +#define A2_4(X,N) (unsigned_2*)offset_4((X), 2, (N)) + +#define A1_8(X,N) (unsigned_1*)offset_8((X), 1, (N)) +#define A2_8(X,N) (unsigned_2*)offset_8((X), 2, (N)) +#define A4_8(X,N) (unsigned_4*)offset_8((X), 4, (N)) + +#define A1_16(X,N) (unsigned_1*)offset_16((X), 1, (N)) +#define A2_16(X,N) (unsigned_2*)offset_16((X), 2, (N)) +#define A4_16(X,N) (unsigned_4*)offset_16((X), 4, (N)) +#define A8_16(X,N) (unsigned_8*)offset_16((X), 8, (N)) + + + + +/* HOST Components: + + Value of sub-word within a host word quantity */ + +#define VH1_2(X) ((unsigned_1)((unsigned_2)(X) >> 8)) +#define VL1_2(X) (unsigned_1)(X) + +#define VH2_4(X) ((unsigned_2)((unsigned_4)(X) >> 16)) +#define VL2_4(X) ((unsigned_2)(X)) + +#define VH4_8(X) ((unsigned_4)((unsigned_8)(X) >> 32)) +#define VL4_8(X) ((unsigned_4)(X)) + +#define VH8_16(X) (sim_endian_split_16 ((X), 0)) +#define VL8_16(X) (sim_endian_split_16 ((X), 1)) + +#if (WITH_TARGET_WORD_BITSIZE == 64) +#define VH_word(X) VH4_8(X) +#define VL_word(X) VL4_8(X) +#endif +#if (WITH_TARGET_WORD_BITSIZE == 32) +#define VH_word(X) VH2_4(X) +#define VL_word(X) VL2_4(X) +#endif + + +#define V1_2(X,N) ((unsigned_1)((unsigned_2)(X) >> ( 8 * (1 - (N))))) + +#define V1_4(X,N) ((unsigned_1)((unsigned_4)(X) >> ( 8 * (3 - (N))))) +#define V2_4(X,N) ((unsigned_2)((unsigned_4)(X) >> (16 * (1 - (N))))) + +#define V1_8(X,N) ((unsigned_1)((unsigned_8)(X) >> ( 8 * (7 - (N))))) +#define V2_8(X,N) ((unsigned_2)((unsigned_8)(X) >> (16 * (3 - (N))))) +#define V4_8(X,N) ((unsigned_4)((unsigned_8)(X) >> (32 * (1 - (N))))) + +#define V1_16(X,N) (*A1_16 (&(X),N)) +#define V2_16(X,N) (*A2_16 (&(X),N)) +#define V4_16(X,N) (*A4_16 (&(X),N)) +#define V8_16(X,N) (*A8_16 (&(X),N)) + + +/* Reverse - insert sub-word into word quantity */ + +#define V2_H1(X) ((unsigned_2)(unsigned_1)(X) << 8) +#define V2_L1(X) ((unsigned_2)(unsigned_1)(X)) + +#define V4_H2(X) ((unsigned_4)(unsigned_2)(X) << 16) +#define V4_L2(X) ((unsigned_4)(unsigned_2)(X)) + +#define V8_H4(X) ((unsigned_8)(unsigned_4)(X) << 32) +#define V8_L4(X) ((unsigned_8)(unsigned_4)(X)) + +#define V16_H8(X) ((unsigned_16)(unsigned_8)(X) << 64) +#define V16_L8(X) ((unsigned_16)(unsigned_8)(X)) + + +#define V2_1(X,N) ((unsigned_2)(unsigned_1)(X) << ( 8 * (1 - (N)))) + +#define V4_1(X,N) ((unsigned_4)(unsigned_1)(X) << ( 8 * (3 - (N)))) +#define V4_2(X,N) ((unsigned_4)(unsigned_2)(X) << (16 * (1 - (N)))) + +#define V8_1(X,N) ((unsigned_8)(unsigned_1)(X) << ( 8 * (7 - (N)))) +#define V8_2(X,N) ((unsigned_8)(unsigned_2)(X) << (16 * (3 - (N)))) +#define V8_4(X,N) ((unsigned_8)(unsigned_4)(X) << (32 * (1 - (N)))) + +#define V16_1(X,N) ((unsigned_16)(unsigned_1)(X) << ( 8 * (15 - (N)))) +#define V16_2(X,N) ((unsigned_16)(unsigned_2)(X) << (16 * (7 - (N)))) +#define V16_4(X,N) ((unsigned_16)(unsigned_4)(X) << (32 * (3 - (N)))) +#define V16_8(X,N) ((unsigned_16)(unsigned_8)(X) << (64 * (1 - (N)))) + + +/* Reverse - insert N sub-words into single word quantity */ + +#define U2_1(I0,I1) (V2_1(I0,0) | V2_1(I1,1)) +#define U4_1(I0,I1,I2,I3) (V4_1(I0,0) | V4_1(I1,1) | V4_1(I2,2) | V4_1(I3,3)) +#define U8_1(I0,I1,I2,I3,I4,I5,I6,I7) \ +(V8_1(I0,0) | V8_1(I1,1) | V8_1(I2,2) | V8_1(I3,3) \ + | V8_1(I4,4) | V8_1(I5,5) | V8_1(I6,6) | V8_1(I7,7)) +#define U16_1(I0,I1,I2,I3,I4,I5,I6,I7,I8,I9,I10,I11,I12,I13,I14,I15) \ +(V16_1(I0,0) | V16_1(I1,1) | V16_1(I2,2) | V16_1(I3,3) \ + | V16_1(I4,4) | V16_1(I5,5) | V16_1(I6,6) | V16_1(I7,7) \ + | V16_1(I8,8) | V16_1(I9,9) | V16_1(I10,10) | V16_1(I11,11) \ + | V16_1(I12,12) | V16_1(I13,13) | V16_1(I14,14) | V16_1(I15,15)) + +#define U4_2(I0,I1) (V4_2(I0,0) | V4_2(I1,1)) +#define U8_2(I0,I1,I2,I3) (V8_2(I0,0) | V8_2(I1,1) | V8_2(I2,2) | V8_2(I3,3)) +#define U16_2(I0,I1,I2,I3,I4,I5,I6,I7) \ +(V16_2(I0,0) | V16_2(I1,1) | V16_2(I2,2) | V16_2(I3,3) \ + | V16_2(I4,4) | V16_2(I5,5) | V16_2(I6,6) | V16_2(I7,7) ) + +#define U8_4(I0,I1) (V8_4(I0,0) | V8_4(I1,1)) +#define U16_4(I0,I1,I2,I3) (V16_4(I0,0) | V16_4(I1,1) | V16_4(I2,2) | V16_4(I3,3)) + +#define U16_8(I0,I1) (sim_endian_join_16 (I0, I1)) + + +#if (WITH_TARGET_WORD_BITSIZE == 64) +#define Vword_H(X) V8_H4(X) +#define Vword_L(X) V8_L4(X) +#endif +#if (WITH_TARGET_WORD_BITSIZE == 32) +#define Vword_H(X) V4_H2(X) +#define Vword_L(X) V4_L2(X) +#endif + + + + +#if H_REVEALS_MODULE_P (SIM_ENDIAN_INLINE) +#include "sim-endian.c" +#endif + +#endif /* _SIM_ENDIAN_H_ */ diff --git a/sim/common/sim-engine.c b/sim/common/sim-engine.c new file mode 100644 index 0000000..9415f63 --- /dev/null +++ b/sim/common/sim-engine.c @@ -0,0 +1,210 @@ +/* Generic simulator halt/restart. + Copyright (C) 1997, 1998 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <stdio.h> + +#include "sim-main.h" +#include "sim-assert.h" + +/* Get the run state. + REASON/SIGRC are the values returned by sim_stop_reason. + ??? Should each cpu have its own copy? */ + +void +sim_engine_get_run_state (SIM_DESC sd, enum sim_stop *reason, int *sigrc) +{ + sim_engine *engine = STATE_ENGINE (sd); + ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + *reason = engine->reason; + *sigrc = engine->sigrc; +} + +/* Set the run state to REASON/SIGRC. + REASON/SIGRC are the values returned by sim_stop_reason. + ??? Should each cpu have its own copy? */ + +void +sim_engine_set_run_state (SIM_DESC sd, enum sim_stop reason, int sigrc) +{ + sim_engine *engine = STATE_ENGINE (sd); + ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + engine->reason = reason; + engine->sigrc = sigrc; +} + +/* Generic halt */ + +void +sim_engine_halt (SIM_DESC sd, + sim_cpu *last_cpu, + sim_cpu *next_cpu, /* NULL - use default */ + sim_cia cia, + enum sim_stop reason, + int sigrc) +{ + sim_engine *engine = STATE_ENGINE (sd); + ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + if (engine->jmpbuf != NULL) + { + jmp_buf *halt_buf = engine->jmpbuf; + engine->last_cpu = last_cpu; + engine->next_cpu = next_cpu; + engine->reason = reason; + engine->sigrc = sigrc; + + SIM_ENGINE_HALT_HOOK (sd, last_cpu, cia); + +#ifdef SIM_CPU_EXCEPTION_SUSPEND + if (last_cpu != NULL && reason != sim_exited) + SIM_CPU_EXCEPTION_SUSPEND (sd, last_cpu, sim_signal_to_host (sd, sigrc)); +#endif + + longjmp (*halt_buf, sim_engine_halt_jmpval); + } + else + sim_io_error (sd, "sim_halt - bad long jump"); +} + + +/* Generic restart */ + +void +sim_engine_restart (SIM_DESC sd, + sim_cpu *last_cpu, + sim_cpu *next_cpu, + sim_cia cia) +{ + sim_engine *engine = STATE_ENGINE (sd); + ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + if (engine->jmpbuf != NULL) + { + jmp_buf *halt_buf = engine->jmpbuf; + engine->last_cpu = last_cpu; + engine->next_cpu = next_cpu; + SIM_ENGINE_RESTART_HOOK (sd, last_cpu, cia); + longjmp (*halt_buf, sim_engine_restart_jmpval); + } + else + sim_io_error (sd, "sim_restart - bad long jump"); +} + + +/* Generic error code */ + +void +sim_engine_vabort (SIM_DESC sd, + sim_cpu *cpu, + sim_cia cia, + const char *fmt, + va_list ap) +{ + ASSERT (sd == NULL || STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + if (sd == NULL) + { + vfprintf (stderr, fmt, ap); + fprintf (stderr, "\nQuit\n"); + abort (); + } + else if (STATE_ENGINE (sd)->jmpbuf == NULL) + { + sim_io_evprintf (sd, fmt, ap); + sim_io_eprintf (sd, "\n"); + sim_io_error (sd, "Quit Simulator"); + } + else + { + sim_io_evprintf (sd, fmt, ap); + sim_io_eprintf (sd, "\n"); + sim_engine_halt (sd, cpu, NULL, cia, sim_stopped, SIM_SIGABRT); + } +} + +void +sim_engine_abort (SIM_DESC sd, + sim_cpu *cpu, + sim_cia cia, + const char *fmt, + ...) +{ + va_list ap; + ASSERT (sd == NULL || STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + va_start(ap, fmt); + sim_engine_vabort (sd, cpu, cia, fmt, ap); + va_end (ap); +} + + +/* Generic next/last cpu */ + +int +sim_engine_last_cpu_nr (SIM_DESC sd) +{ + sim_engine *engine = STATE_ENGINE (sd); + if (engine->last_cpu != NULL) + return engine->last_cpu - STATE_CPU (sd, 0); + else + return MAX_NR_PROCESSORS; +} + +int +sim_engine_next_cpu_nr (SIM_DESC sd) +{ + sim_engine *engine = STATE_ENGINE (sd); + if (engine->next_cpu != NULL) + return engine->next_cpu - STATE_CPU (sd, 0); + else + return sim_engine_last_cpu_nr (sd) + 1; +} + +int +sim_engine_nr_cpus (SIM_DESC sd) +{ + sim_engine *engine = STATE_ENGINE (sd); + return engine->nr_cpus; +} + + + + +/* Initialization */ + +static SIM_RC +sim_engine_init (SIM_DESC sd) +{ + /* initialize the start/stop/resume engine */ + sim_engine *engine = STATE_ENGINE (sd); + engine->jmpbuf = NULL; + engine->last_cpu = NULL; + engine->next_cpu = NULL; + engine->nr_cpus = MAX_NR_PROCESSORS; + engine->reason = sim_running; + engine->sigrc = 0; + engine->stepper = NULL; /* sim_events_init will clean it up */ + return SIM_RC_OK; +} + + +SIM_RC +sim_engine_install (SIM_DESC sd) +{ + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + sim_module_add_init_fn (sd, sim_engine_init); + return SIM_RC_OK; +} diff --git a/sim/common/sim-engine.h b/sim/common/sim-engine.h new file mode 100644 index 0000000..41aa51f --- /dev/null +++ b/sim/common/sim-engine.h @@ -0,0 +1,161 @@ +/* Generic simulator halt/resume. + Copyright (C) 1997, 1998 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef SIM_ENGINE_H +#define SIM_ENGINE_H + + +typedef struct _sim_engine sim_engine; +struct _sim_engine +{ + void *jmpbuf; + sim_cpu *last_cpu; + sim_cpu *next_cpu; + int nr_cpus; + enum sim_stop reason; + sim_event *stepper; + int sigrc; +}; + + + +/* jmpval: 0 (initial use) start simulator + 1 halt simulator + 2 restart simulator + This is required by the ISO C standard (the only time 0 is returned + is at the initial call to setjmp). */ + +enum { + sim_engine_start_jmpval, + sim_engine_halt_jmpval, + sim_engine_restart_jmpval, +}; + + +/* Get/set the run state of CPU to REASON/SIGRC. + REASON/SIGRC are the values returned by sim_stop_reason. */ +void sim_engine_get_run_state (SIM_DESC sd, enum sim_stop *reason, int *sigrc); +void sim_engine_set_run_state (SIM_DESC sd, enum sim_stop reason, int sigrc); + + +/* Halt the simulator *now* */ + +extern void sim_engine_halt +(SIM_DESC sd, + sim_cpu *last_cpu, /* NULL -> in event-mgr */ + sim_cpu *next_cpu, /* NULL -> succ (last_cpu) or event-mgr */ + sim_cia cia, + enum sim_stop reason, + int sigrc); + +/* Halt hook - allow target specific operation when halting a + simulator */ + +#if !defined (SIM_ENGINE_HALT_HOOK) +#define SIM_ENGINE_HALT_HOOK(SD, LAST_CPU, CIA) \ +if ((LAST_CPU) != NULL) CIA_SET (LAST_CPU, CIA) +#endif + +/* NB: If a port uses the SIM_CPU_EXCEPTION_* hooks, the default + SIM_ENGINE_HALT_HOOK and SIM_ENGINE_RESUME_HOOK must not be used. + They conflict in that the PC set by the HALT_HOOK may overwrite the + proper one, as intended to be saved by the EXCEPTION_TRIGGER + hook. */ + + +/* restart the simulator *now* */ + +extern void sim_engine_restart +(SIM_DESC sd, + sim_cpu *last_cpu, /* NULL -> in event-mgr */ + sim_cpu *next_cpu, /* NULL -> succ (last_cpu) or event-mgr */ + sim_cia cia); + +/* Restart hook - allow target specific operation when restarting a + simulator */ + +#if !defined (SIM_ENGINE_RESTART_HOOK) +#define SIM_ENGINE_RESTART_HOOK(SD, LAST_CPU, CIA) SIM_ENGINE_HALT_HOOK(SD, LAST_CPU, CIA) +#endif + + + + +/* Abort the simulator *now*. + + This function is NULL safe. It can be called when either of SD or + CIA are NULL. + + This function is setjmp/longjmp safe. It can be called when of + the sim_engine setjmp/longjmp buffer has not been established. + + Simulators that are using components such as sim-core but are not + yet using this sim-engine module should link in file sim-abort.o + which implements a non setjmp/longjmp version of + sim_engine_abort. */ + +extern void sim_engine_abort +(SIM_DESC sd, + sim_cpu *cpu, + sim_cia cia, + const char *fmt, + ...) __attribute__ ((format (printf, 4, 5))); + +extern void sim_engine_vabort +(SIM_DESC sd, + sim_cpu *cpu, + sim_cia cia, + const char *fmt, + va_list ap); + +/* No abort hook - when possible this function exits using the + engine_halt function (and SIM_ENGINE_HALT_HOOK). */ + + + + +/* Called by the generic sim_resume to run the simulation within the + above safty net. + + An example implementation of sim_engine_run can be found in the + file sim-run.c */ + +extern void sim_engine_run +(SIM_DESC sd, + int next_cpu_nr, + int nr_cpus, + int siggnal); /* most simulators ignore siggnal */ + + + +/* Determine the state of next/last cpu when the simulator was last + halted - a value >= MAX_NR_PROCESSORS indicates that the + event-queue was next/last. */ + +extern int sim_engine_next_cpu_nr (SIM_DESC sd); +extern int sim_engine_last_cpu_nr (SIM_DESC sd); +extern int sim_engine_nr_cpus (SIM_DESC sd); + + +/* Establish the simulator engine */ +MODULE_INSTALL_FN sim_engine_install; + + +#endif diff --git a/sim/common/sim-events.c b/sim/common/sim-events.c new file mode 100644 index 0000000..4b7d9b4 --- /dev/null +++ b/sim/common/sim-events.c @@ -0,0 +1,1188 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef _SIM_EVENTS_C_ +#define _SIM_EVENTS_C_ + +#include "sim-main.h" +#include "sim-assert.h" + +#ifdef HAVE_STRING_H +#include <string.h> +#else +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#endif + +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif + +#include <signal.h> /* For SIGPROCMASK et.al. */ + +#if __CYGWIN32__ +/* The ui_loop_hook is called to keep the GUI alive while the simulator + is running. The counter is to make sure we do not wake it too often. +*/ + +extern void (*ui_loop_hook) PARAMS ((int)); +static unsigned int ui_loop_hook_counter = 0; +#endif + +typedef enum { + watch_invalid, + + /* core - target byte order */ + watch_core_targ_1, + watch_core_targ_2, + watch_core_targ_4, + watch_core_targ_8, + /* core - big-endian */ + watch_core_be_1, + watch_core_be_2, + watch_core_be_4, + watch_core_be_8, + /* core - little-endian */ + watch_core_le_1, + watch_core_le_2, + watch_core_le_4, + watch_core_le_8, + + /* sim - host byte order */ + watch_sim_host_1, + watch_sim_host_2, + watch_sim_host_4, + watch_sim_host_8, + /* sim - big-endian */ + watch_sim_be_1, + watch_sim_be_2, + watch_sim_be_4, + watch_sim_be_8, + /* sim - little-endian */ + watch_sim_le_1, + watch_sim_le_2, + watch_sim_le_4, + watch_sim_le_8, + + /* wallclock */ + watch_clock, + + /* timer */ + watch_timer, +} sim_event_watchpoints; + + +struct _sim_event { + sim_event_watchpoints watching; + void *data; + sim_event_handler *handler; + /* timer event */ + signed64 time_of_event; + /* watch wallclock event */ + unsigned wallclock; + /* watch core address */ + address_word core_addr; + unsigned core_map; + /* watch sim addr */ + void *host_addr; + /* watch core/sim range */ + int is_within; /* 0/1 */ + unsigned ub; + unsigned lb; + unsigned64 ub64; + unsigned64 lb64; + /* trace info (if any) */ + char *trace; + /* list */ + sim_event *next; +}; + + +/* The event queue maintains a single absolute time using two + variables. + + TIME_OF_EVENT: this holds the time at which the next event is ment + to occure. If no next event it will hold the time of the last + event. + + TIME_FROM_EVENT: The current distance from TIME_OF_EVENT. A value + <= 0 (except when poll-event is being processed) indicates that + event processing is due. This variable is decremented once for + each iteration of a clock cycle. + + Initially, the clock is started at time one (0) with TIME_OF_EVENT + == 0 and TIME_FROM_EVENT == 0 and with NR_TICKS_TO_PROCESS == 1. + + Clearly there is a bug in that this code assumes that the absolute + time counter will never become greater than 2^62. + + To avoid the need to use 64bit arithmetic, the event queue always + contains at least one event scheduled every 16 000 ticks. This + limits the time from event counter to values less than + 16 000. */ + + +#if !defined (SIM_EVENTS_POLL_RATE) +#define SIM_EVENTS_POLL_RATE 0x1000 +#endif + + +#define _ETRACE sd, NULL + +#undef ETRACE_P +#define ETRACE_P (WITH_TRACE && STATE_EVENTS (sd)->trace) + +#undef ETRACE +#define ETRACE(ARGS) \ +do \ + { \ + if (ETRACE_P) \ + { \ + if (STRACE_DEBUG_P (sd)) \ + { \ + const char *file; \ + SIM_FILTER_PATH (file, __FILE__); \ + trace_printf (sd, NULL, "%s:%d: ", file, __LINE__); \ + } \ + trace_printf ARGS; \ + } \ + } \ +while (0) + + +/* event queue iterator - don't iterate over the held queue. */ + +#if EXTERN_SIM_EVENTS_P +static sim_event ** +next_event_queue (SIM_DESC sd, + sim_event **queue) +{ + if (queue == NULL) + return &STATE_EVENTS (sd)->queue; + else if (queue == &STATE_EVENTS (sd)->queue) + return &STATE_EVENTS (sd)->watchpoints; + else if (queue == &STATE_EVENTS (sd)->watchpoints) + return &STATE_EVENTS (sd)->watchedpoints; + else if (queue == &STATE_EVENTS (sd)->watchedpoints) + return NULL; + else + sim_io_error (sd, "next_event_queue - bad queue"); + return NULL; +} +#endif + + +STATIC_INLINE_SIM_EVENTS\ +(void) +sim_events_poll (SIM_DESC sd, + void *data) +{ + /* just re-schedule in 1000 million ticks time */ + sim_events_schedule (sd, SIM_EVENTS_POLL_RATE, sim_events_poll, sd); + sim_io_poll_quit (sd); +} + + +/* "events" module install handler. + This is called via sim_module_install to install the "events" subsystem + into the simulator. */ + +#if EXTERN_SIM_EVENTS_P +STATIC_SIM_EVENTS (MODULE_UNINSTALL_FN) sim_events_uninstall; +STATIC_SIM_EVENTS (MODULE_INIT_FN) sim_events_init; +STATIC_SIM_EVENTS (MODULE_RESUME_FN) sim_events_resume; +STATIC_SIM_EVENTS (MODULE_SUSPEND_FN) sim_events_suspend; +#endif + +#if EXTERN_SIM_EVENTS_P +SIM_RC +sim_events_install (SIM_DESC sd) +{ + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + sim_module_add_uninstall_fn (sd, sim_events_uninstall); + sim_module_add_init_fn (sd, sim_events_init); + sim_module_add_resume_fn (sd, sim_events_resume); + sim_module_add_suspend_fn (sd, sim_events_suspend); + return SIM_RC_OK; +} +#endif + + +/* Suspend/resume the event queue manager when the simulator is not + running */ + +#if EXTERN_SIM_EVENTS_P +static SIM_RC +sim_events_resume (SIM_DESC sd) +{ + sim_events *events = STATE_EVENTS (sd); + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + SIM_ASSERT (events->resume_wallclock == 0); + events->resume_wallclock = sim_elapsed_time_get (); + return SIM_RC_OK; +} +#endif + +#if EXTERN_SIM_EVENTS_P +static SIM_RC +sim_events_suspend (SIM_DESC sd) +{ + sim_events *events = STATE_EVENTS (sd); + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + SIM_ASSERT (events->resume_wallclock != 0); + events->elapsed_wallclock += sim_elapsed_time_since (events->resume_wallclock); + events->resume_wallclock = 0; + return SIM_RC_OK; +} +#endif + + +/* Uninstall the "events" subsystem from the simulator. */ + +#if EXTERN_SIM_EVENTS_P +static void +sim_events_uninstall (SIM_DESC sd) +{ + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + /* FIXME: free buffers, etc. */ +} +#endif + + +/* malloc/free */ + +#if EXTERN_SIM_EVENTS_P +static sim_event * +sim_events_zalloc (SIM_DESC sd) +{ + sim_events *events = STATE_EVENTS (sd); + sim_event *new = events->free_list; + if (new != NULL) + { + events->free_list = new->next; + memset (new, 0, sizeof (*new)); + } + else + { +#if defined (HAVE_SIGPROCMASK) && defined (SIG_SETMASK) + /*-LOCK-*/ + sigset_t old_mask; + sigset_t new_mask; + sigfillset(&new_mask); + sigprocmask (SIG_SETMASK, &new_mask, &old_mask); +#endif + new = ZALLOC (sim_event); +#if defined (HAVE_SIGPROCMASK) && defined (SIG_SETMASK) + /*-UNLOCK-*/ + sigprocmask (SIG_SETMASK, &old_mask, NULL); +#endif + } + return new; +} +#endif + +STATIC_INLINE_SIM_EVENTS\ +(void) +sim_events_free (SIM_DESC sd, + sim_event *dead) +{ + sim_events *events = STATE_EVENTS (sd); + dead->next = events->free_list; + events->free_list = dead; + if (dead->trace != NULL) + { + free (dead->trace); /* NB: asprintf returns a `free' buf */ + dead->trace = NULL; + } +} + + +/* Initialize the simulator event manager */ + +#if EXTERN_SIM_EVENTS_P +SIM_RC +sim_events_init (SIM_DESC sd) +{ + sim_events *events = STATE_EVENTS (sd); + + /* drain the interrupt queue */ + events->nr_held = 0; + if (events->held == NULL) + events->held = NZALLOC (sim_event, MAX_NR_SIGNAL_SIM_EVENTS); + + /* drain the normal queues */ + { + sim_event **queue = NULL; + while ((queue = next_event_queue (sd, queue)) != NULL) + { + if (queue == NULL) break; + while (*queue != NULL) + { + sim_event *dead = *queue; + *queue = dead->next; + sim_events_free (sd, dead); + } + *queue = NULL; + } + } + + /* wind time back to zero */ + events->nr_ticks_to_process = 1; /* start by doing queue */ + events->time_of_event = 0; + events->time_from_event = 0; + events->elapsed_wallclock = 0; + events->resume_wallclock = 0; + + /* schedule our initial counter event */ + sim_events_schedule (sd, 0, sim_events_poll, sd); + + /* from now on, except when the large-int event is being processed + the event queue is non empty */ + SIM_ASSERT (events->queue != NULL); + + return SIM_RC_OK; +} +#endif + + +INLINE_SIM_EVENTS\ +(signed64) +sim_events_time (SIM_DESC sd) +{ + sim_events *events = STATE_EVENTS (sd); + return (events->time_of_event - events->time_from_event); +} + + +INLINE_SIM_EVENTS\ +(unsigned long) +sim_events_elapsed_time (SIM_DESC sd) +{ + unsigned long elapsed = STATE_EVENTS (sd)->elapsed_wallclock; + + /* Are we being called inside sim_resume? + (Is there a simulation in progress?) */ + if (STATE_EVENTS (sd)->resume_wallclock != 0) + elapsed += sim_elapsed_time_since (STATE_EVENTS (sd)->resume_wallclock); + + return elapsed; +} + + +STATIC_INLINE_SIM_EVENTS\ +(void) +update_time_from_event (SIM_DESC sd) +{ + sim_events *events = STATE_EVENTS (sd); + signed64 current_time = sim_events_time (sd); + if (events->queue != NULL) + { + events->time_of_event = events->queue->time_of_event; + events->time_from_event = (events->queue->time_of_event - current_time); + } + else + { + events->time_of_event = current_time - 1; + events->time_from_event = -1; + } + SIM_ASSERT (current_time == sim_events_time (sd)); +} + + +#if EXTERN_SIM_EVENTS_P +static void +insert_sim_event (SIM_DESC sd, + sim_event *new_event, + signed64 delta) +{ + sim_events *events = STATE_EVENTS (sd); + sim_event *curr; + sim_event **prev; + signed64 time_of_event; + + if (delta < 0) + sim_io_error (sd, "what is past is past!\n"); + + /* compute when the event should occure */ + time_of_event = sim_events_time (sd) + delta; + + /* find the queue insertion point - things are time ordered */ + prev = &events->queue; + curr = events->queue; + while (curr != NULL && time_of_event >= curr->time_of_event) + { + SIM_ASSERT (curr->next == NULL + || curr->time_of_event <= curr->next->time_of_event); + prev = &curr->next; + curr = curr->next; + } + SIM_ASSERT (curr == NULL || time_of_event < curr->time_of_event); + + /* insert it */ + new_event->next = curr; + *prev = new_event; + new_event->time_of_event = time_of_event; + + /* adjust the time until the first event */ + update_time_from_event (sd); +} +#endif + + +#if EXTERN_SIM_EVENTS_P +sim_event * +sim_events_schedule (SIM_DESC sd, + signed64 delta_time, + sim_event_handler *handler, + void *data) +{ + va_list dummy; + return sim_events_schedule_vtracef (sd, delta_time, handler, data, + NULL, dummy); +} +#endif + + +#if EXTERN_SIM_EVENTS_P +sim_event * +sim_events_schedule_tracef (SIM_DESC sd, + signed64 delta_time, + sim_event_handler *handler, + void *data, + const char *fmt, + ...) +{ + sim_event *new_event; + va_list ap; + va_start (ap, fmt); + new_event = sim_events_schedule_vtracef (sd, delta_time, handler, data, fmt, ap); + va_end (ap); + return new_event; +} +#endif + + +#if EXTERN_SIM_EVENTS_P +sim_event * +sim_events_schedule_vtracef (SIM_DESC sd, + signed64 delta_time, + sim_event_handler *handler, + void *data, + const char *fmt, + va_list ap) +{ + sim_event *new_event = sim_events_zalloc (sd); + new_event->data = data; + new_event->handler = handler; + new_event->watching = watch_timer; + if (fmt == NULL || !ETRACE_P || vasprintf (&new_event->trace, fmt, ap) < 0) + new_event->trace = NULL; + insert_sim_event(sd, new_event, delta_time); + ETRACE((_ETRACE, + "event scheduled at %ld - tag 0x%lx - time %ld, handler 0x%lx, data 0x%lx%s%s\n", + (long)sim_events_time(sd), + (long)new_event, + (long)new_event->time_of_event, + (long)new_event->handler, + (long)new_event->data, + (new_event->trace != NULL) ? ", " : "", + (new_event->trace != NULL) ? new_event->trace : "")); + return new_event; +} +#endif + + +#if EXTERN_SIM_EVENTS_P +void +sim_events_schedule_after_signal (SIM_DESC sd, + signed64 delta_time, + sim_event_handler *handler, + void *data) +{ + sim_events *events = STATE_EVENTS (sd); + sim_event *new_event; +#if defined (HAVE_SIGPROCMASK) && defined (SIG_SETMASK) + /*-LOCK-*/ + sigset_t old_mask; + sigset_t new_mask; + sigfillset(&new_mask); + sigprocmask (SIG_SETMASK, &new_mask, &old_mask); +#endif + + /* allocate an event entry from the signal buffer */ + new_event = &events->held [events->nr_held]; + events->nr_held ++; + if (events->nr_held > MAX_NR_SIGNAL_SIM_EVENTS) + { + sim_engine_abort (NULL, NULL, NULL_CIA, + "sim_events_schedule_after_signal - buffer oveflow"); + } + + new_event->data = data; + new_event->handler = handler; + new_event->time_of_event = delta_time; /* work it out later */ + new_event->next = NULL; + + events->work_pending = 1; /* notify main process */ + +#if defined (HAVE_SIGPROCMASK) && defined (SIG_SETMASK) + /*-UNLOCK-*/ + sigprocmask (SIG_SETMASK, &old_mask, NULL); +#endif + + ETRACE ((_ETRACE, + "signal scheduled at %ld - tag 0x%lx - time %ld, handler 0x%lx, data 0x%lx\n", + (long)sim_events_time(sd), + (long)new_event, + (long)new_event->time_of_event, + (long)new_event->handler, + (long)new_event->data)); +} +#endif + + +#if EXTERN_SIM_EVENTS_P +sim_event * +sim_events_watch_clock (SIM_DESC sd, + unsigned delta_ms_time, + sim_event_handler *handler, + void *data) +{ + sim_events *events = STATE_EVENTS (sd); + sim_event *new_event = sim_events_zalloc (sd); + /* type */ + new_event->watching = watch_clock; + /* handler */ + new_event->data = data; + new_event->handler = handler; + /* data */ + if (events->resume_wallclock == 0) + new_event->wallclock = (events->elapsed_wallclock + delta_ms_time); + else + new_event->wallclock = (events->elapsed_wallclock + + sim_elapsed_time_since (events->resume_wallclock) + + delta_ms_time); + /* insert */ + new_event->next = events->watchpoints; + events->watchpoints = new_event; + events->work_pending = 1; + ETRACE ((_ETRACE, + "event watching clock at %ld - tag 0x%lx - wallclock %ld, handler 0x%lx, data 0x%lx\n", + (long)sim_events_time (sd), + (long)new_event, + (long)new_event->wallclock, + (long)new_event->handler, + (long)new_event->data)); + return new_event; +} +#endif + + +#if EXTERN_SIM_EVENTS_P +sim_event * +sim_events_watch_sim (SIM_DESC sd, + void *host_addr, + int nr_bytes, + int byte_order, + int is_within, + unsigned64 lb, + unsigned64 ub, + sim_event_handler *handler, + void *data) +{ + sim_events *events = STATE_EVENTS (sd); + sim_event *new_event = sim_events_zalloc (sd); + /* type */ + switch (byte_order) + { + case 0: + switch (nr_bytes) + { + case 1: new_event->watching = watch_sim_host_1; break; + case 2: new_event->watching = watch_sim_host_2; break; + case 4: new_event->watching = watch_sim_host_4; break; + case 8: new_event->watching = watch_sim_host_8; break; + default: sim_io_error (sd, "sim_events_watch_sim - invalid nr bytes"); + } + break; + case BIG_ENDIAN: + switch (nr_bytes) + { + case 1: new_event->watching = watch_sim_be_1; break; + case 2: new_event->watching = watch_sim_be_2; break; + case 4: new_event->watching = watch_sim_be_4; break; + case 8: new_event->watching = watch_sim_be_8; break; + default: sim_io_error (sd, "sim_events_watch_sim - invalid nr bytes"); + } + break; + case LITTLE_ENDIAN: + switch (nr_bytes) + { + case 1: new_event->watching = watch_sim_le_1; break; + case 2: new_event->watching = watch_sim_le_2; break; + case 4: new_event->watching = watch_sim_le_4; break; + case 8: new_event->watching = watch_sim_le_8; break; + default: sim_io_error (sd, "sim_events_watch_sim - invalid nr bytes"); + } + break; + default: + sim_io_error (sd, "sim_events_watch_sim - invalid byte order"); + } + /* handler */ + new_event->data = data; + new_event->handler = handler; + /* data */ + new_event->host_addr = host_addr; + new_event->lb = lb; + new_event->lb64 = lb; + new_event->ub = ub; + new_event->ub64 = ub; + new_event->is_within = (is_within != 0); + /* insert */ + new_event->next = events->watchpoints; + events->watchpoints = new_event; + events->work_pending = 1; + ETRACE ((_ETRACE, + "event watching host at %ld - tag 0x%lx - host-addr 0x%lx, 0x%lx..0x%lx, handler 0x%lx, data 0x%lx\n", + (long)sim_events_time (sd), + (long)new_event, + (long)new_event->host_addr, + (long)new_event->lb, + (long)new_event->ub, + (long)new_event->handler, + (long)new_event->data)); + return new_event; +} +#endif + + +#if EXTERN_SIM_EVENTS_P +sim_event * +sim_events_watch_core (SIM_DESC sd, + address_word core_addr, + unsigned core_map, + int nr_bytes, + int byte_order, + int is_within, + unsigned64 lb, + unsigned64 ub, + sim_event_handler *handler, + void *data) +{ + sim_events *events = STATE_EVENTS (sd); + sim_event *new_event = sim_events_zalloc (sd); + /* type */ + switch (byte_order) + { + case 0: + switch (nr_bytes) + { + case 1: new_event->watching = watch_core_targ_1; break; + case 2: new_event->watching = watch_core_targ_2; break; + case 4: new_event->watching = watch_core_targ_4; break; + case 8: new_event->watching = watch_core_targ_8; break; + default: sim_io_error (sd, "sim_events_watch_core - invalid nr bytes"); + } + break; + case BIG_ENDIAN: + switch (nr_bytes) + { + case 1: new_event->watching = watch_core_be_1; break; + case 2: new_event->watching = watch_core_be_2; break; + case 4: new_event->watching = watch_core_be_4; break; + case 8: new_event->watching = watch_core_be_8; break; + default: sim_io_error (sd, "sim_events_watch_core - invalid nr bytes"); + } + break; + case LITTLE_ENDIAN: + switch (nr_bytes) + { + case 1: new_event->watching = watch_core_le_1; break; + case 2: new_event->watching = watch_core_le_2; break; + case 4: new_event->watching = watch_core_le_4; break; + case 8: new_event->watching = watch_core_le_8; break; + default: sim_io_error (sd, "sim_events_watch_core - invalid nr bytes"); + } + break; + default: + sim_io_error (sd, "sim_events_watch_core - invalid byte order"); + } + /* handler */ + new_event->data = data; + new_event->handler = handler; + /* data */ + new_event->core_addr = core_addr; + new_event->core_map = core_map; + new_event->lb = lb; + new_event->lb64 = lb; + new_event->ub = ub; + new_event->ub64 = ub; + new_event->is_within = (is_within != 0); + /* insert */ + new_event->next = events->watchpoints; + events->watchpoints = new_event; + events->work_pending = 1; + ETRACE ((_ETRACE, + "event watching host at %ld - tag 0x%lx - host-addr 0x%lx, 0x%lx..0x%lx, handler 0x%lx, data 0x%lx\n", + (long)sim_events_time (sd), + (long)new_event, + (long)new_event->host_addr, + (long)new_event->lb, + (long)new_event->ub, + (long)new_event->handler, + (long)new_event->data)); + return new_event; +} +#endif + + +#if EXTERN_SIM_EVENTS_P +void +sim_events_deschedule (SIM_DESC sd, + sim_event *event_to_remove) +{ + sim_events *events = STATE_EVENTS (sd); + sim_event *to_remove = (sim_event*)event_to_remove; + if (event_to_remove != NULL) + { + sim_event **queue = NULL; + while ((queue = next_event_queue (sd, queue)) != NULL) + { + sim_event **ptr_to_current; + for (ptr_to_current = queue; + *ptr_to_current != NULL && *ptr_to_current != to_remove; + ptr_to_current = &(*ptr_to_current)->next); + if (*ptr_to_current == to_remove) + { + sim_event *dead = *ptr_to_current; + *ptr_to_current = dead->next; + ETRACE ((_ETRACE, + "event/watch descheduled at %ld - tag 0x%lx - time %ld, handler 0x%lx, data 0x%lx%s%s\n", + (long) sim_events_time (sd), + (long) event_to_remove, + (long) dead->time_of_event, + (long) dead->handler, + (long) dead->data, + (dead->trace != NULL) ? ", " : "", + (dead->trace != NULL) ? dead->trace : "")); + sim_events_free (sd, dead); + update_time_from_event (sd); + SIM_ASSERT ((events->time_from_event >= 0) == (events->queue != NULL)); + return; + } + } + } + ETRACE ((_ETRACE, + "event/watch descheduled at %ld - tag 0x%lx - not found\n", + (long) sim_events_time (sd), + (long) event_to_remove)); +} +#endif + + +STATIC_INLINE_SIM_EVENTS\ +(int) +sim_watch_valid (SIM_DESC sd, + sim_event *to_do) +{ + switch (to_do->watching) + { + +#define WATCH_CORE(N,OP,EXT) \ + int ok; \ + unsigned_##N word = 0; \ + int nr_read = sim_core_read_buffer (sd, NULL, to_do->core_map, &word, \ + to_do->core_addr, sizeof (word)); \ + OP (word); \ + ok = (nr_read == sizeof (unsigned_##N) \ + && (to_do->is_within \ + == (word >= to_do->lb##EXT \ + && word <= to_do->ub##EXT))); + + case watch_core_targ_1: + { + WATCH_CORE (1, T2H,); + return ok; + } + case watch_core_targ_2: + { + WATCH_CORE (2, T2H,); + return ok; + } + case watch_core_targ_4: + { + WATCH_CORE (4, T2H,); + return ok; + } + case watch_core_targ_8: + { + WATCH_CORE (8, T2H,64); + return ok; + } + + case watch_core_be_1: + { + WATCH_CORE (1, BE2H,); + return ok; + } + case watch_core_be_2: + { + WATCH_CORE (2, BE2H,); + return ok; + } + case watch_core_be_4: + { + WATCH_CORE (4, BE2H,); + return ok; + } + case watch_core_be_8: + { + WATCH_CORE (8, BE2H,64); + return ok; + } + + case watch_core_le_1: + { + WATCH_CORE (1, LE2H,); + return ok; + } + case watch_core_le_2: + { + WATCH_CORE (2, LE2H,); + return ok; + } + case watch_core_le_4: + { + WATCH_CORE (4, LE2H,); + return ok; + } + case watch_core_le_8: + { + WATCH_CORE (8, LE2H,64); + return ok; + } +#undef WATCH_CORE + +#define WATCH_SIM(N,OP,EXT) \ + int ok; \ + unsigned_##N word = *(unsigned_##N*)to_do->host_addr; \ + OP (word); \ + ok = (to_do->is_within \ + == (word >= to_do->lb##EXT \ + && word <= to_do->ub##EXT)); + + case watch_sim_host_1: + { + WATCH_SIM (1, word = ,); + return ok; + } + case watch_sim_host_2: + { + WATCH_SIM (2, word = ,); + return ok; + } + case watch_sim_host_4: + { + WATCH_SIM (4, word = ,); + return ok; + } + case watch_sim_host_8: + { + WATCH_SIM (8, word = ,64); + return ok; + } + + case watch_sim_be_1: + { + WATCH_SIM (1, BE2H,); + return ok; + } + case watch_sim_be_2: + { + WATCH_SIM (2, BE2H,); + return ok; + } + case watch_sim_be_4: + { + WATCH_SIM (4, BE2H,); + return ok; + } + case watch_sim_be_8: + { + WATCH_SIM (8, BE2H,64); + return ok; + } + + case watch_sim_le_1: + { + WATCH_SIM (1, LE2H,); + return ok; + } + case watch_sim_le_2: + { + WATCH_SIM (1, LE2H,); + return ok; + } + case watch_sim_le_4: + { + WATCH_SIM (1, LE2H,); + return ok; + } + case watch_sim_le_8: + { + WATCH_SIM (1, LE2H,64); + return ok; + } +#undef WATCH_SIM + + case watch_clock: /* wallclock */ + { + unsigned long elapsed_time = sim_events_elapsed_time (sd); + return (elapsed_time >= to_do->wallclock); + } + + default: + sim_io_error (sd, "sim_watch_valid - bad switch"); + break; + + } + return 1; +} + + +INLINE_SIM_EVENTS\ +(int) +sim_events_tick (SIM_DESC sd) +{ + sim_events *events = STATE_EVENTS (sd); + + /* this should only be called after the previous ticks have been + fully processed */ + + /* Advance the time but *only* if there is nothing to process */ + if (events->work_pending + || events->time_from_event == 0) + { + events->nr_ticks_to_process += 1; + return 1; + } + else + { + events->time_from_event -= 1; + return 0; + } +} + + +INLINE_SIM_EVENTS\ +(int) +sim_events_tickn (SIM_DESC sd, + int n) +{ + sim_events *events = STATE_EVENTS (sd); + SIM_ASSERT (n > 0); + + /* this should only be called after the previous ticks have been + fully processed */ + + /* Advance the time but *only* if there is nothing to process */ + if (events->work_pending || events->time_from_event < n) + { + events->nr_ticks_to_process += n; + return 1; + } + else + { + events->time_from_event -= n; + return 0; + } +} + + +INLINE_SIM_EVENTS\ +(void) +sim_events_slip (SIM_DESC sd, + int slip) +{ + sim_events *events = STATE_EVENTS (sd); + SIM_ASSERT (slip > 0); + + /* Flag a ready event with work_pending instead of number of ticks + to process so that the time continues to be correct */ + if (events->time_from_event < slip) + { + events->work_pending = 1; + } + events->time_from_event -= slip; +} + + +INLINE_SIM_EVENTS\ +(void) +sim_events_preprocess (SIM_DESC sd, + int events_were_last, + int events_were_next) +{ + sim_events *events = STATE_EVENTS(sd); + if (events_were_last) + { + /* Halted part way through event processing */ + ASSERT (events->nr_ticks_to_process != 0); + /* The external world can't tell if the event that stopped the + simulator was the last event to process. */ + ASSERT (events_were_next); + sim_events_process (sd); + } + else if (events_were_next) + { + /* Halted by the last processor */ + if (sim_events_tick (sd)) + sim_events_process (sd); + } +} + + +INLINE_SIM_EVENTS\ +(void) +sim_events_process (SIM_DESC sd) +{ + sim_events *events = STATE_EVENTS(sd); + signed64 event_time = sim_events_time(sd); + + /* Clear work_pending before checking nr_held. Clearing + work_pending after nr_held (with out a lock could loose an + event). */ + events->work_pending = 0; + + /* move any events that were asynchronously queued by any signal + handlers onto the real event queue. */ + if (events->nr_held > 0) + { + int i; + +#if defined(HAVE_SIGPROCMASK) && defined(SIG_SETMASK) + /*-LOCK-*/ + sigset_t old_mask; + sigset_t new_mask; + sigfillset(&new_mask); + sigprocmask(SIG_SETMASK, &new_mask, &old_mask); +#endif + + for (i = 0; i < events->nr_held; i++) + { + sim_event *entry = &events->held [i]; + sim_events_schedule (sd, + entry->time_of_event, + entry->handler, + entry->data); + } + events->nr_held = 0; + +#if defined(HAVE_SIGPROCMASK) && defined(SIG_SETMASK) + /*-UNLOCK-*/ + sigprocmask(SIG_SETMASK, &old_mask, NULL); +#endif + + } + + /* Process any watchpoints. Be careful to allow a watchpoint to + appear/disappear under our feet. + To ensure that watchpoints are processed only once per cycle, + they are moved onto a watched queue, this returned to the + watchpoint queue when all queue processing has been + completed. */ + while (events->watchpoints != NULL) + { + sim_event *to_do = events->watchpoints; + events->watchpoints = to_do->next; + if (sim_watch_valid (sd, to_do)) + { + sim_event_handler *handler = to_do->handler; + void *data = to_do->data; + ETRACE((_ETRACE, + "event issued at %ld - tag 0x%lx - handler 0x%lx, data 0x%lx%s%s\n", + (long) event_time, + (long) to_do, + (long) handler, + (long) data, + (to_do->trace != NULL) ? ", " : "", + (to_do->trace != NULL) ? to_do->trace : "")); + sim_events_free (sd, to_do); + handler (sd, data); + } + else + { + to_do->next = events->watchedpoints; + events->watchedpoints = to_do; + } + } + + /* consume all events for this or earlier times. Be careful to + allow an event to appear/disappear under our feet */ + while (events->queue->time_of_event < + (event_time + events->nr_ticks_to_process)) + { + sim_event *to_do = events->queue; + sim_event_handler *handler = to_do->handler; + void *data = to_do->data; + events->queue = to_do->next; + update_time_from_event (sd); + ETRACE((_ETRACE, + "event issued at %ld - tag 0x%lx - handler 0x%lx, data 0x%lx%s%s\n", + (long) event_time, + (long) to_do, + (long) handler, + (long) data, + (to_do->trace != NULL) ? ", " : "", + (to_do->trace != NULL) ? to_do->trace : "")); + sim_events_free (sd, to_do); + handler (sd, data); + } + + /* put things back where they belong ready for the next iteration */ + events->watchpoints = events->watchedpoints; + events->watchedpoints = NULL; + if (events->watchpoints != NULL) + events->work_pending = 1; + + /* advance the time */ + SIM_ASSERT (events->time_from_event >= events->nr_ticks_to_process); + SIM_ASSERT (events->queue != NULL); /* always poll event */ + events->time_from_event -= events->nr_ticks_to_process; + + /* this round of processing complete */ + events->nr_ticks_to_process = 0; + +#if __CYGWIN32__ + /* Now call the ui_loop_hook to give the gui a chance to + process events. */ + + if (ui_loop_hook != NULL) + { + /* attempt to limit calls to 1-10 per second */ + if (! (ui_loop_hook_counter++ & 0xf)) + (*ui_loop_hook) (-2); /* magic */ + } +#endif +} + +#endif diff --git a/sim/common/sim-events.h b/sim/common/sim-events.h new file mode 100644 index 0000000..3bae3df --- /dev/null +++ b/sim/common/sim-events.h @@ -0,0 +1,271 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef SIM_EVENTS_H +#define SIM_EVENTS_H + + +/* Notes: + + When scheduling an event, the a delta of zero/one refers to the + timeline as follows: + + epoch 0|1 1|2 2|3 3| + **queue**|--insn--|*queue*|--insn--|*queue*|--insn--|*queue*| + | ^ ^ | ^ ^ + `- +0 ------------ +1 --.. `----- +0 ------------- +1 --.. + + When the queue is initialized, the time is set to zero with a + number of initialization events scheduled. Consequently, as also + illustrated above, the event queue should be processed before the + first instruction. That instruction being executed during tick 1. + + The simulator main loop may take a form similar to: + + if (halt-/restart-setjmp) + { + + .... // Determine who should go next + last-cpu-nr = get-last-cpu-nr (sd); + next-cpu-nr = get-next-cpu-nr (sd); + events-were-last? = (last-cpu-nr >= nr-cpus); + events-were-next? = (next-cpu-nr >= nr-cpus); + + .... // process any outstanding events + sim_events_preprocess (sd, events-were-last?, events-were-next?); + if (events-were-next) + next-cpu-nr = 0; + + .... // prime main loop + + while (1) + { + .... // model one insn of next-cpu-nr .. nr-cpus + if (sim_events_tick (sd)) + sim_events_process (sd); + next-cpu-nr = 0 + } + } + + NB. In the above pseudo code it is assumed that any cpu-nr >= + nr-cpus is a marker for the event queue. */ + + +typedef void sim_event_handler(SIM_DESC sd, void *data); + +typedef struct _sim_event sim_event; + +typedef struct _sim_events sim_events; +struct _sim_events { + int nr_ticks_to_process; + sim_event *queue; + sim_event *watchpoints; + sim_event *watchedpoints; + sim_event *free_list; + /* flag additional work needed */ + volatile int work_pending; + /* the asynchronous event queue */ +#ifndef MAX_NR_SIGNAL_SIM_EVENTS +#define MAX_NR_SIGNAL_SIM_EVENTS 2 +#endif + sim_event *held; + volatile int nr_held; + /* timekeeping */ + unsigned long elapsed_wallclock; + SIM_ELAPSED_TIME resume_wallclock; + signed64 time_of_event; + int time_from_event; + int trace; +}; + + + +/* Install the "events" module. */ + +extern SIM_RC sim_events_install (SIM_DESC sd); + + +/* Schedule an event DELTA_TIME ticks into the future */ + +extern sim_event *sim_events_schedule +(SIM_DESC sd, + signed64 delta_time, + sim_event_handler *handler, + void *data); + +extern sim_event *sim_events_schedule_tracef +(SIM_DESC sd, + signed64 delta_time, + sim_event_handler *handler, + void *data, + const char *fmt, + ...) __attribute__ ((format (printf, 5, 6))); + +extern sim_event *sim_events_schedule_vtracef +(SIM_DESC sd, + signed64 delta_time, + sim_event_handler *handler, + void *data, + const char *fmt, + va_list ap); + + +extern void sim_events_schedule_after_signal +(SIM_DESC sd, + signed64 delta_time, + sim_event_handler *handler, + void *data); + +/* NB: signal level events can't have trace strings as malloc isn't + available */ + + + +/* Schedule an event milli-seconds from NOW. The exact interpretation + of wallclock is host dependant. */ + +extern sim_event *sim_events_watch_clock +(SIM_DESC sd, + unsigned delta_ms_time, + sim_event_handler *handler, + void *data); + + +/* Schedule an event when the test (IS_WITHIN == (VAL >= LB && VAL <= + UB)) of the NR_BYTES value at HOST_ADDR with BYTE_ORDER endian is + true. + + HOST_ADDR: pointer into the host address space. + BYTE_ORDER: 0 - host endian; BIG_ENDIAN; LITTLE_ENDIAN */ + +extern sim_event *sim_events_watch_sim +(SIM_DESC sd, + void *host_addr, + int nr_bytes, + int byte_order, + int is_within, + unsigned64 lb, + unsigned64 ub, + sim_event_handler *handler, + void *data); + + +/* Schedule an event when the test (IS_WITHIN == (VAL >= LB && VAL <= + UB)) of the NR_BYTES value at CORE_ADDR in BYTE_ORDER endian is + true. + + CORE_ADDR/MAP: pointer into the target address space. + BYTE_ORDER: 0 - current target endian; BIG_ENDIAN; LITTLE_ENDIAN */ + +extern sim_event *sim_events_watch_core +(SIM_DESC sd, + address_word core_addr, + unsigned map, + int nr_bytes, + int byte_order, + int is_within, + unsigned64 lb, + unsigned64 ub, + sim_event_handler *handler, + void *data); + +/* Deschedule the specified event */ + +extern void sim_events_deschedule +(SIM_DESC sd, + sim_event *event_to_remove); + + +/* Prepare for main simulator loop. Ensure that the next thing to do + is not event processing. + + If the simulator halted part way through event processing then both + EVENTS_WERE_LAST and EVENTS_WERE_NEXT shall be true. + + If the simulator halted after processing the last cpu, then only + EVENTS_WERE_NEXT shall be true. */ + +INLINE_SIM_EVENTS\ +(void) sim_events_preprocess +(SIM_DESC sd, + int events_were_last, + int events_were_next); + + +/* Progress time. + + Separated into two parts so that the main loop can save its context + before the event queue is processed. When sim_events_tick*() + returns true, any simulation context should be saved and + sim_events_process() called. + + SIM_EVENTS_TICK advances the clock by 1 cycle. + + SIM_EVENTS_TICKN advances the clock by N cycles (1..MAXINT). */ + +INLINE_SIM_EVENTS\ +(int) sim_events_tick +(SIM_DESC sd); + +INLINE_SIM_EVENTS\ +(int) sim_events_tickn +(SIM_DESC sd, + int n); + +INLINE_SIM_EVENTS\ +(void) sim_events_process +(SIM_DESC sd); + + +/* Advance the clock by an additional SLIP cycles at the next call to + sim_events_tick*(). For multiple calls, the effect is + accumulative. */ + +INLINE_SIM_EVENTS\ +(void) sim_events_slip +(SIM_DESC sd, + int slip); + + +/* Progress time such that an event shall occure upon the next call to + sim_events tick */ + +#if 0 +INLINE_SIM_EVENTS\ +(void) sim_events_timewarp +(SIM_DESC sd); +#endif + + +/* local concept of elapsed target time */ + +INLINE_SIM_EVENTS\ +(signed64) sim_events_time +(SIM_DESC sd); + + +/* local concept of elapsed host time (milliseconds) */ + +INLINE_SIM_EVENTS\ +(unsigned long) sim_events_elapsed_time +(SIM_DESC sd); + +#endif diff --git a/sim/common/sim-fpu.c b/sim/common/sim-fpu.c new file mode 100644 index 0000000..abf746a --- /dev/null +++ b/sim/common/sim-fpu.c @@ -0,0 +1,2578 @@ +/* This is a software floating point library which can be used instead + of the floating point routines in libgcc1.c for targets without + hardware floating point. */ + +/* Copyright (C) 1994,1997-1998 Free Software Foundation, Inc. + +This file is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file with other programs, and to distribute +those programs without any restriction coming from the use of this +file. (The General Public License restrictions do apply in other +respects; for example, they cover modification of the file, and +distribution when not linked into another program.) + +This file is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* As a special exception, if you link this library with other files, + some of which are compiled with GCC, to produce an executable, + this library does not by itself cause the resulting executable + to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +/* This implements IEEE 754 format arithmetic, but does not provide a + mechanism for setting the rounding mode, or for generating or handling + exceptions. + + The original code by Steve Chamberlain, hacked by Mark Eichin and Jim + Wilson, all of Cygnus Support. */ + + +#ifndef SIM_FPU_C +#define SIM_FPU_C + +#include "sim-basics.h" +#include "sim-fpu.h" + +#include "sim-io.h" +#include "sim-assert.h" + + +/* Debugging support. */ + +static void +print_bits (unsigned64 x, + int msbit, + sim_fpu_print_func print, + void *arg) +{ + unsigned64 bit = LSBIT64 (msbit); + int i = 4; + while (bit) + { + if (i == 0) + print (arg, ","); + if ((x & bit)) + print (arg, "1"); + else + print (arg, "0"); + bit >>= 1; + i = (i + 1) % 4; + } +} + + + +/* Quick and dirty conversion between a host double and host 64bit int */ + +typedef union { + double d; + unsigned64 i; +} sim_fpu_map; + + +/* A packed IEEE floating point number. + + Form is <SIGN:1><BIASEDEXP:NR_EXPBITS><FRAC:NR_FRACBITS> for both + 32 and 64 bit numbers. This number is interpreted as: + + Normalized (0 < BIASEDEXP && BIASEDEXP < EXPMAX): + (sign ? '-' : '+') 1.<FRAC> x 2 ^ (BIASEDEXP - EXPBIAS) + + Denormalized (0 == BIASEDEXP && FRAC != 0): + (sign ? "-" : "+") 0.<FRAC> x 2 ^ (- EXPBIAS) + + Zero (0 == BIASEDEXP && FRAC == 0): + (sign ? "-" : "+") 0.0 + + Infinity (BIASEDEXP == EXPMAX && FRAC == 0): + (sign ? "-" : "+") "infinity" + + SignalingNaN (BIASEDEXP == EXPMAX && FRAC > 0 && FRAC < QUIET_NAN): + SNaN.FRAC + + QuietNaN (BIASEDEXP == EXPMAX && FRAC > 0 && FRAC > QUIET_NAN): + QNaN.FRAC + + */ + +#define NR_EXPBITS (is_double ? 11 : 8) +#define NR_FRACBITS (is_double ? 52 : 23) +#define SIGNBIT (is_double ? MSBIT64 (0) : MSBIT64 (32)) + +#define EXPMAX32 (255) +#define EXMPAX64 (2047) +#define EXPMAX ((unsigned) (is_double ? EXMPAX64 : EXPMAX32)) + +#define EXPBIAS32 (127) +#define EXPBIAS64 (1023) +#define EXPBIAS (is_double ? EXPBIAS64 : EXPBIAS32) + +#define QUIET_NAN LSBIT64 (NR_FRACBITS - 1) + + + +/* An unpacked floating point number. + + When unpacked, the fraction of both a 32 and 64 bit floating point + number is stored using the same format: + + 64 bit - <IMPLICIT_1:1><FRACBITS:52><GUARDS:8><PAD:00> + 32 bit - <IMPLICIT_1:1><FRACBITS:23><GUARDS:7><PAD:30> */ + +#define NR_PAD32 (30) +#define NR_PAD64 (0) +#define NR_PAD (is_double ? NR_PAD64 : NR_PAD32) +#define PADMASK (is_double ? 0 : LSMASK64 (NR_PAD32 - 1, 0)) + +#define NR_GUARDS32 (7 + NR_PAD32) +#define NR_GUARDS64 (8 + NR_PAD64) +#define NR_GUARDS (is_double ? NR_GUARDS64 : NR_GUARDS32) +#define GUARDMASK LSMASK64 (NR_GUARDS - 1, 0) + +#define GUARDMSB LSBIT64 (NR_GUARDS - 1) +#define GUARDLSB LSBIT64 (NR_PAD) +#define GUARDROUND LSMASK64 (NR_GUARDS - 2, 0) + +#define NR_FRAC_GUARD (60) +#define IMPLICIT_1 LSBIT64 (NR_FRAC_GUARD) +#define IMPLICIT_2 LSBIT64 (NR_FRAC_GUARD + 1) +#define IMPLICIT_4 LSBIT64 (NR_FRAC_GUARD + 2) +#define NR_SPARE 2 + +#define FRAC32MASK LSMASK64 (63, NR_FRAC_GUARD - 32 + 1) + +#define NORMAL_EXPMIN (-(EXPBIAS)+1) + +#define NORMAL_EXPMAX32 (EXPBIAS32) +#define NORMAL_EXPMAX64 (EXPBIAS64) +#define NORMAL_EXPMAX (EXPBIAS) + + +/* Integer constants */ + +#define MAX_INT32 ((signed64) LSMASK64 (30, 0)) +#define MAX_UINT32 LSMASK64 (31, 0) +#define MIN_INT32 ((signed64) LSMASK64 (63, 31)) + +#define MAX_INT64 ((signed64) LSMASK64 (62, 0)) +#define MAX_UINT64 LSMASK64 (63, 0) +#define MIN_INT64 ((signed64) LSMASK64 (63, 63)) + +#define MAX_INT (is_64bit ? MAX_INT64 : MAX_INT32) +#define MIN_INT (is_64bit ? MIN_INT64 : MIN_INT32) +#define MAX_UINT (is_64bit ? MAX_UINT64 : MAX_UINT32) +#define NR_INTBITS (is_64bit ? 64 : 32) + +/* Squeese an unpacked sim_fpu struct into a 32/64 bit integer */ +STATIC_INLINE_SIM_FPU (unsigned64) +pack_fpu (const sim_fpu *src, + int is_double) +{ + int sign; + unsigned64 exp; + unsigned64 fraction; + unsigned64 packed; + + switch (src->class) + { + /* create a NaN */ + case sim_fpu_class_qnan: + sign = src->sign; + exp = EXPMAX; + /* force fraction to correct class */ + fraction = src->fraction; + fraction >>= NR_GUARDS; + fraction |= QUIET_NAN; + break; + case sim_fpu_class_snan: + sign = src->sign; + exp = EXPMAX; + /* force fraction to correct class */ + fraction = src->fraction; + fraction >>= NR_GUARDS; + fraction &= ~QUIET_NAN; + break; + case sim_fpu_class_infinity: + sign = src->sign; + exp = EXPMAX; + fraction = 0; + break; + case sim_fpu_class_zero: + sign = src->sign; + exp = 0; + fraction = 0; + break; + case sim_fpu_class_number: + case sim_fpu_class_denorm: + ASSERT (src->fraction >= IMPLICIT_1); + ASSERT (src->fraction < IMPLICIT_2); + if (src->normal_exp < NORMAL_EXPMIN) + { + /* This number's exponent is too low to fit into the bits + available in the number We'll denormalize the number by + storing zero in the exponent and shift the fraction to + the right to make up for it. */ + int nr_shift = NORMAL_EXPMIN - src->normal_exp; + if (nr_shift > NR_FRACBITS) + { + /* underflow, just make the number zero */ + sign = src->sign; + exp = 0; + fraction = 0; + } + else + { + sign = src->sign; + exp = 0; + /* Shift by the value */ + fraction = src->fraction; + fraction >>= NR_GUARDS; + fraction >>= nr_shift; + } + } + else if (src->normal_exp > NORMAL_EXPMAX) + { + /* Infinity */ + sign = src->sign; + exp = EXPMAX; + fraction = 0; + } + else + { + exp = (src->normal_exp + EXPBIAS); + sign = src->sign; + fraction = src->fraction; + /* FIXME: Need to round according to WITH_SIM_FPU_ROUNDING + or some such */ + /* Round to nearest: If the guard bits are the all zero, but + the first, then we're half way between two numbers, + choose the one which makes the lsb of the answer 0. */ + if ((fraction & GUARDMASK) == GUARDMSB) + { + if ((fraction & (GUARDMSB << 1))) + fraction += (GUARDMSB << 1); + } + else + { + /* Add a one to the guards to force round to nearest */ + fraction += GUARDROUND; + } + if ((fraction & IMPLICIT_2)) /* rounding resulted in carry */ + { + exp += 1; + fraction >>= 1; + } + fraction >>= NR_GUARDS; + /* When exp == EXPMAX (overflow from carry) fraction must + have been made zero */ + ASSERT ((exp == EXPMAX) <= ((fraction & ~IMPLICIT_1) == 0)); + } + break; + default: + abort (); + } + + packed = ((sign ? SIGNBIT : 0) + | (exp << NR_FRACBITS) + | LSMASKED64 (fraction, NR_FRACBITS - 1, 0)); + + /* trace operation */ +#if 0 + if (is_double) + { + } + else + { + printf ("pack_fpu: "); + printf ("-> %c%0lX.%06lX\n", + LSMASKED32 (packed, 31, 31) ? '8' : '0', + (long) LSEXTRACTED32 (packed, 30, 23), + (long) LSEXTRACTED32 (packed, 23 - 1, 0)); + } +#endif + + return packed; +} + + +/* Unpack a 32/64 bit integer into a sim_fpu structure */ +STATIC_INLINE_SIM_FPU (void) +unpack_fpu (sim_fpu *dst, unsigned64 packed, int is_double) +{ + unsigned64 fraction = LSMASKED64 (packed, NR_FRACBITS - 1, 0); + unsigned exp = LSEXTRACTED64 (packed, NR_EXPBITS + NR_FRACBITS - 1, NR_FRACBITS); + int sign = (packed & SIGNBIT) != 0; + + if (exp == 0) + { + /* Hmm. Looks like 0 */ + if (fraction == 0) + { + /* tastes like zero */ + dst->class = sim_fpu_class_zero; + dst->sign = sign; + } + else + { + /* Zero exponent with non zero fraction - it's denormalized, + so there isn't a leading implicit one - we'll shift it so + it gets one. */ + dst->normal_exp = exp - EXPBIAS + 1; + dst->class = sim_fpu_class_denorm; + dst->sign = sign; + fraction <<= NR_GUARDS; + while (fraction < IMPLICIT_1) + { + fraction <<= 1; + dst->normal_exp--; + } + dst->fraction = fraction; + } + } + else if (exp == EXPMAX) + { + /* Huge exponent*/ + if (fraction == 0) + { + /* Attached to a zero fraction - means infinity */ + dst->class = sim_fpu_class_infinity; + dst->sign = sign; + /* dst->normal_exp = EXPBIAS; */ + /* dst->fraction = 0; */ + } + else + { + /* Non zero fraction, means NaN */ + dst->sign = sign; + dst->fraction = (fraction << NR_GUARDS); + if (fraction >= QUIET_NAN) + dst->class = sim_fpu_class_qnan; + else + dst->class = sim_fpu_class_snan; + } + } + else + { + /* Nothing strange about this number */ + dst->class = sim_fpu_class_number; + dst->sign = sign; + dst->fraction = ((fraction << NR_GUARDS) | IMPLICIT_1); + dst->normal_exp = exp - EXPBIAS; + } + + /* trace operation */ +#if 0 + if (is_double) + { + } + else + { + printf ("unpack_fpu: %c%02lX.%06lX ->\n", + LSMASKED32 (packed, 31, 31) ? '8' : '0', + (long) LSEXTRACTED32 (packed, 30, 23), + (long) LSEXTRACTED32 (packed, 23 - 1, 0)); + } +#endif + + /* sanity checks */ + { + sim_fpu_map val; + val.i = pack_fpu (dst, 1); + if (is_double) + { + ASSERT (val.i == packed); + } + else + { + unsigned32 val = pack_fpu (dst, 0); + unsigned32 org = packed; + ASSERT (val == org); + } + } +} + + +/* Convert a floating point into an integer */ +STATIC_INLINE_SIM_FPU (int) +fpu2i (signed64 *i, + const sim_fpu *s, + int is_64bit, + sim_fpu_round round) +{ + unsigned64 tmp; + int shift; + int status = 0; + if (sim_fpu_is_zero (s)) + { + *i = 0; + return 0; + } + if (sim_fpu_is_snan (s)) + { + *i = MIN_INT; /* FIXME */ + return sim_fpu_status_invalid_cvi; + } + if (sim_fpu_is_qnan (s)) + { + *i = MIN_INT; /* FIXME */ + return sim_fpu_status_invalid_cvi; + } + /* map infinity onto MAX_INT... */ + if (sim_fpu_is_infinity (s)) + { + *i = s->sign ? MIN_INT : MAX_INT; + return sim_fpu_status_invalid_cvi; + } + /* it is a number, but a small one */ + if (s->normal_exp < 0) + { + *i = 0; + return sim_fpu_status_inexact; + } + /* Is the floating point MIN_INT or just close? */ + if (s->sign && s->normal_exp == (NR_INTBITS - 1)) + { + *i = MIN_INT; + ASSERT (s->fraction >= IMPLICIT_1); + if (s->fraction == IMPLICIT_1) + return 0; /* exact */ + if (is_64bit) /* can't round */ + return sim_fpu_status_invalid_cvi; /* must be overflow */ + /* For a 32bit with MAX_INT, rounding is possible */ + switch (round) + { + case sim_fpu_round_default: + abort (); + case sim_fpu_round_zero: + if ((s->fraction & FRAC32MASK) != IMPLICIT_1) + return sim_fpu_status_invalid_cvi; + else + return sim_fpu_status_inexact; + break; + case sim_fpu_round_near: + { + if ((s->fraction & FRAC32MASK) != IMPLICIT_1) + return sim_fpu_status_invalid_cvi; + else if ((s->fraction & !FRAC32MASK) >= (~FRAC32MASK >> 1)) + return sim_fpu_status_invalid_cvi; + else + return sim_fpu_status_inexact; + } + case sim_fpu_round_up: + if ((s->fraction & FRAC32MASK) == IMPLICIT_1) + return sim_fpu_status_inexact; + else + return sim_fpu_status_invalid_cvi; + case sim_fpu_round_down: + return sim_fpu_status_invalid_cvi; + } + } + /* Would right shifting result in the FRAC being shifted into + (through) the integer's sign bit? */ + if (s->normal_exp > (NR_INTBITS - 2)) + { + *i = s->sign ? MIN_INT : MAX_INT; + return sim_fpu_status_invalid_cvi; + } + /* normal number shift it into place */ + tmp = s->fraction; + shift = (s->normal_exp - (NR_FRAC_GUARD)); + if (shift > 0) + { + tmp <<= shift; + } + else + { + shift = -shift; + if (tmp & ((SIGNED64 (1) << shift) - 1)) + status |= sim_fpu_status_inexact; + tmp >>= shift; + } + *i = s->sign ? (-tmp) : (tmp); + return status; +} + +/* convert an integer into a floating point */ +STATIC_INLINE_SIM_FPU (int) +i2fpu (sim_fpu *f, signed64 i, int is_64bit) +{ + int status = 0; + if (i == 0) + { + f->class = sim_fpu_class_zero; + f->sign = 0; + } + else + { + f->class = sim_fpu_class_number; + f->sign = (i < 0); + f->normal_exp = NR_FRAC_GUARD; + + if (f->sign) + { + /* Special case for minint, since there is no corresponding + +ve integer representation for it */ + if (i == MIN_INT) + { + f->fraction = IMPLICIT_1; + f->normal_exp = NR_INTBITS - 1; + } + else + f->fraction = (-i); + } + else + f->fraction = i; + + if (f->fraction >= IMPLICIT_2) + { + do + { + f->fraction >>= 1; + f->normal_exp += 1; + } + while (f->fraction >= IMPLICIT_2); + } + else if (f->fraction < IMPLICIT_1) + { + do + { + f->fraction <<= 1; + f->normal_exp -= 1; + } + while (f->fraction < IMPLICIT_1); + } + } + + /* trace operation */ +#if 0 + { + printf ("i2fpu: 0x%08lX ->\n", (long) i); + } +#endif + + /* sanity check */ + { + signed64 val; + fpu2i (&val, f, is_64bit, sim_fpu_round_zero); + if (i >= MIN_INT32 && i <= MAX_INT32) + { + ASSERT (val == i); + } + } + + return status; +} + + +/* Convert a floating point into an integer */ +STATIC_INLINE_SIM_FPU (int) +fpu2u (unsigned64 *u, const sim_fpu *s, int is_64bit) +{ + const int is_double = 1; + unsigned64 tmp; + int shift; + if (sim_fpu_is_zero (s)) + { + *u = 0; + return 0; + } + if (sim_fpu_is_nan (s)) + { + *u = 0; + return 0; + } + /* it is a negative number */ + if (s->sign) + { + *u = 0; + return 0; + } + /* get reasonable MAX_USI_INT... */ + if (sim_fpu_is_infinity (s)) + { + *u = MAX_UINT; + return 0; + } + /* it is a number, but a small one */ + if (s->normal_exp < 0) + { + *u = 0; + return 0; + } + /* overflow */ + if (s->normal_exp > (NR_INTBITS - 1)) + { + *u = MAX_UINT; + return 0; + } + /* normal number */ + tmp = (s->fraction & ~PADMASK); + shift = (s->normal_exp - (NR_FRACBITS + NR_GUARDS)); + if (shift > 0) + { + tmp <<= shift; + } + else + { + shift = -shift; + tmp >>= shift; + } + *u = tmp; + return 0; +} + +/* Convert an unsigned integer into a floating point */ +STATIC_INLINE_SIM_FPU (int) +u2fpu (sim_fpu *f, unsigned64 u, int is_64bit) +{ + if (u == 0) + { + f->class = sim_fpu_class_zero; + f->sign = 0; + } + else + { + f->class = sim_fpu_class_number; + f->sign = 0; + f->normal_exp = NR_FRAC_GUARD; + f->fraction = u; + + while (f->fraction < IMPLICIT_1) + { + f->fraction <<= 1; + f->normal_exp -= 1; + } + } + return 0; +} + + +/* register <-> sim_fpu */ + +INLINE_SIM_FPU (void) +sim_fpu_32to (sim_fpu *f, unsigned32 s) +{ + unpack_fpu (f, s, 0); +} + + +INLINE_SIM_FPU (void) +sim_fpu_232to (sim_fpu *f, unsigned32 h, unsigned32 l) +{ + unsigned64 s = h; + s = (s << 32) | l; + unpack_fpu (f, s, 1); +} + + +INLINE_SIM_FPU (void) +sim_fpu_64to (sim_fpu *f, unsigned64 s) +{ + unpack_fpu (f, s, 1); +} + + +INLINE_SIM_FPU (void) +sim_fpu_to32 (unsigned32 *s, + const sim_fpu *f) +{ + *s = pack_fpu (f, 0); +} + + +INLINE_SIM_FPU (void) +sim_fpu_to232 (unsigned32 *h, unsigned32 *l, + const sim_fpu *f) +{ + unsigned64 s = pack_fpu (f, 1); + *l = s; + *h = (s >> 32); +} + + +INLINE_SIM_FPU (void) +sim_fpu_to64 (unsigned64 *u, + const sim_fpu *f) +{ + *u = pack_fpu (f, 1); +} + + +INLINE_SIM_FPU (void) +sim_fpu_fractionto (sim_fpu *f, + int sign, + int normal_exp, + unsigned64 fraction, + int precision) +{ + int shift = (NR_FRAC_GUARD - precision); + f->class = sim_fpu_class_number; + f->sign = sign; + f->normal_exp = normal_exp; + /* shift the fraction to where sim-fpu expects it */ + if (shift >= 0) + f->fraction = (fraction << shift); + else + f->fraction = (fraction >> -shift); + f->fraction |= IMPLICIT_1; +} + + +INLINE_SIM_FPU (unsigned64) +sim_fpu_tofraction (const sim_fpu *d, + int precision) +{ + /* we have NR_FRAC_GUARD bits, we want only PRECISION bits */ + int shift = (NR_FRAC_GUARD - precision); + unsigned64 fraction = (d->fraction & ~IMPLICIT_1); + if (shift >= 0) + return fraction >> shift; + else + return fraction << -shift; +} + + +/* Rounding */ + +STATIC_INLINE_SIM_FPU (int) +do_normal_overflow (sim_fpu *f, + int is_double, + sim_fpu_round round) +{ + switch (round) + { + case sim_fpu_round_default: + return 0; + case sim_fpu_round_near: + f->class = sim_fpu_class_infinity; + break; + case sim_fpu_round_up: + if (!f->sign) + f->class = sim_fpu_class_infinity; + break; + case sim_fpu_round_down: + if (f->sign) + f->class = sim_fpu_class_infinity; + break; + case sim_fpu_round_zero: + break; + } + f->normal_exp = NORMAL_EXPMAX; + f->fraction = LSMASK64 (NR_FRAC_GUARD, NR_GUARDS); + return (sim_fpu_status_overflow | sim_fpu_status_inexact); +} + +STATIC_INLINE_SIM_FPU (int) +do_normal_underflow (sim_fpu *f, + int is_double, + sim_fpu_round round) +{ + switch (round) + { + case sim_fpu_round_default: + return 0; + case sim_fpu_round_near: + f->class = sim_fpu_class_zero; + break; + case sim_fpu_round_up: + if (f->sign) + f->class = sim_fpu_class_zero; + break; + case sim_fpu_round_down: + if (!f->sign) + f->class = sim_fpu_class_zero; + break; + case sim_fpu_round_zero: + f->class = sim_fpu_class_zero; + break; + } + f->normal_exp = NORMAL_EXPMIN - NR_FRACBITS; + f->fraction = IMPLICIT_1; + return (sim_fpu_status_inexact | sim_fpu_status_underflow); +} + + + +/* Round a number using NR_GUARDS. + Will return the rounded number or F->FRACTION == 0 when underflow */ + +STATIC_INLINE_SIM_FPU (int) +do_normal_round (sim_fpu *f, + int nr_guards, + sim_fpu_round round) +{ + unsigned64 guardmask = LSMASK64 (nr_guards - 1, 0); + unsigned64 guardmsb = LSBIT64 (nr_guards - 1); + unsigned64 fraclsb = guardmsb << 1; + if ((f->fraction & guardmask)) + { + int status = sim_fpu_status_inexact; + switch (round) + { + case sim_fpu_round_default: + return 0; + case sim_fpu_round_near: + if ((f->fraction & guardmsb)) + { + if ((f->fraction & fraclsb)) + { + status |= sim_fpu_status_rounded; + } + else if ((f->fraction & (guardmask >> 1))) + { + status |= sim_fpu_status_rounded; + } + } + break; + case sim_fpu_round_up: + if (!f->sign) + status |= sim_fpu_status_rounded; + break; + case sim_fpu_round_down: + if (f->sign) + status |= sim_fpu_status_rounded; + break; + case sim_fpu_round_zero: + break; + } + f->fraction &= ~guardmask; + /* round if needed, handle resulting overflow */ + if ((status & sim_fpu_status_rounded)) + { + f->fraction += fraclsb; + if ((f->fraction & IMPLICIT_2)) + { + f->fraction >>= 1; + f->normal_exp += 1; + } + } + return status; + } + else + return 0; +} + + +STATIC_INLINE_SIM_FPU (int) +do_round (sim_fpu *f, + int is_double, + sim_fpu_round round, + sim_fpu_denorm denorm) +{ + switch (f->class) + { + case sim_fpu_class_qnan: + case sim_fpu_class_zero: + case sim_fpu_class_infinity: + return 0; + break; + case sim_fpu_class_snan: + /* Quieten a SignalingNaN */ + f->class = sim_fpu_class_qnan; + return sim_fpu_status_invalid_snan; + break; + case sim_fpu_class_number: + case sim_fpu_class_denorm: + { + int status; + ASSERT (f->fraction < IMPLICIT_2); + ASSERT (f->fraction >= IMPLICIT_1); + if (f->normal_exp < NORMAL_EXPMIN) + { + /* This number's exponent is too low to fit into the bits + available in the number. Round off any bits that will be + discarded as a result of denormalization. Edge case is + the implicit bit shifted to GUARD0 and then rounded + up. */ + int shift = NORMAL_EXPMIN - f->normal_exp; + if (shift + NR_GUARDS <= NR_FRAC_GUARD + 1 + && !(denorm & sim_fpu_denorm_zero)) + { + status = do_normal_round (f, shift + NR_GUARDS, round); + if (f->fraction == 0) /* rounding underflowed */ + { + status |= do_normal_underflow (f, is_double, round); + } + else if (f->normal_exp < NORMAL_EXPMIN) /* still underflow? */ + { + status |= sim_fpu_status_denorm; + /* Any loss of precision when denormalizing is + underflow. Some processors check for underflow + before rounding, some after! */ + if (status & sim_fpu_status_inexact) + status |= sim_fpu_status_underflow; + /* Flag that resultant value has been denormalized */ + f->class = sim_fpu_class_denorm; + } + else if ((denorm & sim_fpu_denorm_underflow_inexact)) + { + if ((status & sim_fpu_status_inexact)) + status |= sim_fpu_status_underflow; + } + } + else + { + status = do_normal_underflow (f, is_double, round); + } + } + else if (f->normal_exp > NORMAL_EXPMAX) + { + /* Infinity */ + status = do_normal_overflow (f, is_double, round); + } + else + { + status = do_normal_round (f, NR_GUARDS, round); + if (f->fraction == 0) + /* f->class = sim_fpu_class_zero; */ + status |= do_normal_underflow (f, is_double, round); + else if (f->normal_exp > NORMAL_EXPMAX) + /* oops! rounding caused overflow */ + status |= do_normal_overflow (f, is_double, round); + } + ASSERT ((f->class == sim_fpu_class_number + || f->class == sim_fpu_class_denorm) + <= (f->fraction < IMPLICIT_2 && f->fraction >= IMPLICIT_1)); + return status; + } + } + return 0; +} + +INLINE_SIM_FPU (int) +sim_fpu_round_32 (sim_fpu *f, + sim_fpu_round round, + sim_fpu_denorm denorm) +{ + return do_round (f, 0, round, denorm); +} + +INLINE_SIM_FPU (int) +sim_fpu_round_64 (sim_fpu *f, + sim_fpu_round round, + sim_fpu_denorm denorm) +{ + return do_round (f, 1, round, denorm); +} + + + +/* Arithmetic ops */ + +INLINE_SIM_FPU (int) +sim_fpu_add (sim_fpu *f, + const sim_fpu *l, + const sim_fpu *r) +{ + if (sim_fpu_is_snan (l)) + { + *f = *l; + f->class = sim_fpu_class_qnan; + return sim_fpu_status_invalid_snan; + } + if (sim_fpu_is_snan (r)) + { + *f = *r; + f->class = sim_fpu_class_qnan; + return sim_fpu_status_invalid_snan; + } + if (sim_fpu_is_qnan (l)) + { + *f = *l; + return 0; + } + if (sim_fpu_is_qnan (r)) + { + *f = *r; + return 0; + } + if (sim_fpu_is_infinity (l)) + { + if (sim_fpu_is_infinity (r) + && l->sign != r->sign) + { + *f = sim_fpu_qnan; + return sim_fpu_status_invalid_isi; + } + *f = *l; + return 0; + } + if (sim_fpu_is_infinity (r)) + { + *f = *r; + return 0; + } + if (sim_fpu_is_zero (l)) + { + if (sim_fpu_is_zero (r)) + { + *f = sim_fpu_zero; + f->sign = l->sign & r->sign; + } + else + *f = *r; + return 0; + } + if (sim_fpu_is_zero (r)) + { + *f = *l; + return 0; + } + { + int status = 0; + int shift = l->normal_exp - r->normal_exp; + unsigned64 lfraction; + unsigned64 rfraction; + /* use exp of larger */ + if (shift >= NR_FRAC_GUARD) + { + /* left has much bigger magnitute */ + *f = *l; + return sim_fpu_status_inexact; + } + if (shift <= - NR_FRAC_GUARD) + { + /* right has much bigger magnitute */ + *f = *r; + return sim_fpu_status_inexact; + } + lfraction = l->fraction; + rfraction = r->fraction; + if (shift > 0) + { + f->normal_exp = l->normal_exp; + if (rfraction & LSMASK64 (shift - 1, 0)) + { + status |= sim_fpu_status_inexact; + rfraction |= LSBIT64 (shift); /* stick LSBit */ + } + rfraction >>= shift; + } + else if (shift < 0) + { + f->normal_exp = r->normal_exp; + if (lfraction & LSMASK64 (- shift - 1, 0)) + { + status |= sim_fpu_status_inexact; + lfraction |= LSBIT64 (- shift); /* stick LSBit */ + } + lfraction >>= -shift; + } + else + { + f->normal_exp = r->normal_exp; + } + + /* perform the addition */ + if (l->sign) + lfraction = - lfraction; + if (r->sign) + rfraction = - rfraction; + f->fraction = lfraction + rfraction; + + /* zero? */ + if (f->fraction == 0) + { + *f = sim_fpu_zero; + return 0; + } + + /* sign? */ + f->class = sim_fpu_class_number; + if ((signed64) f->fraction >= 0) + f->sign = 0; + else + { + f->sign = 1; + f->fraction = - f->fraction; + } + + /* normalize it */ + if ((f->fraction & IMPLICIT_2)) + { + f->fraction = (f->fraction >> 1) | (f->fraction & 1); + f->normal_exp ++; + } + else if (f->fraction < IMPLICIT_1) + { + do + { + f->fraction <<= 1; + f->normal_exp --; + } + while (f->fraction < IMPLICIT_1); + } + ASSERT (f->fraction >= IMPLICIT_1 && f->fraction < IMPLICIT_2); + return status; + } +} + + +INLINE_SIM_FPU (int) +sim_fpu_sub (sim_fpu *f, + const sim_fpu *l, + const sim_fpu *r) +{ + if (sim_fpu_is_snan (l)) + { + *f = *l; + f->class = sim_fpu_class_qnan; + return sim_fpu_status_invalid_snan; + } + if (sim_fpu_is_snan (r)) + { + *f = *r; + f->class = sim_fpu_class_qnan; + return sim_fpu_status_invalid_snan; + } + if (sim_fpu_is_qnan (l)) + { + *f = *l; + return 0; + } + if (sim_fpu_is_qnan (r)) + { + *f = *r; + return 0; + } + if (sim_fpu_is_infinity (l)) + { + if (sim_fpu_is_infinity (r) + && l->sign == r->sign) + { + *f = sim_fpu_qnan; + return sim_fpu_status_invalid_isi; + } + *f = *l; + return 0; + } + if (sim_fpu_is_infinity (r)) + { + *f = *r; + f->sign = !r->sign; + return 0; + } + if (sim_fpu_is_zero (l)) + { + if (sim_fpu_is_zero (r)) + { + *f = sim_fpu_zero; + f->sign = l->sign & !r->sign; + } + else + { + *f = *r; + f->sign = !r->sign; + } + return 0; + } + if (sim_fpu_is_zero (r)) + { + *f = *l; + return 0; + } + { + int status = 0; + int shift = l->normal_exp - r->normal_exp; + unsigned64 lfraction; + unsigned64 rfraction; + /* use exp of larger */ + if (shift >= NR_FRAC_GUARD) + { + /* left has much bigger magnitute */ + *f = *l; + return sim_fpu_status_inexact; + } + if (shift <= - NR_FRAC_GUARD) + { + /* right has much bigger magnitute */ + *f = *r; + f->sign = !r->sign; + return sim_fpu_status_inexact; + } + lfraction = l->fraction; + rfraction = r->fraction; + if (shift > 0) + { + f->normal_exp = l->normal_exp; + if (rfraction & LSMASK64 (shift - 1, 0)) + { + status |= sim_fpu_status_inexact; + rfraction |= LSBIT64 (shift); /* stick LSBit */ + } + rfraction >>= shift; + } + else if (shift < 0) + { + f->normal_exp = r->normal_exp; + if (lfraction & LSMASK64 (- shift - 1, 0)) + { + status |= sim_fpu_status_inexact; + lfraction |= LSBIT64 (- shift); /* stick LSBit */ + } + lfraction >>= -shift; + } + else + { + f->normal_exp = r->normal_exp; + } + + /* perform the subtraction */ + if (l->sign) + lfraction = - lfraction; + if (!r->sign) + rfraction = - rfraction; + f->fraction = lfraction + rfraction; + + /* zero? */ + if (f->fraction == 0) + { + *f = sim_fpu_zero; + return 0; + } + + /* sign? */ + f->class = sim_fpu_class_number; + if ((signed64) f->fraction >= 0) + f->sign = 0; + else + { + f->sign = 1; + f->fraction = - f->fraction; + } + + /* normalize it */ + if ((f->fraction & IMPLICIT_2)) + { + f->fraction = (f->fraction >> 1) | (f->fraction & 1); + f->normal_exp ++; + } + else if (f->fraction < IMPLICIT_1) + { + do + { + f->fraction <<= 1; + f->normal_exp --; + } + while (f->fraction < IMPLICIT_1); + } + ASSERT (f->fraction >= IMPLICIT_1 && f->fraction < IMPLICIT_2); + return status; + } +} + + +INLINE_SIM_FPU (int) +sim_fpu_mul (sim_fpu *f, + const sim_fpu *l, + const sim_fpu *r) +{ + if (sim_fpu_is_snan (l)) + { + *f = *l; + f->class = sim_fpu_class_qnan; + return sim_fpu_status_invalid_snan; + } + if (sim_fpu_is_snan (r)) + { + *f = *r; + f->class = sim_fpu_class_qnan; + return sim_fpu_status_invalid_snan; + } + if (sim_fpu_is_qnan (l)) + { + *f = *l; + return 0; + } + if (sim_fpu_is_qnan (r)) + { + *f = *r; + return 0; + } + if (sim_fpu_is_infinity (l)) + { + if (sim_fpu_is_zero (r)) + { + *f = sim_fpu_qnan; + return sim_fpu_status_invalid_imz; + } + *f = *l; + f->sign = l->sign ^ r->sign; + return 0; + } + if (sim_fpu_is_infinity (r)) + { + if (sim_fpu_is_zero (l)) + { + *f = sim_fpu_qnan; + return sim_fpu_status_invalid_imz; + } + *f = *r; + f->sign = l->sign ^ r->sign; + return 0; + } + if (sim_fpu_is_zero (l) || sim_fpu_is_zero (r)) + { + *f = sim_fpu_zero; + f->sign = l->sign ^ r->sign; + return 0; + } + /* Calculate the mantissa by multiplying both 64bit numbers to get a + 128 bit number */ + { + unsigned64 low; + unsigned64 high; + unsigned64 nl = l->fraction & 0xffffffff; + unsigned64 nh = l->fraction >> 32; + unsigned64 ml = r->fraction & 0xffffffff; + unsigned64 mh = r->fraction >>32; + unsigned64 pp_ll = ml * nl; + unsigned64 pp_hl = mh * nl; + unsigned64 pp_lh = ml * nh; + unsigned64 pp_hh = mh * nh; + unsigned64 res2 = 0; + unsigned64 res0 = 0; + unsigned64 ps_hh__ = pp_hl + pp_lh; + if (ps_hh__ < pp_hl) + res2 += UNSIGNED64 (0x100000000); + pp_hl = (ps_hh__ << 32) & UNSIGNED64 (0xffffffff00000000); + res0 = pp_ll + pp_hl; + if (res0 < pp_ll) + res2++; + res2 += ((ps_hh__ >> 32) & 0xffffffff) + pp_hh; + high = res2; + low = res0; + + f->normal_exp = l->normal_exp + r->normal_exp; + f->sign = l->sign ^ r->sign; + f->class = sim_fpu_class_number; + + /* Input is bounded by [1,2) ; [2^60,2^61) + Output is bounded by [1,4) ; [2^120,2^122) */ + + /* Adjust the exponent according to where the decimal point ended + up in the high 64 bit word. In the source the decimal point + was at NR_FRAC_GUARD. */ + f->normal_exp += NR_FRAC_GUARD + 64 - (NR_FRAC_GUARD * 2); + + /* The high word is bounded according to the above. Consequently + it has never overflowed into IMPLICIT_2. */ + ASSERT (high < LSBIT64 (((NR_FRAC_GUARD + 1) * 2) - 64)); + ASSERT (high >= LSBIT64 ((NR_FRAC_GUARD * 2) - 64)); + ASSERT (LSBIT64 (((NR_FRAC_GUARD + 1) * 2) - 64) < IMPLICIT_1); + +#if 0 + printf ("\n"); + print_bits (high, 63, (sim_fpu_print_func*)fprintf, stdout); + printf (";"); + print_bits (low, 63, (sim_fpu_print_func*)fprintf, stdout); + printf ("\n"); +#endif + + /* normalize */ + do + { + f->normal_exp--; + high <<= 1; + if (low & LSBIT64 (63)) + high |= 1; + low <<= 1; + } + while (high < IMPLICIT_1); + +#if 0 + print_bits (high, 63, (sim_fpu_print_func*)fprintf, stdout); + printf (";"); + print_bits (low, 63, (sim_fpu_print_func*)fprintf, stdout); + printf ("\n"); +#endif + + ASSERT (high >= IMPLICIT_1 && high < IMPLICIT_2); + if (low != 0) + { + f->fraction = (high | 1); /* sticky */ + return sim_fpu_status_inexact; + } + else + { + f->fraction = high; + return 0; + } + return 0; + } +} + +INLINE_SIM_FPU (int) +sim_fpu_div (sim_fpu *f, + const sim_fpu *l, + const sim_fpu *r) +{ + if (sim_fpu_is_snan (l)) + { + *f = *l; + f->class = sim_fpu_class_qnan; + return sim_fpu_status_invalid_snan; + } + if (sim_fpu_is_snan (r)) + { + *f = *r; + f->class = sim_fpu_class_qnan; + return sim_fpu_status_invalid_snan; + } + if (sim_fpu_is_qnan (l)) + { + *f = *l; + f->class = sim_fpu_class_qnan; + return 0; + } + if (sim_fpu_is_qnan (r)) + { + *f = *r; + f->class = sim_fpu_class_qnan; + return 0; + } + if (sim_fpu_is_infinity (l)) + { + if (sim_fpu_is_infinity (r)) + { + *f = sim_fpu_qnan; + return sim_fpu_status_invalid_idi; + } + else + { + *f = *l; + f->sign = l->sign ^ r->sign; + return 0; + } + } + if (sim_fpu_is_zero (l)) + { + if (sim_fpu_is_zero (r)) + { + *f = sim_fpu_qnan; + return sim_fpu_status_invalid_zdz; + } + else + { + *f = *l; + f->sign = l->sign ^ r->sign; + return 0; + } + } + if (sim_fpu_is_infinity (r)) + { + *f = sim_fpu_zero; + f->sign = l->sign ^ r->sign; + return 0; + } + if (sim_fpu_is_zero (r)) + { + f->class = sim_fpu_class_infinity; + f->sign = l->sign ^ r->sign; + return sim_fpu_status_invalid_div0; + } + + /* Calculate the mantissa by multiplying both 64bit numbers to get a + 128 bit number */ + { + /* quotient = ( ( numerator / denominator) + x 2^(numerator exponent - denominator exponent) + */ + unsigned64 numerator; + unsigned64 denominator; + unsigned64 quotient; + unsigned64 bit; + + f->class = sim_fpu_class_number; + f->sign = l->sign ^ r->sign; + f->normal_exp = l->normal_exp - r->normal_exp; + + numerator = l->fraction; + denominator = r->fraction; + + /* Fraction will be less than 1.0 */ + if (numerator < denominator) + { + numerator <<= 1; + f->normal_exp--; + } + ASSERT (numerator >= denominator); + + /* Gain extra precision, already used one spare bit */ + numerator <<= NR_SPARE; + denominator <<= NR_SPARE; + + /* Does divide one bit at a time. Optimize??? */ + quotient = 0; + bit = (IMPLICIT_1 << NR_SPARE); + while (bit) + { + if (numerator >= denominator) + { + quotient |= bit; + numerator -= denominator; + } + bit >>= 1; + numerator <<= 1; + } + +#if 0 + printf ("\n"); + print_bits (quotient, 63, (sim_fpu_print_func*)fprintf, stdout); + printf ("\n"); + print_bits (numerator, 63, (sim_fpu_print_func*)fprintf, stdout); + printf ("\n"); + print_bits (denominator, 63, (sim_fpu_print_func*)fprintf, stdout); + printf ("\n"); +#endif + + /* discard (but save) the extra bits */ + if ((quotient & LSMASK64 (NR_SPARE -1, 0))) + quotient = (quotient >> NR_SPARE) | 1; + else + quotient = (quotient >> NR_SPARE); + + f->fraction = quotient; + ASSERT (f->fraction >= IMPLICIT_1 && f->fraction < IMPLICIT_2); + if (numerator != 0) + { + f->fraction |= 1; /* stick remaining bits */ + return sim_fpu_status_inexact; + } + else + return 0; + } +} + + +INLINE_SIM_FPU (int) +sim_fpu_max (sim_fpu *f, + const sim_fpu *l, + const sim_fpu *r) +{ + if (sim_fpu_is_snan (l)) + { + *f = *l; + f->class = sim_fpu_class_qnan; + return sim_fpu_status_invalid_snan; + } + if (sim_fpu_is_snan (r)) + { + *f = *r; + f->class = sim_fpu_class_qnan; + return sim_fpu_status_invalid_snan; + } + if (sim_fpu_is_qnan (l)) + { + *f = *l; + return 0; + } + if (sim_fpu_is_qnan (r)) + { + *f = *r; + return 0; + } + if (sim_fpu_is_infinity (l)) + { + if (sim_fpu_is_infinity (r) + && l->sign == r->sign) + { + *f = sim_fpu_qnan; + return sim_fpu_status_invalid_isi; + } + if (l->sign) + *f = *r; /* -inf < anything */ + else + *f = *l; /* +inf > anthing */ + return 0; + } + if (sim_fpu_is_infinity (r)) + { + if (r->sign) + *f = *l; /* anything > -inf */ + else + *f = *r; /* anthing < +inf */ + return 0; + } + if (l->sign > r->sign) + { + *f = *r; /* -ve < +ve */ + return 0; + } + if (l->sign < r->sign) + { + *f = *l; /* +ve > -ve */ + return 0; + } + ASSERT (l->sign == r->sign); + if (l->normal_exp > r->normal_exp + || (l->normal_exp == r->normal_exp && + l->fraction > r->fraction)) + { + /* |l| > |r| */ + if (l->sign) + *f = *r; /* -ve < -ve */ + else + *f = *l; /* +ve > +ve */ + return 0; + } + else + { + /* |l| <= |r| */ + if (l->sign) + *f = *l; /* -ve > -ve */ + else + *f = *r; /* +ve < +ve */ + return 0; + } +} + + +INLINE_SIM_FPU (int) +sim_fpu_min (sim_fpu *f, + const sim_fpu *l, + const sim_fpu *r) +{ + if (sim_fpu_is_snan (l)) + { + *f = *l; + f->class = sim_fpu_class_qnan; + return sim_fpu_status_invalid_snan; + } + if (sim_fpu_is_snan (r)) + { + *f = *r; + f->class = sim_fpu_class_qnan; + return sim_fpu_status_invalid_snan; + } + if (sim_fpu_is_qnan (l)) + { + *f = *l; + return 0; + } + if (sim_fpu_is_qnan (r)) + { + *f = *r; + return 0; + } + if (sim_fpu_is_infinity (l)) + { + if (sim_fpu_is_infinity (r) + && l->sign == r->sign) + { + *f = sim_fpu_qnan; + return sim_fpu_status_invalid_isi; + } + if (l->sign) + *f = *l; /* -inf < anything */ + else + *f = *r; /* +inf > anthing */ + return 0; + } + if (sim_fpu_is_infinity (r)) + { + if (r->sign) + *f = *r; /* anything > -inf */ + else + *f = *l; /* anything < +inf */ + return 0; + } + if (l->sign > r->sign) + { + *f = *l; /* -ve < +ve */ + return 0; + } + if (l->sign < r->sign) + { + *f = *r; /* +ve > -ve */ + return 0; + } + ASSERT (l->sign == r->sign); + if (l->normal_exp > r->normal_exp + || (l->normal_exp == r->normal_exp && + l->fraction > r->fraction)) + { + /* |l| > |r| */ + if (l->sign) + *f = *l; /* -ve < -ve */ + else + *f = *r; /* +ve > +ve */ + return 0; + } + else + { + /* |l| <= |r| */ + if (l->sign) + *f = *r; /* -ve > -ve */ + else + *f = *l; /* +ve < +ve */ + return 0; + } +} + + +INLINE_SIM_FPU (int) +sim_fpu_neg (sim_fpu *f, + const sim_fpu *r) +{ + if (sim_fpu_is_snan (r)) + { + *f = *r; + f->class = sim_fpu_class_qnan; + return sim_fpu_status_invalid_snan; + } + if (sim_fpu_is_qnan (r)) + { + *f = *r; + return 0; + } + *f = *r; + f->sign = !r->sign; + return 0; +} + + +INLINE_SIM_FPU (int) +sim_fpu_abs (sim_fpu *f, + const sim_fpu *r) +{ + if (sim_fpu_is_snan (r)) + { + *f = *r; + f->class = sim_fpu_class_qnan; + return sim_fpu_status_invalid_snan; + } + if (sim_fpu_is_qnan (r)) + { + *f = *r; + return 0; + } + *f = *r; + f->sign = 0; + return 0; +} + + +INLINE_SIM_FPU (int) +sim_fpu_inv (sim_fpu *f, + const sim_fpu *r) +{ + if (sim_fpu_is_snan (r)) + { + *f = *r; + f->class = sim_fpu_class_qnan; + return sim_fpu_status_invalid_snan; + } + if (sim_fpu_is_qnan (r)) + { + *f = *r; + f->class = sim_fpu_class_qnan; + return 0; + } + if (sim_fpu_is_infinity (r)) + { + *f = sim_fpu_zero; + f->sign = r->sign; + return 0; + } + if (sim_fpu_is_zero (r)) + { + f->class = sim_fpu_class_infinity; + f->sign = r->sign; + return sim_fpu_status_invalid_div0; + } + *f = *r; + f->normal_exp = - r->normal_exp; + return 0; +} + + +INLINE_SIM_FPU (int) +sim_fpu_sqrt (sim_fpu *f, + const sim_fpu *r) +{ + if (sim_fpu_is_snan (r)) + { + *f = sim_fpu_qnan; + return sim_fpu_status_invalid_snan; + } + if (sim_fpu_is_qnan (r)) + { + *f = sim_fpu_qnan; + return 0; + } + if (sim_fpu_is_zero (r)) + { + f->class = sim_fpu_class_zero; + f->sign = r->sign; + return 0; + } + if (sim_fpu_is_infinity (r)) + { + if (r->sign) + { + *f = sim_fpu_qnan; + return sim_fpu_status_invalid_sqrt; + } + else + { + f->class = sim_fpu_class_infinity; + f->sign = 0; + f->sign = 0; + return 0; + } + } + if (r->sign) + { + *f = sim_fpu_qnan; + return sim_fpu_status_invalid_sqrt; + } + + /* @(#)e_sqrt.c 5.1 93/09/24 */ + /* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + + /* __ieee754_sqrt(x) + * Return correctly rounded sqrt. + * ------------------------------------------ + * | Use the hardware sqrt if you have one | + * ------------------------------------------ + * Method: + * Bit by bit method using integer arithmetic. (Slow, but portable) + * 1. Normalization + * Scale x to y in [1,4) with even powers of 2: + * find an integer k such that 1 <= (y=x*2^(2k)) < 4, then + * sqrt(x) = 2^k * sqrt(y) + - + - Since: + - sqrt ( x*2^(2m) ) = sqrt(x).2^m ; m even + - sqrt ( x*2^(2m + 1) ) = sqrt(2.x).2^m ; m odd + - Define: + - y = ((m even) ? x : 2.x) + - Then: + - y in [1, 4) ; [IMPLICIT_1,IMPLICIT_4) + - And: + - sqrt (y) in [1, 2) ; [IMPLICIT_1,IMPLICIT_2) + - + * 2. Bit by bit computation + * Let q = sqrt(y) truncated to i bit after binary point (q = 1), + * i 0 + * i+1 2 + * s = 2*q , and y = 2 * ( y - q ). (1) + * i i i i + * + * To compute q from q , one checks whether + * i+1 i + * + * -(i+1) 2 + * (q + 2 ) <= y. (2) + * i + * -(i+1) + * If (2) is false, then q = q ; otherwise q = q + 2 . + * i+1 i i+1 i + * + * With some algebric manipulation, it is not difficult to see + * that (2) is equivalent to + * -(i+1) + * s + 2 <= y (3) + * i i + * + * The advantage of (3) is that s and y can be computed by + * i i + * the following recurrence formula: + * if (3) is false + * + * s = s , y = y ; (4) + * i+1 i i+1 i + * + - + - NOTE: y = 2*y + - i+1 i + - + * otherwise, + * -i -(i+1) + * s = s + 2 , y = y - s - 2 (5) + * i+1 i i+1 i i + * + - + - -(i+1) + - NOTE: y = 2 (y - s - 2 ) + - i+1 i i + - + * One may easily use induction to prove (4) and (5). + * Note. Since the left hand side of (3) contain only i+2 bits, + * it does not necessary to do a full (53-bit) comparison + * in (3). + * 3. Final rounding + * After generating the 53 bits result, we compute one more bit. + * Together with the remainder, we can decide whether the + * result is exact, bigger than 1/2ulp, or less than 1/2ulp + * (it will never equal to 1/2ulp). + * The rounding mode can be detected by checking whether + * huge + tiny is equal to huge, and whether huge - tiny is + * equal to huge for some floating point number "huge" and "tiny". + * + * Special cases: + * sqrt(+-0) = +-0 ... exact + * sqrt(inf) = inf + * sqrt(-ve) = NaN ... with invalid signal + * sqrt(NaN) = NaN ... with invalid signal for signaling NaN + * + * Other methods : see the appended file at the end of the program below. + *--------------- + */ + + { + /* generate sqrt(x) bit by bit */ + unsigned64 y; + unsigned64 q; + unsigned64 s; + unsigned64 b; + + f->class = sim_fpu_class_number; + f->sign = 0; + y = r->fraction; + f->normal_exp = (r->normal_exp >> 1); /* exp = [exp/2] */ + + /* odd exp, double x to make it even */ + ASSERT (y >= IMPLICIT_1 && y < IMPLICIT_4); + if ((r->normal_exp & 1)) + { + y += y; + } + ASSERT (y >= IMPLICIT_1 && y < (IMPLICIT_2 << 1)); + + /* Let loop determine first value of s (either 1 or 2) */ + b = IMPLICIT_1; + q = 0; + s = 0; + + while (b) + { + unsigned64 t = s + b; + if (t <= y) + { + s |= (b << 1); + y -= t; + q |= b; + } + y <<= 1; + b >>= 1; + } + + ASSERT (q >= IMPLICIT_1 && q < IMPLICIT_2); + f->fraction = q; + if (y != 0) + { + f->fraction |= 1; /* stick remaining bits */ + return sim_fpu_status_inexact; + } + else + return 0; + } +} + + +/* int/long <-> sim_fpu */ + +INLINE_SIM_FPU (int) +sim_fpu_i32to (sim_fpu *f, + signed32 i, + sim_fpu_round round) +{ + i2fpu (f, i, 0); + return 0; +} + +INLINE_SIM_FPU (int) +sim_fpu_u32to (sim_fpu *f, + unsigned32 u, + sim_fpu_round round) +{ + u2fpu (f, u, 0); + return 0; +} + +INLINE_SIM_FPU (int) +sim_fpu_i64to (sim_fpu *f, + signed64 i, + sim_fpu_round round) +{ + i2fpu (f, i, 1); + return 0; +} + +INLINE_SIM_FPU (int) +sim_fpu_u64to (sim_fpu *f, + unsigned64 u, + sim_fpu_round round) +{ + u2fpu (f, u, 1); + return 0; +} + + +INLINE_SIM_FPU (int) +sim_fpu_to32i (signed32 *i, + const sim_fpu *f, + sim_fpu_round round) +{ + signed64 i64; + int status = fpu2i (&i64, f, 0, round); + *i = i64; + return status; +} + +INLINE_SIM_FPU (int) +sim_fpu_to32u (unsigned32 *u, + const sim_fpu *f, + sim_fpu_round round) +{ + unsigned64 u64; + int status = fpu2u (&u64, f, 0); + *u = u64; + return status; +} + +INLINE_SIM_FPU (int) +sim_fpu_to64i (signed64 *i, + const sim_fpu *f, + sim_fpu_round round) +{ + return fpu2i (i, f, 1, round); +} + + +INLINE_SIM_FPU (int) +sim_fpu_to64u (unsigned64 *u, + const sim_fpu *f, + sim_fpu_round round) +{ + return fpu2u (u, f, 1); +} + + + +/* sim_fpu -> host format */ + +#if 0 +INLINE_SIM_FPU (float) +sim_fpu_2f (const sim_fpu *f) +{ + return fval.d; +} +#endif + + +INLINE_SIM_FPU (double) +sim_fpu_2d (const sim_fpu *s) +{ + sim_fpu_map val; + if (sim_fpu_is_snan (s)) + { + /* gag SNaN's */ + sim_fpu n = *s; + n.class = sim_fpu_class_qnan; + val.i = pack_fpu (&n, 1); + } + else + { + val.i = pack_fpu (s, 1); + } + return val.d; +} + + +#if 0 +INLINE_SIM_FPU (void) +sim_fpu_f2 (sim_fpu *f, + float s) +{ + sim_fpu_map val; + val.d = s; + unpack_fpu (f, val.i, 1); +} +#endif + + +INLINE_SIM_FPU (void) +sim_fpu_d2 (sim_fpu *f, + double d) +{ + sim_fpu_map val; + val.d = d; + unpack_fpu (f, val.i, 1); +} + + +/* General */ + +INLINE_SIM_FPU (int) +sim_fpu_is_nan (const sim_fpu *d) +{ + switch (d->class) + { + case sim_fpu_class_qnan: + case sim_fpu_class_snan: + return 1; + default: + return 0; + } +} + +INLINE_SIM_FPU (int) +sim_fpu_is_qnan (const sim_fpu *d) +{ + switch (d->class) + { + case sim_fpu_class_qnan: + return 1; + default: + return 0; + } +} + +INLINE_SIM_FPU (int) +sim_fpu_is_snan (const sim_fpu *d) +{ + switch (d->class) + { + case sim_fpu_class_snan: + return 1; + default: + return 0; + } +} + +INLINE_SIM_FPU (int) +sim_fpu_is_zero (const sim_fpu *d) +{ + switch (d->class) + { + case sim_fpu_class_zero: + return 1; + default: + return 0; + } +} + +INLINE_SIM_FPU (int) +sim_fpu_is_infinity (const sim_fpu *d) +{ + switch (d->class) + { + case sim_fpu_class_infinity: + return 1; + default: + return 0; + } +} + +INLINE_SIM_FPU (int) +sim_fpu_is_number (const sim_fpu *d) +{ + switch (d->class) + { + case sim_fpu_class_denorm: + case sim_fpu_class_number: + return 1; + default: + return 0; + } +} + +INLINE_SIM_FPU (int) +sim_fpu_is_denorm (const sim_fpu *d) +{ + switch (d->class) + { + case sim_fpu_class_denorm: + return 1; + default: + return 0; + } +} + + +INLINE_SIM_FPU (int) +sim_fpu_sign (const sim_fpu *d) +{ + return d->sign; +} + + +INLINE_SIM_FPU (int) +sim_fpu_exp (const sim_fpu *d) +{ + return d->normal_exp; +} + + + +INLINE_SIM_FPU (int) +sim_fpu_is (const sim_fpu *d) +{ + switch (d->class) + { + case sim_fpu_class_qnan: + return SIM_FPU_IS_QNAN; + case sim_fpu_class_snan: + return SIM_FPU_IS_SNAN; + case sim_fpu_class_infinity: + if (d->sign) + return SIM_FPU_IS_NINF; + else + return SIM_FPU_IS_PINF; + case sim_fpu_class_number: + if (d->sign) + return SIM_FPU_IS_NNUMBER; + else + return SIM_FPU_IS_PNUMBER; + case sim_fpu_class_denorm: + if (d->sign) + return SIM_FPU_IS_NDENORM; + else + return SIM_FPU_IS_PDENORM; + case sim_fpu_class_zero: + if (d->sign) + return SIM_FPU_IS_NZERO; + else + return SIM_FPU_IS_PZERO; + default: + return -1; + abort (); + } +} + +INLINE_SIM_FPU (int) +sim_fpu_cmp (const sim_fpu *l, const sim_fpu *r) +{ + sim_fpu res; + sim_fpu_sub (&res, l, r); + return sim_fpu_is (&res); +} + +INLINE_SIM_FPU (int) +sim_fpu_is_lt (const sim_fpu *l, const sim_fpu *r) +{ + int status; + sim_fpu_lt (&status, l, r); + return status; +} + +INLINE_SIM_FPU (int) +sim_fpu_is_le (const sim_fpu *l, const sim_fpu *r) +{ + int is; + sim_fpu_le (&is, l, r); + return is; +} + +INLINE_SIM_FPU (int) +sim_fpu_is_eq (const sim_fpu *l, const sim_fpu *r) +{ + int is; + sim_fpu_eq (&is, l, r); + return is; +} + +INLINE_SIM_FPU (int) +sim_fpu_is_ne (const sim_fpu *l, const sim_fpu *r) +{ + int is; + sim_fpu_ne (&is, l, r); + return is; +} + +INLINE_SIM_FPU (int) +sim_fpu_is_ge (const sim_fpu *l, const sim_fpu *r) +{ + int is; + sim_fpu_ge (&is, l, r); + return is; +} + +INLINE_SIM_FPU (int) +sim_fpu_is_gt (const sim_fpu *l, const sim_fpu *r) +{ + int is; + sim_fpu_gt (&is, l, r); + return is; +} + + +/* Compare operators */ + +INLINE_SIM_FPU (int) +sim_fpu_lt (int *is, + const sim_fpu *l, + const sim_fpu *r) +{ + if (!sim_fpu_is_nan (l) && !sim_fpu_is_nan (r)) + { + sim_fpu_map lval; + sim_fpu_map rval; + lval.i = pack_fpu (l, 1); + rval.i = pack_fpu (r, 1); + (*is) = (lval.d < rval.d); + return 0; + } + else if (sim_fpu_is_snan (l) || sim_fpu_is_snan (r)) + { + *is = 0; + return sim_fpu_status_invalid_snan; + } + else + { + *is = 0; + return sim_fpu_status_invalid_qnan; + } +} + +INLINE_SIM_FPU (int) +sim_fpu_le (int *is, + const sim_fpu *l, + const sim_fpu *r) +{ + if (!sim_fpu_is_nan (l) && !sim_fpu_is_nan (r)) + { + sim_fpu_map lval; + sim_fpu_map rval; + lval.i = pack_fpu (l, 1); + rval.i = pack_fpu (r, 1); + *is = (lval.d <= rval.d); + return 0; + } + else if (sim_fpu_is_snan (l) || sim_fpu_is_snan (r)) + { + *is = 0; + return sim_fpu_status_invalid_snan; + } + else + { + *is = 0; + return sim_fpu_status_invalid_qnan; + } +} + +INLINE_SIM_FPU (int) +sim_fpu_eq (int *is, + const sim_fpu *l, + const sim_fpu *r) +{ + if (!sim_fpu_is_nan (l) && !sim_fpu_is_nan (r)) + { + sim_fpu_map lval; + sim_fpu_map rval; + lval.i = pack_fpu (l, 1); + rval.i = pack_fpu (r, 1); + (*is) = (lval.d == rval.d); + return 0; + } + else if (sim_fpu_is_snan (l) || sim_fpu_is_snan (r)) + { + *is = 0; + return sim_fpu_status_invalid_snan; + } + else + { + *is = 0; + return sim_fpu_status_invalid_qnan; + } +} + +INLINE_SIM_FPU (int) +sim_fpu_ne (int *is, + const sim_fpu *l, + const sim_fpu *r) +{ + if (!sim_fpu_is_nan (l) && !sim_fpu_is_nan (r)) + { + sim_fpu_map lval; + sim_fpu_map rval; + lval.i = pack_fpu (l, 1); + rval.i = pack_fpu (r, 1); + (*is) = (lval.d != rval.d); + return 0; + } + else if (sim_fpu_is_snan (l) || sim_fpu_is_snan (r)) + { + *is = 0; + return sim_fpu_status_invalid_snan; + } + else + { + *is = 0; + return sim_fpu_status_invalid_qnan; + } +} + +INLINE_SIM_FPU (int) +sim_fpu_ge (int *is, + const sim_fpu *l, + const sim_fpu *r) +{ + return sim_fpu_le (is, r, l); +} + +INLINE_SIM_FPU (int) +sim_fpu_gt (int *is, + const sim_fpu *l, + const sim_fpu *r) +{ + return sim_fpu_lt (is, r, l); +} + + +/* A number of useful constants */ + +#if EXTERN_SIM_FPU_P +const sim_fpu sim_fpu_zero = { + sim_fpu_class_zero, +}; +const sim_fpu sim_fpu_qnan = { + sim_fpu_class_qnan, +}; +const sim_fpu sim_fpu_one = { + sim_fpu_class_number, 0, IMPLICIT_1, 1 +}; +const sim_fpu sim_fpu_two = { + sim_fpu_class_number, 0, IMPLICIT_1, 2 +}; +const sim_fpu sim_fpu_max32 = { + sim_fpu_class_number, 0, LSMASK64 (NR_FRAC_GUARD, NR_GUARDS32), NORMAL_EXPMAX32 +}; +const sim_fpu sim_fpu_max64 = { + sim_fpu_class_number, 0, LSMASK64 (NR_FRAC_GUARD, NR_GUARDS64), NORMAL_EXPMAX64 +}; +#endif + + +/* For debugging */ + +INLINE_SIM_FPU (void) +sim_fpu_print_fpu (const sim_fpu *f, + sim_fpu_print_func *print, + void *arg) +{ + print (arg, "%s", f->sign ? "-" : "+"); + switch (f->class) + { + case sim_fpu_class_qnan: + print (arg, "0."); + print_bits (f->fraction, NR_FRAC_GUARD - 1, print, arg); + print (arg, "*QuietNaN"); + break; + case sim_fpu_class_snan: + print (arg, "0."); + print_bits (f->fraction, NR_FRAC_GUARD - 1, print, arg); + print (arg, "*SignalNaN"); + break; + case sim_fpu_class_zero: + print (arg, "0.0"); + break; + case sim_fpu_class_infinity: + print (arg, "INF"); + break; + case sim_fpu_class_number: + case sim_fpu_class_denorm: + print (arg, "1."); + print_bits (f->fraction, NR_FRAC_GUARD - 1, print, arg); + print (arg, "*2^%+-5d", f->normal_exp); + ASSERT (f->fraction >= IMPLICIT_1); + ASSERT (f->fraction < IMPLICIT_2); + } +} + + +INLINE_SIM_FPU (void) +sim_fpu_print_status (int status, + sim_fpu_print_func *print, + void *arg) +{ + int i = 1; + char *prefix = ""; + while (status >= i) + { + switch ((sim_fpu_status) (status & i)) + { + case sim_fpu_status_denorm: + print (arg, "%sD", prefix); + break; + case sim_fpu_status_invalid_snan: + print (arg, "%sSNaN", prefix); + break; + case sim_fpu_status_invalid_qnan: + print (arg, "%sQNaN", prefix); + break; + case sim_fpu_status_invalid_isi: + print (arg, "%sISI", prefix); + break; + case sim_fpu_status_invalid_idi: + print (arg, "%sIDI", prefix); + break; + case sim_fpu_status_invalid_zdz: + print (arg, "%sZDZ", prefix); + break; + case sim_fpu_status_invalid_imz: + print (arg, "%sIMZ", prefix); + break; + case sim_fpu_status_invalid_cvi: + print (arg, "%sCVI", prefix); + break; + case sim_fpu_status_invalid_cmp: + print (arg, "%sCMP", prefix); + break; + case sim_fpu_status_invalid_sqrt: + print (arg, "%sSQRT", prefix); + break; + break; + case sim_fpu_status_inexact: + print (arg, "%sX", prefix); + break; + break; + case sim_fpu_status_overflow: + print (arg, "%sO", prefix); + break; + break; + case sim_fpu_status_underflow: + print (arg, "%sU", prefix); + break; + break; + case sim_fpu_status_invalid_div0: + print (arg, "%s/", prefix); + break; + break; + case sim_fpu_status_rounded: + print (arg, "%sR", prefix); + break; + break; + } + i <<= 1; + prefix = ","; + } +} + +#endif diff --git a/sim/common/sim-fpu.h b/sim/common/sim-fpu.h new file mode 100644 index 0000000..05d53c2 --- /dev/null +++ b/sim/common/sim-fpu.h @@ -0,0 +1,417 @@ +/* Simulator Floating-point support. + Copyright (C) 1997-1998 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + + +#ifndef SIM_FPU_H +#define SIM_FPU_H + + + +/* The FPU intermediate type - this object, passed by reference, + should be treated as opaque. + + + Pragmatics - pass struct by ref: + + The alternatives for this object/interface that were considered + were: a packed 64 bit value; an unpacked structure passed by value; + and an unpacked structure passed by reference. + + The packed 64 bit value was rejected because: it limited the + precision of intermediate values; reasonable performance would only + be achieved when the sim_fpu package was in-lined allowing repeated + unpacking operations to be eliminated. + + For unpacked structures (passed by value and reference), the code + quality of GCC-2.7 (on x86) for each alternative was compared. + Needless to say the results, while better then for a packed 64 bit + object, were still poor (GCC had only limited support for the + optimization of references to structure members). Regardless, the + struct-by-ref alternative achieved better results when compiled + with (better speed) and without (better code density) in-lining. + Here's looking forward to an improved GCC optimizer. + + + Pragmatics - avoid host FP hardware: + + FP operations can be implemented by either: the host's floating + point hardware; or by emulating the FP operations using integer + only routines. This is direct tradeoff between speed, portability + and correctness. + + The two principal reasons for selecting portability and correctness + over speed are: + + 1 - Correctness. The assumption that FP correctness wasn't an + issue for code being run on simulators was wrong. Instead of + running FP tolerant (?) code, simulator users instead typically run + very aggressive FP code sequences. The sole purpose of those + sequences being to test the target ISA's FP implementation. + + 2 - Portability. The host FP implementation is not predictable. A + simulator modeling aggressive FP code sequences using the hosts FPU + relies heavily on the correctness of the hosts FP implementation. + It turns out that such trust can be misplaced. The behavior of + host FP implementations when handling edge conditions such as SNaNs + and exceptions varied widely. + + + */ + + +typedef enum +{ + sim_fpu_class_zero, + sim_fpu_class_snan, + sim_fpu_class_qnan, + sim_fpu_class_number, + sim_fpu_class_denorm, + sim_fpu_class_infinity, +} sim_fpu_class; + +typedef struct _sim_fpu { + sim_fpu_class class; + int sign; + unsigned64 fraction; + int normal_exp; +} sim_fpu; + + + +/* Rounding options. + + The value zero (sim_fpu_round_default) for ALU operations indicates + that, when possible, rounding should be avoided. */ + +typedef enum +{ + sim_fpu_round_default = 0, + sim_fpu_round_near = 1, + sim_fpu_round_zero = 2, + sim_fpu_round_up = 3, + sim_fpu_round_down = 4, +} sim_fpu_round; + + +/* Options when handling denormalized numbers. */ + +typedef enum +{ + sim_fpu_denorm_default = 0, + sim_fpu_denorm_underflow_inexact = 1, + sim_fpu_denorm_zero = 2, +} sim_fpu_denorm; + + + +/* Status values returned by FPU operators. + + When checking the result of an FP sequence (ex 32to, add, single, + to32) the caller may either: check the return value of each FP + operator; or form the union (OR) of the returned values and examine + them once at the end. + + FIXME: This facility is still being developed. The choice of + status values returned and their exact meaning may changed in the + future. */ + +typedef enum +{ + sim_fpu_status_invalid_snan = 1, + sim_fpu_status_invalid_qnan = 2, + sim_fpu_status_invalid_isi = 4, /* (inf - inf) */ + sim_fpu_status_invalid_idi = 8, /* (inf / inf) */ + sim_fpu_status_invalid_zdz = 16, /* (0 / 0) */ + sim_fpu_status_invalid_imz = 32, /* (inf * 0) */ + sim_fpu_status_invalid_cvi = 64, /* convert to integer */ + sim_fpu_status_invalid_div0 = 128, /* (X / 0) */ + sim_fpu_status_invalid_cmp = 256, /* compare */ + sim_fpu_status_invalid_sqrt = 512, + sim_fpu_status_rounded = 1024, + sim_fpu_status_inexact = 2048, + sim_fpu_status_overflow = 4096, + sim_fpu_status_underflow = 8192, + sim_fpu_status_denorm = 16384, +} sim_fpu_status; + + + + +/* Directly map between a 32/64 bit register and the sim_fpu internal + type. + + When converting from the 32/64 bit packed format to the sim_fpu + internal type, the operation is exact. + + When converting from the sim_fpu internal type to 32/64 bit packed + format, the operation may result in a loss of precision. The + configuration macro WITH_FPU_CONVERSION controls this. By default, + silent round to nearest is performed. Alternativly, round up, + round down and round to zero can be performed. In a simulator + emulating exact FPU behavour, sim_fpu_round_{32,64} should be + called before packing the sim_fpu value. */ + +INLINE_SIM_FPU (void) sim_fpu_32to (sim_fpu *f, unsigned32 s); +INLINE_SIM_FPU (void) sim_fpu_232to (sim_fpu *f, unsigned32 h, unsigned32 l); +INLINE_SIM_FPU (void) sim_fpu_64to (sim_fpu *f, unsigned64 d); + +INLINE_SIM_FPU (void) sim_fpu_to32 (unsigned32 *s, const sim_fpu *f); +INLINE_SIM_FPU (void) sim_fpu_to232 (unsigned32 *h, unsigned32 *l, const sim_fpu *f); +INLINE_SIM_FPU (void) sim_fpu_to64 (unsigned64 *d, const sim_fpu *f); + + +/* Create a sim_fpu struct using raw information. (FRACTION & LSMASK + (PRECISION-1, 0)) is assumed to contain the fraction part of the + floating-point number. The leading bit LSBIT (PRECISION) is always + implied. The number created can be represented by: + + (SIGN ? "-" : "+") "1." FRACTION{PRECISION-1,0} X 2 ^ NORMAL_EXP> + + You can not specify zero using this function. */ + +INLINE_SIM_FPU (void) sim_fpu_fractionto (sim_fpu *f, int sign, int normal_exp, unsigned64 fraction, int precision); + +/* Reverse operaton. If S is a non-zero number, discards the implied + leading one and returns PRECISION fraction bits. No rounding is + performed. */ +INLINE_SIM_FPU (unsigned64) sim_fpu_tofraction (const sim_fpu *s, int precision); + + + +/* Rounding operators. + + Force an intermediate result to an exact 32/64 bit + representation. */ + +INLINE_SIM_FPU (int) sim_fpu_round_32 (sim_fpu *f, + sim_fpu_round round, + sim_fpu_denorm denorm); +INLINE_SIM_FPU (int) sim_fpu_round_64 (sim_fpu *f, + sim_fpu_round round, + sim_fpu_denorm denorm); + + + +/* Arrithmetic operators. + + FIXME: In the future, additional arguments ROUNDING and BITSIZE may + be added. */ + +typedef int (sim_fpu_op1) (sim_fpu *f, + const sim_fpu *l); +typedef int (sim_fpu_op2) (sim_fpu *f, + const sim_fpu *l, + const sim_fpu *r); + +INLINE_SIM_FPU (int) sim_fpu_add (sim_fpu *f, + const sim_fpu *l, const sim_fpu *r); +INLINE_SIM_FPU (int) sim_fpu_sub (sim_fpu *f, + const sim_fpu *l, const sim_fpu *r); +INLINE_SIM_FPU (int) sim_fpu_mul (sim_fpu *f, + const sim_fpu *l, const sim_fpu *r); +INLINE_SIM_FPU (int) sim_fpu_div (sim_fpu *f, + const sim_fpu *l, const sim_fpu *r); +INLINE_SIM_FPU (int) sim_fpu_max (sim_fpu *f, + const sim_fpu *l, const sim_fpu *r); +INLINE_SIM_FPU (int) sim_fpu_min (sim_fpu *f, + const sim_fpu *l, const sim_fpu *r); +INLINE_SIM_FPU (int) sim_fpu_neg (sim_fpu *f, + const sim_fpu *a); +INLINE_SIM_FPU (int) sim_fpu_abs (sim_fpu *f, + const sim_fpu *a); +INLINE_SIM_FPU (int) sim_fpu_inv (sim_fpu *f, + const sim_fpu *a); +INLINE_SIM_FPU (int) sim_fpu_sqrt (sim_fpu *f, + const sim_fpu *sqr); + + + +/* Conversion of integer <-> floating point. */ + +INLINE_SIM_FPU (int) sim_fpu_i32to (sim_fpu *f, signed32 i, + sim_fpu_round round); +INLINE_SIM_FPU (int) sim_fpu_u32to (sim_fpu *f, unsigned32 u, + sim_fpu_round round); +INLINE_SIM_FPU (int) sim_fpu_i64to (sim_fpu *f, signed64 i, + sim_fpu_round round); +INLINE_SIM_FPU (int) sim_fpu_u64to (sim_fpu *f, unsigned64 u, + sim_fpu_round round); +#if 0 +INLINE_SIM_FPU (int) sim_fpu_i232to (sim_fpu *f, signed32 h, signed32 l, + sim_fpu_round round); +#endif +#if 0 +INLINE_SIM_FPU (int) sim_fpu_u232to (sim_fpu *f, unsigned32 h, unsigned32 l, + sim_fpu_round round); +#endif + +INLINE_SIM_FPU (int) sim_fpu_to32i (signed32 *i, const sim_fpu *f, + sim_fpu_round round); +INLINE_SIM_FPU (int) sim_fpu_to32u (unsigned32 *u, const sim_fpu *f, + sim_fpu_round round); +INLINE_SIM_FPU (int) sim_fpu_to64i (signed64 *i, const sim_fpu *f, + sim_fpu_round round); +INLINE_SIM_FPU (int) sim_fpu_to64u (unsigned64 *u, const sim_fpu *f, + sim_fpu_round round); +#if 0 +INLINE_SIM_FPU (int) sim_fpu_to232i (signed64 *h, signed64 *l, const sim_fpu *f, + sim_fpu_round round); +#endif +#if 0 +INLINE_SIM_FPU (int) sim_fpu_to232u (unsigned64 *h, unsigned64 *l, const sim_fpu *f, + sim_fpu_round round); +#endif + + +/* Conversion of internal sim_fpu type to host double format. + + For debuging/tracing only. A SNaN is never returned. */ + +/* INLINE_SIM_FPU (float) sim_fpu_2f (const sim_fpu *f); */ +INLINE_SIM_FPU (double) sim_fpu_2d (const sim_fpu *d); + +/* INLINE_SIM_FPU (void) sim_fpu_f2 (sim_fpu *f, float s); */ +INLINE_SIM_FPU (void) sim_fpu_d2 (sim_fpu *f, double d); + + + +/* Specific number classes. + + NB: When either, a 32/64 bit floating points is converted to + internal format, or an internal format number is rounded to 32/64 + bit precision, a special marker is retained that indicates that the + value was normalized. For such numbers both is_number and + is_denorm return true. */ + +INLINE_SIM_FPU (int) sim_fpu_is_nan (const sim_fpu *s); /* 1 => SNaN or QNaN */ +INLINE_SIM_FPU (int) sim_fpu_is_snan (const sim_fpu *s); /* 1 => SNaN */ +INLINE_SIM_FPU (int) sim_fpu_is_qnan (const sim_fpu *s); /* 1 => QNaN */ + +INLINE_SIM_FPU (int) sim_fpu_is_zero (const sim_fpu *s); +INLINE_SIM_FPU (int) sim_fpu_is_infinity (const sim_fpu *s); +INLINE_SIM_FPU (int) sim_fpu_is_number (const sim_fpu *s); /* !zero */ +INLINE_SIM_FPU (int) sim_fpu_is_denorm (const sim_fpu *s); /* !zero */ + + + +/* Floating point fields */ + +INLINE_SIM_FPU (int) sim_fpu_sign (const sim_fpu *s); +INLINE_SIM_FPU (int) sim_fpu_exp (const sim_fpu *s); + + + +/* Specific comparison operators + + For NaNs et.al., the comparison operators will set IS to zero and + return a nonzero result. */ + +INLINE_SIM_FPU (int) sim_fpu_lt (int *is, const sim_fpu *l, const sim_fpu *r); +INLINE_SIM_FPU (int) sim_fpu_le (int *is, const sim_fpu *l, const sim_fpu *r); +INLINE_SIM_FPU (int) sim_fpu_eq (int *is, const sim_fpu *l, const sim_fpu *r); +INLINE_SIM_FPU (int) sim_fpu_ne (int *is, const sim_fpu *l, const sim_fpu *r); +INLINE_SIM_FPU (int) sim_fpu_ge (int *is, const sim_fpu *l, const sim_fpu *r); +INLINE_SIM_FPU (int) sim_fpu_gt (int *is, const sim_fpu *l, const sim_fpu *r); + +INLINE_SIM_FPU (int) sim_fpu_is_lt (const sim_fpu *l, const sim_fpu *r); +INLINE_SIM_FPU (int) sim_fpu_is_le (const sim_fpu *l, const sim_fpu *r); +INLINE_SIM_FPU (int) sim_fpu_is_eq (const sim_fpu *l, const sim_fpu *r); +INLINE_SIM_FPU (int) sim_fpu_is_ne (const sim_fpu *l, const sim_fpu *r); +INLINE_SIM_FPU (int) sim_fpu_is_ge (const sim_fpu *l, const sim_fpu *r); +INLINE_SIM_FPU (int) sim_fpu_is_gt (const sim_fpu *l, const sim_fpu *r); + + + +/* General number class and comparison operators. + + The result of the comparison is indicated by returning one of the + values below. Efficient emulation of a target FP compare + instruction can be achieved by redefining the values below to match + corresponding target FP status bits. + + For instance. SIM_FPU_QNAN may be redefined to be the bit + `INVALID' while SIM_FPU_NINF might be redefined as the bits + `NEGATIVE | INFINITY | VALID'. */ + +#ifndef SIM_FPU_IS_SNAN +enum { + SIM_FPU_IS_SNAN = 1, /* Noisy not-a-number */ + SIM_FPU_IS_QNAN = 2, /* Quite not-a-number */ + SIM_FPU_IS_NINF = 3, /* -infinity */ + SIM_FPU_IS_PINF = 4, /* +infinity */ + SIM_FPU_IS_NNUMBER = 5, /* -number - [ -MAX .. -MIN ] */ + SIM_FPU_IS_PNUMBER = 6, /* +number - [ +MIN .. +MAX ] */ + SIM_FPU_IS_NDENORM = 7, /* -denorm - ( MIN .. 0 ) */ + SIM_FPU_IS_PDENORM = 8, /* +denorm - ( 0 .. MIN ) */ + SIM_FPU_IS_NZERO = 9, /* -0 */ + SIM_FPU_IS_PZERO = 10, /* +0 */ +}; +#endif + +INLINE_SIM_FPU (int) sim_fpu_is (const sim_fpu *l); +INLINE_SIM_FPU (int) sim_fpu_cmp (const sim_fpu *l, const sim_fpu *r); + + + +/* A constant of useful numbers */ + +extern const sim_fpu sim_fpu_zero; +extern const sim_fpu sim_fpu_one; +extern const sim_fpu sim_fpu_two; +extern const sim_fpu sim_fpu_qnan; +extern const sim_fpu sim_fpu_max32; +extern const sim_fpu sim_fpu_max64; + + +/* Select the applicable functions for the fp_word type */ + +#if WITH_TARGET_FLOATING_POINT_BITSIZE == 32 +#define sim_fpu_tofp sim_fpu_to32 +#define sim_fpu_fpto sim_fpu_32to +#define sim_fpu_round_fp sim_fpu_round_32 +#define sim_fpu_maxfp sim_fpu_max32 +#endif +#if WITH_TARGET_FLOATING_POINT_BITSIZE == 64 +#define sim_fpu_tofp sim_fpu_to64 +#define sim_fpu_fpto sim_fpu_64to +#define sim_fpu_round_fp sim_fpu_round_64 +#define sim_fpu_maxfp sim_fpu_max64 +#endif + + + +/* For debugging */ + +typedef void sim_fpu_print_func (void *, char *, ...); + +INLINE_SIM_FPU (void) sim_fpu_print_fpu (const sim_fpu *f, + sim_fpu_print_func *print, + void *arg); + +INLINE_SIM_FPU (void) sim_fpu_print_status (int status, + sim_fpu_print_func *print, + void *arg); + +#if H_REVEALS_MODULE_P (SIM_FPU_INLINE) +#include "sim-fpu.c" +#endif + +#endif diff --git a/sim/common/sim-hload.c b/sim/common/sim-hload.c new file mode 100644 index 0000000..e4016f4 --- /dev/null +++ b/sim/common/sim-hload.c @@ -0,0 +1,69 @@ +/* Generic load for hardware simulator models. + Copyright (C) 1997 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "sim-main.h" +#include "bfd.h" +#include "sim-utils.h" +#include "sim-assert.h" + + +/* Generic implementation of sim_load that works with simulators + modeling a hardware platform. */ + +SIM_RC +sim_load (sd, prog_name, prog_bfd, from_tty) + SIM_DESC sd; + char *prog_name; + struct _bfd *prog_bfd; + int from_tty; +{ + bfd *result_bfd; + + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + if (sim_analyze_program (sd, prog_name, prog_bfd) != SIM_RC_OK) + return SIM_RC_FAIL; + SIM_ASSERT (STATE_PROG_BFD (sd) != NULL); + + /* NOTE: For historical reasons, older hardware simulators + incorrectly write the program sections at LMA interpreted as a + virtual address. This is still accommodated for backward + compatibility reasons. */ + /* FIXME: The following simulators use this file as of 980313: + m32r, mips, v850 [grep for sim-hload in all Makefile.in's]. + Each of these should be properly using lma. When this is confirmed, + SIM_HANDLES_LMA can go away. */ +#ifndef SIM_HANDLES_LMA +#define SIM_HANDLES_LMA 0 +#endif + + result_bfd = sim_load_file (sd, STATE_MY_NAME (sd), + STATE_CALLBACK (sd), + prog_name, + STATE_PROG_BFD (sd), + STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG, + SIM_HANDLES_LMA, sim_write); + if (result_bfd == NULL) + { + bfd_close (STATE_PROG_BFD (sd)); + STATE_PROG_BFD (sd) = NULL; + return SIM_RC_FAIL; + } + return SIM_RC_OK; +} diff --git a/sim/common/sim-hrw.c b/sim/common/sim-hrw.c new file mode 100644 index 0000000..9538302 --- /dev/null +++ b/sim/common/sim-hrw.c @@ -0,0 +1,41 @@ +/* Generic memory read/write for hardware simulator models. + Copyright (C) 1997 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "sim-main.h" +#include "sim-assert.h" + +/* Generic implementation of sim_read that works with simulators + modeling real hardware */ + +int +sim_read (SIM_DESC sd, SIM_ADDR mem, unsigned char *buf, int length) +{ + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + return sim_core_read_buffer (sd, NULL, read_map, + buf, mem, length); +} + +int +sim_write (SIM_DESC sd, SIM_ADDR mem, unsigned char *buf, int length) +{ + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + return sim_core_write_buffer (sd, NULL, write_map, + buf, mem, length); +} diff --git a/sim/common/sim-hw.c b/sim/common/sim-hw.c new file mode 100644 index 0000000..f438462 --- /dev/null +++ b/sim/common/sim-hw.c @@ -0,0 +1,508 @@ +/* Simulator hardware option handling. + Copyright (C) 1998 Free Software Foundation, Inc. + Contributed by Cygnus Support and Andrew Cagney. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "sim-main.h" +#include "sim-assert.h" +#include "sim-options.h" + +#include "sim-hw.h" + +#include "hw-tree.h" +#include "hw-device.h" +#include "hw-main.h" +#include "hw-base.h" + + +#ifdef HAVE_STRING_H +#include <string.h> +#else +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#include <ctype.h> +#include <sys/errno.h> + + +struct sim_hw { + struct hw *tree; + int trace_p; + int info_p; + /* if called from a processor */ + sim_cpu *cpu; + sim_cia cia; +}; + + +struct hw * +sim_hw_parse (struct sim_state *sd, + const char *fmt, + ...) +{ + struct hw *current; + va_list ap; + va_start (ap, fmt); + current = hw_tree_vparse (STATE_HW (sd)->tree, fmt, ap); + va_end (ap); + return current; +} + +struct printer { + struct sim_state *file; + void (*print) (struct sim_state *, const char *, va_list ap); +}; + +static void +do_print (void *file, const char *fmt, ...) +{ + struct printer *p = file; + va_list ap; + va_start (ap, fmt); + p->print (p->file, fmt, ap); + va_end (ap); +} + +void +sim_hw_print (struct sim_state *sd, + void (*print) (struct sim_state *, const char *, va_list ap)) +{ + struct printer p; + p.file = sd; + p.print = print; + hw_tree_print (STATE_HW (sd)->tree, do_print, &p); +} + + + + +/* command line options. */ + +enum { + OPTION_HW_INFO = OPTION_START, + OPTION_HW_TRACE, + OPTION_HW_DEVICE, + OPTION_HW_FILE, +}; + +static DECLARE_OPTION_HANDLER (hw_option_handler); + +static const OPTION hw_options[] = +{ + { {"hw-info", no_argument, NULL, OPTION_HW_INFO }, + '\0', NULL, "List configurable hw regions", + hw_option_handler }, + { {"info-hw", no_argument, NULL, OPTION_HW_INFO }, + '\0', NULL, NULL, + hw_option_handler }, + + { {"hw-trace", optional_argument, NULL, OPTION_HW_TRACE }, + '\0', "on|off", "Trace all hardware devices", + hw_option_handler }, + { {"trace-hw", optional_argument, NULL, OPTION_HW_TRACE }, + '\0', NULL, NULL, + hw_option_handler }, + + { {"hw-device", required_argument, NULL, OPTION_HW_DEVICE }, + '\0', "DEVICE", "Add the specified device", + hw_option_handler }, + + { {"hw-file", required_argument, NULL, OPTION_HW_FILE }, + '\0', "FILE", "Add the devices listed in the file", + hw_option_handler }, + + { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL } +}; + + + +/* Copied from ../ppc/psim.c:psim_merge_device_file() */ + +static SIM_RC +merge_device_file (struct sim_state *sd, + const char *file_name) +{ + FILE *description; + struct hw *current = STATE_HW (sd)->tree; + int line_nr; + char device_path[1000]; + + /* try opening the file */ + description = fopen (file_name, "r"); + if (description == NULL) + { + perror (file_name); + return SIM_RC_FAIL; + } + + line_nr = 0; + while (fgets (device_path, sizeof(device_path), description)) + { + char *device; + /* check that a complete line was read */ + if (strchr (device_path, '\n') == NULL) + { + fclose (description); + sim_io_eprintf (sd, "%s:%d: line to long", file_name, line_nr); + return SIM_RC_FAIL; + } + *strchr (device_path, '\n') = '\0'; + line_nr++; + /* skip comments ("#" or ";") and blank lines lines */ + for (device = device_path; + *device != '\0' && isspace (*device); + device++); + if (device[0] == '#' + || device[0] == ';' + || device[0] == '\0') + continue; + /* merge any appended lines */ + while (device_path[strlen (device_path) - 1] == '\\') + { + int curlen = strlen (device_path) - 1; + /* zap the `\' at the end of the line */ + device_path[curlen] = '\0'; + /* append the next line */ + if (!fgets (device_path + curlen, + sizeof (device_path) - curlen, + description)) + { + fclose (description); + sim_io_eprintf (sd, "%s:%d: unexpected eof", file_name, line_nr); + return SIM_RC_FAIL; + } + if (strchr(device_path, '\n') == NULL) + { + fclose(description); + sim_io_eprintf (sd, "%s:%d: line to long", file_name, line_nr); + return SIM_RC_FAIL; + } + *strchr(device_path, '\n') = '\0'; + line_nr++; + } + /* parse this line */ + current = hw_tree_parse (current, "%s", device); + } + fclose (description); + return SIM_RC_OK; +} + + +static SIM_RC +hw_option_handler (struct sim_state *sd, sim_cpu *cpu, int opt, + char *arg, int is_command) +{ + switch (opt) + { + + case OPTION_HW_INFO: + { + /* delay info until after the tree is finished */ + STATE_HW (sd)->info_p = 1; + return SIM_RC_OK; + break; + } + + case OPTION_HW_TRACE: + { + if (arg == NULL) + { + STATE_HW (sd)->trace_p = 1; + } + else if (strcmp (arg, "yes") == 0 + || strcmp (arg, "on") == 0) + { + STATE_HW (sd)->trace_p = 1; + } + else if (strcmp (arg, "no") == 0 + || strcmp (arg, "off") == 0) + { + STATE_HW (sd)->trace_p = 0; + } + else + { + sim_io_eprintf (sd, "Option --hw-trace ignored\n"); + /* set tracing on all devices */ + return SIM_RC_FAIL; + } + /* FIXME: Not very nice - see also hw-base.c */ + if (STATE_HW (sd)->trace_p) + hw_tree_parse (STATE_HW (sd)->tree, "/global-trace? true"); + return SIM_RC_OK; + break; + } + + case OPTION_HW_DEVICE: + { + hw_tree_parse (STATE_HW (sd)->tree, arg); + return SIM_RC_OK; + } + + case OPTION_HW_FILE: + { + return merge_device_file (sd, arg); + } + + default: + sim_io_eprintf (sd, "Unknown hw option %d\n", opt); + return SIM_RC_FAIL; + + } + + return SIM_RC_FAIL; +} + + +/* "hw" module install handler. + + This is called via sim_module_install to install the "hw" subsystem + into the simulator. */ + +static MODULE_INIT_FN sim_hw_init; +static MODULE_UNINSTALL_FN sim_hw_uninstall; + +SIM_RC +sim_hw_install (struct sim_state *sd) +{ + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + sim_add_option_table (sd, NULL, hw_options); + sim_module_add_uninstall_fn (sd, sim_hw_uninstall); + sim_module_add_init_fn (sd, sim_hw_init); + STATE_HW (sd) = ZALLOC (struct sim_hw); + STATE_HW (sd)->tree = hw_tree_create (sd, "core"); + return SIM_RC_OK; +} + + +static SIM_RC +sim_hw_init (struct sim_state *sd) +{ + /* FIXME: anything needed? */ + hw_tree_finish (STATE_HW (sd)->tree); + if (STATE_HW (sd)->info_p) + sim_hw_print (sd, sim_io_vprintf); + return SIM_RC_OK; +} + +/* Uninstall the "hw" subsystem from the simulator. */ + +static void +sim_hw_uninstall (struct sim_state *sd) +{ + /* hw_tree_delete (STATE_HW (sd)->tree); */ + zfree (STATE_HW (sd)); + STATE_HW (sd) = NULL; +} + + + +/* Data transfers to/from the hardware device tree. There are several + cases. */ + + +/* CPU: The simulation is running and the current CPU/CIA + initiates a data transfer. */ + +void +sim_cpu_hw_io_read_buffer (sim_cpu *cpu, + sim_cia cia, + struct hw *hw, + void *dest, + int space, + unsigned_word addr, + unsigned nr_bytes) +{ + SIM_DESC sd = CPU_STATE (cpu); + STATE_HW (sd)->cpu = cpu; + STATE_HW (sd)->cia = cia; + if (hw_io_read_buffer (hw, dest, space, addr, nr_bytes) != nr_bytes) + sim_engine_abort (sd, cpu, cia, "broken CPU read"); +} + +void +sim_cpu_hw_io_write_buffer (sim_cpu *cpu, + sim_cia cia, + struct hw *hw, + const void *source, + int space, + unsigned_word addr, + unsigned nr_bytes) +{ + SIM_DESC sd = CPU_STATE (cpu); + STATE_HW (sd)->cpu = cpu; + STATE_HW (sd)->cia = cia; + if (hw_io_write_buffer (hw, source, space, addr, nr_bytes) != nr_bytes) + sim_engine_abort (sd, cpu, cia, "broken CPU write"); +} + + + + +/* SYSTEM: A data transfer is being initiated by the system. */ + +unsigned +sim_hw_io_read_buffer (struct sim_state *sd, + struct hw *hw, + void *dest, + int space, + unsigned_word addr, + unsigned nr_bytes) +{ + STATE_HW (sd)->cpu = NULL; + return hw_io_read_buffer (hw, dest, space, addr, nr_bytes); +} + +unsigned +sim_hw_io_write_buffer (struct sim_state *sd, + struct hw *hw, + const void *source, + int space, + unsigned_word addr, + unsigned nr_bytes) +{ + STATE_HW (sd)->cpu = NULL; + return hw_io_write_buffer (hw, source, space, addr, nr_bytes); +} + + + +/* Abort the simulation specifying HW as the reason */ + +void +hw_vabort (struct hw *me, + const char *fmt, + va_list ap) +{ + const char *name; + char *msg; + /* find an identity */ + if (me != NULL && hw_path (me) != NULL && hw_path (me) [0] != '\0') + name = hw_path (me); + else if (me != NULL && hw_name (me) != NULL && hw_name (me)[0] != '\0') + name = hw_name (me); + else if (me != NULL && hw_family (me) != NULL && hw_family (me)[0] != '\0') + name = hw_family (me); + else + name = "device"; + /* construct an updated format string */ + msg = alloca (strlen (name) + strlen (": ") + strlen (fmt) + 1); + strcpy (msg, name); + strcat (msg, ": "); + strcat (msg, fmt); + /* report the problem */ + sim_engine_vabort (hw_system (me), + STATE_HW (hw_system (me))->cpu, + STATE_HW (hw_system (me))->cia, + msg, ap); +} + +void +hw_abort (struct hw *me, + const char *fmt, + ...) +{ + va_list ap; + /* report the problem */ + va_start (ap, fmt); + hw_vabort (me, fmt, ap); + va_end (ap); +} + +void +sim_hw_abort (struct sim_state *sd, + struct hw *me, + const char *fmt, + ...) +{ + va_list ap; + va_start (ap, fmt); + if (me == NULL) + sim_engine_vabort (sd, NULL, NULL_CIA, fmt, ap); + else + hw_vabort (me, fmt, ap); + va_end (ap); +} + + +/* MISC routines to tie HW into the rest of the system */ + +void +hw_halt (struct hw *me, + int reason, + int status) +{ + struct sim_state *sd = hw_system (me); + struct sim_hw *sim = STATE_HW (sd); + sim_engine_halt (sd, sim->cpu, NULL, sim->cia, reason, status); +} + +struct _sim_cpu * +hw_system_cpu (struct hw *me) +{ + return STATE_HW (hw_system (me))->cpu; +} + +void +hw_trace (struct hw *me, + const char *fmt, + ...) +{ + if (hw_trace_p (me)) /* to be sure, to be sure */ + { + va_list ap; + va_start (ap, fmt); + sim_io_eprintf (hw_system (me), "%s: ", hw_path (me)); + sim_io_evprintf (hw_system (me), fmt, ap); + sim_io_eprintf (hw_system (me), "\n"); + va_end (ap); + } +} + + +/* Based on gdb-4.17/sim/ppc/main.c:sim_io_read_stdin() */ + +int +do_hw_poll_read (struct hw *me, + do_hw_poll_read_method *read, + int sim_io_fd, + void *buf, + unsigned sizeof_buf) +{ + int status = read (hw_system (me), sim_io_fd, buf, sizeof_buf); + if (status > 0) + return status; + else if (status == 0 && sizeof_buf == 0) + return 0; + else if (status == 0) + return HW_IO_EOF; + else /* status < 0 */ + { +#ifdef EAGAIN + if (STATE_CALLBACK (hw_system (me))->last_errno == EAGAIN) + return HW_IO_NOT_READY; + else + return HW_IO_EOF; +#else + return HW_IO_EOF; +#endif + } +} diff --git a/sim/common/sim-hw.h b/sim/common/sim-hw.h new file mode 100644 index 0000000..1bebd18 --- /dev/null +++ b/sim/common/sim-hw.h @@ -0,0 +1,98 @@ +/* Device definitions. + Copyright (C) 1998 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef SIM_HW_H +#define SIM_HW_H + + +/* Establish this object */ + +SIM_RC sim_hw_install +(struct sim_state *sd); + + +/* Parse a hardware definition */ + +struct hw *sim_hw_parse +(struct sim_state *sd, + const char *fmt, + ...) __attribute__ ((format (printf, 2, 3))); + + +/* Print the hardware tree */ + +void sim_hw_print +(struct sim_state *sd, + void (*print) (struct sim_state *, const char *, va_list ap)); + + +/* Abort the simulation specifying HW as the reason */ + +void sim_hw_abort +(SIM_DESC sd, + struct hw *hw, + const char *fmt, + ...) __attribute__ ((format (printf, 3, 4))); + + + +/* CPU: The simulation is running and the current CPU/CIA + initiates a data transfer. */ + +void sim_cpu_hw_io_read_buffer +(sim_cpu *cpu, + sim_cia cia, + struct hw *hw, + void *dest, + int space, + unsigned_word addr, + unsigned nr_bytes); + +void sim_cpu_hw_io_write_buffer +(sim_cpu *cpu, + sim_cia cia, + struct hw *hw, + const void *source, + int space, + unsigned_word addr, + unsigned nr_bytes); + + + +/* SYSTEM: A data transfer is being initiated by the system. */ + +unsigned sim_hw_io_read_buffer +(struct sim_state *sd, + struct hw *hw, + void *dest, + int space, + unsigned_word addr, + unsigned nr_bytes); + +unsigned sim_hw_io_write_buffer +(struct sim_state *sd, + struct hw *hw, + const void *source, + int space, + unsigned_word addr, + unsigned nr_bytes); + + +#endif diff --git a/sim/common/sim-info.c b/sim/common/sim-info.c new file mode 100644 index 0000000..0083227 --- /dev/null +++ b/sim/common/sim-info.c @@ -0,0 +1,32 @@ +/* Generic memory read/write for hardware simulator models. + Copyright (C) 1998 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "sim-main.h" +#include "sim-assert.h" + +/* Generic implementation of sim_info that works with simulators using + sim-module. */ + +void +sim_info (SIM_DESC sd, int verbose) +{ + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + sim_module_info (sd, verbose || STATE_VERBOSE_P (sd)); +} diff --git a/sim/common/sim-inline.c b/sim/common/sim-inline.c new file mode 100644 index 0000000..770c65e --- /dev/null +++ b/sim/common/sim-inline.c @@ -0,0 +1,96 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au> + Copyright (C) 1997, Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef SIM_INLINE_C +#define SIM_INLINE_C + +#undef SIM_INLINE_P +#define SIM_INLINE_P 1 + +#include "sim-inline.h" +#include "sim-main.h" + + +#if C_REVEALS_MODULE_P (SIM_BITS_INLINE) +#include "sim-bits.c" +#endif + + +#if C_REVEALS_MODULE_P (SIM_CORE_INLINE) +#include "sim-core.c" +#endif + + +#if C_REVEALS_MODULE_P (SIM_ENDIAN_INLINE) +#include "sim-endian.c" +#endif + + +#if C_REVEALS_MODULE_P (SIM_EVENTS_INLINE) +#include "sim-events.c" +#endif + + +#if C_REVEALS_MODULE_P (SIM_FPU_INLINE) +#include "sim-fpu.c" +#endif + + +#if C_REVEALS_MODULE_P (SIM_TYPES_INLINE) +#include "sim-types.c" +#endif + + +#if C_REVEALS_MODULE_P (SIM_MAIN_INLINE) +#include "sim-main.c" +#endif + + +#if C_REVEALS_MODULE_P (ENGINE_INLINE) +/* #include "engine.c" - handled by generator */ +#endif + + +#if C_REVEALS_MODULE_P (ICACHE_INLINE) +/* #include "icache.c" - handled by generator */ +#endif + + +#if C_REVEALS_MODULE_P (IDECODE_INLINE) +/* #include "idecode.c" - handled by generator */ +#endif + + +#if C_REVEALS_MODULE_P (SEMANTICS_INLINE) +/* #include "semantics.c" - handled by generator */ +#endif + + +#if C_REVEALS_MODULE_P (SUPPORT_INLINE) +/* #include "support.c" - handled by generator */ +#endif + + +#undef SIM_INLINE_P +#define SIM_INLINE_P 0 + +#endif diff --git a/sim/common/sim-inline.h b/sim/common/sim-inline.h new file mode 100644 index 0000000..300658d --- /dev/null +++ b/sim/common/sim-inline.h @@ -0,0 +1,810 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au> + Copyright (C) 1997, Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef SIM_INLINE_H +#define SIM_INLINE_H + + +/* INLINE CODE SELECTION: + + GCC -O3 attempts to inline any function or procedure in scope. The + options below facilitate finer grained control over what is and + what is not inlined. In particular, it allows the selection of + modules for inlining. Doing this allows the compiler to both + eliminate the overhead of function calls and (as a consequence) + also eliminate further dead code. + + On a CISC (x86) I've found that I can achieve an order of magintude + speed improvement (x3-x5). In the case of RISC (sparc) while the + performance gain isn't as great it is still significant. + + Each module is controled by the macro <module>_INLINE which can + have the values described below + + 0 (ZERO) + + Do not inline any thing for the given module + + The following bit fields values can be combined: + + H_REVEALS_MODULE: + C_REVEALS_MODULE: + + Include the C file for the module into the file being + compiled. The actual inlining is controlled separatly. + + While of no apparent benefit, this makes it possible for the + included module, when compiled, to inline its calls to what + would otherwize be external functions. + + {C_,H_} Determines where the module is inlined. A + H_REVEALS_MODULE will be included everywhere. + + INLINE_GLOBALS: + + Make external functions within the module `inline'. Thus if + the module is included into a file being compiled, calls to + the included modules funtions can be eliminated. INLINE_MODULE + implies REVEAL_MODULE. + + INLINE_LOCALS: + + Make internal (static) functions within the module `inline'. + + + CODING STYLE: + + The inline ability is enabled by specifying every data and function + declaration and definition using one of the following methods: + + + GLOBAL INLINE FUNCTIONS: + + Such functions are small and used heavily. Inlining them + will eliminate an unnecessary function call overhead. + + .h: INLINE_OURPKG (void) ourpkg_func + (int x, + int y); + + .c: INLINE_OURPKG (void) + ourpkg_func (int x, + int y) + { + ... + } + + + GLOBAL INLINE VARIABLES: + + This doesn't make much sense. + + + GLOBAL NON-INLINE (EXTERN) FUNCTIONS AND VARIABLES: + + These include functions with varargs parameters. It can + also include large rarely used functions that contribute + little when inlined. + + .h: extern int ourpkg_print + (char *fmt, ...); + extern int a_global_variable; + + .c: #if EXTERN_OURPKG_P + int + ourpkg_print (char *fmt, + ...) + { + ... + } + #endif + #if EXTERN_OURPKG_P + int a_global_variable = 1; + #endif + + + LOCAL (STATIC) FUNCTIONS: + + These can either be marked inline or just static static vis: + + .h: STATIC_INLINE_OURPKG (int) ourpkg_staticf (void); + .c: STATIC_INLINE_OURPKG (int) + ourpkg_staticf (void) + { + .. + } + + .h: STATIC_OURPKG (int) ourpkg_staticf (void); + .c: STATIC_OURPKG (int) + ourpkg_staticf (void) + { + .. + } + + + All .h files: + + + All modules must wrap their .h code in the following: + + #ifndef OURPKG_H + #define OURPKG_H + ... code proper ... + #endif + + In addition, modules that want to allow global inlining must + include the lines (below) at the end of the .h file. (FIXME: + Shouldn't be needed). + + #if H_REVEALS_MODULE_P (OURPKG_INLINE) + #include "ourpkg.c" + #endif + + + All .c files: + + All modules must wrap their .c code in the following + + #ifndef OURPKG_C + #define OURPKG_C + ... code proper ... + #endif + + + NOW IT WORKS: + + 0: + + Since no inlining is defined. All macro's get standard defaults + (extern, static, ...). + + + + H_REVEALS_MODULE (alt includes our): + + + altprog.c defines ALTPROG_C and then includes sim-inline.h. + + In sim-inline.h the expression `` H_REVEALS_MODULE_P + (OURPROG_INLINE) && ! defined (OURPROG_C) && REVEAL_MODULE_P + (OURPROG_INLINE) '' is TRUE so it defines *_OURPROG as static + and EXTERN_OURPROG_P as FALSE. + + altprog.c includes ourprog.h. + + In ourprog.h the expression ``H_REVEALS_MODULE_P + (OURPROG_INLINE)'' is TRUE so it includes ourprog.c. + + Consequently, all the code in ourprog.c is visible and static in + the file altprog.c + + + + H_REVEALS_MODULE (our includes our): + + + ourprog.c defines OURPROG_C and then includes sim-inline.h. + + In sim-inline.h the term `` ! defined (OURPROG_C) '' is FALSE so + it defines *_OURPROG as non-static and EXTERN_OURPROG_P as TRUE. + + ourprog.c includes ourprog.h. + + In ourprog.h the expression ``H_REVEALS_MODULE_P + (OURPROG_INLINE)'' is true so it includes ourprog.c. + + In ourprog.c (second include) the expression defined (OURPROG_C) + and so the body is not re-included. + + Consequently, ourprog.o will contain a non-static copy of all + the exported symbols. + + + + C_REVEALS_MODULE (alt includes our): + + + altprog.c defines ALTPROG_C and then includes sim-inline.c + + sim-inline.c defines C_INLINE_C and then includes sim-inline.h + + In sim-inline.h the expression `` defined (SIM_INLINE) && ! + defined (OURPROG_C) && REVEAL_MODULE_P (OURPROG_INLINE) '' is + true so it defines *_OURPROG as static and EXTERN_OURPROG_P as + FALSE. + + In sim-inline.c the expression ``C_REVEALS_MODULE_P + (OURPROG_INLINE)'' is true so it includes ourprog.c. + + Consequently, all the code in ourprog.c is visible and static in + the file altprog.c. + + + + C_REVEALS_MODULE (our includes our): + + + ourprog.c defines OURPROG_C and then includes sim-inline.c + + sim-inline.c defines C_INLINE_C and then includes sim-inline.h + + In sim-inline.h the term `` ! defined (OURPROG_C) '' is FALSE + so it defines *_OURPROG as non-static and EXTERN_OURPROG_P as + TRUE. + + Consequently, ourprog.o will contain a non-static copy of all + the exported symbols. + + + + REALITY CHECK: + + This is not for the faint hearted. I've seen GCC get up to 500mb + trying to compile what this can create. */ + +#define H_REVEALS_MODULE 1 +#define C_REVEALS_MODULE 2 +#define INLINE_GLOBALS 4 +#define INLINE_LOCALS 8 + +#define REGPARM_MODULE 32 + +#define ALL_H_INLINE (H_REVEALS_MODULE | INLINE_GLOBALS | INLINE_LOCALS) +#define ALL_C_INLINE (C_REVEALS_MODULE | INLINE_GLOBALS | INLINE_LOCALS) + + +/* Default macro to simplify control several of key the inlines */ + +#ifndef DEFAULT_INLINE +#define DEFAULT_INLINE INLINE_LOCALS +#endif + +#define REVEAL_MODULE_P(X) (X & (H_REVEALS_MODULE | C_REVEALS_MODULE)) +#define H_REVEALS_MODULE_P(X) ((X & H_REVEALS_MODULE)) +#define C_REVEALS_MODULE_P(X) ((X & C_REVEALS_MODULE)) + + +#ifndef HAVE_INLINE +#ifdef __GNUC__ +#define HAVE_INLINE +#endif +#endif + + +/* Your compilers inline prefix */ + +#ifndef INLINE +#if defined (__GNUC__) && defined (__OPTIMIZE__) +#define INLINE __inline__ +#else +#define INLINE /*inline*/ +#endif +#endif + +/* ??? Temporary, pending decision to always use extern inline and do a vast + cleanup of inline support. */ +#ifndef INLINE2 +#if defined (__GNUC__) +#define INLINE2 __inline__ +#else +#define INLINE2 /*inline*/ +#endif +#endif + + +/* Your compiler's static inline prefix */ + +#ifndef STATIC_INLINE +#define STATIC_INLINE static INLINE +#endif + + +/* Your compiler's extern inline prefix */ + +#ifndef EXTERN_INLINE +#define EXTERN_INLINE extern INLINE2 +#endif + + +/* Your compiler's no-return reserved word */ + +#ifndef NORETURN +#define NORETURN +#endif + + + +/* Your compilers's unused reserved word */ + +#if !defined (UNUSED) +#if (!defined (__GNUC__) \ + || (__GNUC__ < 2) \ + || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)) +#define UNUSED +#else +#define UNUSED __attribute__((__unused__)) +#endif +#endif + + + + +/* Your compilers nonstandard function call mechanism prefix */ + +#if !defined REGPARM +#if defined (__GNUC__) && (defined (__i386__) || defined (__i486__) || defined (__i586__) || defined (__i686__)) +#if (WITH_REGPARM && WITH_STDCALL) +#define REGPARM __attribute__((__regparm__(WITH_REGPARM),__stdcall__)) +#else +#if (WITH_REGPARM && !WITH_STDCALL) +#define REGPARM __attribute__((__regparm__(WITH_REGPARM))) +#else +#if (!WITH_REGPARM && WITH_STDCALL) +#define REGPARM __attribute__((__stdcall__)) +#endif +#endif +#endif +#endif +#endif + +#if !defined REGPARM +#define REGPARM +#endif + + + +/* ***** + sim-bits and sim-endian are treated differently from the rest + of the modules below. Their default value is ALL_H_INLINE. + The rest are ALL_C_INLINE. Don't blink, you'll miss it! + ***** + */ + +/* sim-bits */ + +#if !defined (SIM_BITS_INLINE) && (DEFAULT_INLINE) +# define SIM_BITS_INLINE (ALL_H_INLINE) +#endif + +#if (SIM_BITS_INLINE & REGPARM_MODULE) +# define REGPARM_SIM_BITS REGPARM +#else +# define REGPARM_SIM_BITS +#endif + +#if ((H_REVEALS_MODULE_P (SIM_BITS_INLINE) || defined (SIM_INLINE_C)) \ + && !defined (SIM_BITS_C) \ + && (REVEAL_MODULE_P (SIM_BITS_INLINE))) +# if (SIM_BITS_INLINE & INLINE_GLOBALS) +# define INLINE_SIM_BITS(TYPE) static INLINE TYPE UNUSED +# define EXTERN_SIM_BITS_P 0 +# else +# define INLINE_SIM_BITS(TYPE) static TYPE UNUSED REGPARM_SIM_BITS +# define EXTERN_SIM_BITS_P 0 +# endif +#else +# define INLINE_SIM_BITS(TYPE) TYPE REGPARM_SIM_BITS +# define EXTERN_SIM_BITS_P 1 +#endif + +#if (SIM_BITS_INLINE & INLINE_LOCALS) +# define STATIC_INLINE_SIM_BITS(TYPE) static INLINE TYPE +#else +# define STATIC_INLINE_SIM_BITS(TYPE) static TYPE REGPARM_SIM_BITS +#endif + +#define STATIC_SIM_BITS(TYPE) static TYPE + + + +/* sim-core */ + +#if !defined (SIM_CORE_INLINE) && (DEFAULT_INLINE) +# define SIM_CORE_INLINE ALL_C_INLINE +#endif + +#if (SIM_CORE_INLINE & REGPARM_MODULE) +# define REGPARM_SIM_CORE REGPARM +#else +# define REGPARM_SIM_CORE +#endif + +#if ((H_REVEALS_MODULE_P (SIM_CORE_INLINE) || defined (SIM_INLINE_C)) \ + && !defined (SIM_CORE_C) \ + && (REVEAL_MODULE_P (SIM_CORE_INLINE))) +# if (SIM_CORE_INLINE & INLINE_GLOBALS) +# define INLINE_SIM_CORE(TYPE) static INLINE TYPE UNUSED +# define EXTERN_SIM_CORE_P 0 +#else +# define INLINE_SIM_CORE(TYPE) static TYPE UNUSED REGPARM_SIM_CORE +# define EXTERN_SIM_CORE_P 0 +#endif +#else +# define INLINE_SIM_CORE(TYPE) TYPE REGPARM_SIM_CORE +# define EXTERN_SIM_CORE_P 1 +#endif + +#if (SIM_CORE_INLINE & INLINE_LOCALS) +# define STATIC_INLINE_SIM_CORE(TYPE) static INLINE TYPE +#else +# define STATIC_INLINE_SIM_CORE(TYPE) static TYPE REGPARM_SIM_CORE +#endif + +#define STATIC_SIM_CORE(TYPE) static TYPE + + + +/* sim-endian */ + +#if !defined (SIM_ENDIAN_INLINE) && (DEFAULT_INLINE) +# define SIM_ENDIAN_INLINE ALL_H_INLINE +#endif + +#if (SIM_ENDIAN_INLINE & REGPARM_MODULE) +# define REGPARM_SIM_ENDIAN REGPARM +#else +# define REGPARM_SIM_ENDIAN +#endif + +#if ((H_REVEALS_MODULE_P (SIM_ENDIAN_INLINE) || defined (SIM_INLINE_C)) \ + && !defined (SIM_ENDIAN_C) \ + && (REVEAL_MODULE_P (SIM_ENDIAN_INLINE))) +# if (SIM_ENDIAN_INLINE & INLINE_GLOBALS) +# define INLINE_SIM_ENDIAN(TYPE) static INLINE TYPE UNUSED +# define EXTERN_SIM_ENDIAN_P 0 +# else +# define INLINE_SIM_ENDIAN(TYPE) static TYPE UNUSED REGPARM_SIM_ENDIAN +# define EXTERN_SIM_ENDIAN_P 0 +# endif +#else +# define INLINE_SIM_ENDIAN(TYPE) TYPE REGPARM_SIM_ENDIAN +# define EXTERN_SIM_ENDIAN_P 1 +#endif + +#if (SIM_ENDIAN_INLINE & INLINE_LOCALS) +# define STATIC_INLINE_SIM_ENDIAN(TYPE) static INLINE TYPE +#else +# define STATIC_INLINE_SIM_ENDIAN(TYPE) static TYPE REGPARM_SIM_ENDIAN +#endif + +#define STATIC_SIM_ENDIAN(TYPE) static TYPE + + + +/* sim-events */ + +#if !defined (SIM_EVENTS_INLINE) && (DEFAULT_INLINE) +# define SIM_EVENTS_INLINE ALL_C_INLINE +#endif + +#if (SIM_EVENTS_INLINE & REGPARM_MODULE) +# define REGPARM_SIM_EVENTS REGPARM +#else +# define REGPARM_SIM_EVENTS +#endif + +#if ((H_REVEALS_MODULE_P (SIM_EVENTS_INLINE) || defined (SIM_INLINE_C)) \ + && !defined (SIM_EVENTS_C) \ + && (REVEAL_MODULE_P (SIM_EVENTS_INLINE))) +# if (SIM_EVENTS_INLINE & INLINE_GLOBALS) +# define INLINE_SIM_EVENTS(TYPE) static INLINE TYPE UNUSED +# define EXTERN_SIM_EVENTS_P 0 +# else +# define INLINE_SIM_EVENTS(TYPE) static TYPE UNUSED REGPARM_SIM_EVENTS +# define EXTERN_SIM_EVENTS_P 0 +# endif +#else +# define INLINE_SIM_EVENTS(TYPE) TYPE REGPARM_SIM_EVENTS +# define EXTERN_SIM_EVENTS_P 1 +#endif + +#if (SIM_EVENTS_INLINE & INLINE_LOCALS) +# define STATIC_INLINE_SIM_EVENTS(TYPE) static INLINE TYPE +#else +# define STATIC_INLINE_SIM_EVENTS(TYPE) static TYPE REGPARM_SIM_EVENTS +#endif + +#define STATIC_SIM_EVENTS(TYPE) static TYPE + + + +/* sim-fpu */ + +#if !defined (SIM_FPU_INLINE) && (DEFAULT_INLINE) +# define SIM_FPU_INLINE ALL_C_INLINE +#endif + +#if (SIM_FPU_INLINE & REGPARM_MODULE) +# define REGPARM_SIM_FPU REGPARM +#else +# define REGPARM_SIM_FPU +#endif + +#if ((H_REVEALS_MODULE_P (SIM_FPU_INLINE) || defined (SIM_INLINE_C)) \ + && !defined (SIM_FPU_C) \ + && (REVEAL_MODULE_P (SIM_FPU_INLINE))) +# if (SIM_FPU_INLINE & INLINE_GLOBALS) +# define INLINE_SIM_FPU(TYPE) static INLINE TYPE UNUSED +# define EXTERN_SIM_FPU_P 0 +# else +# define INLINE_SIM_FPU(TYPE) static TYPE UNUSED REGPARM_SIM_FPU +# define EXTERN_SIM_FPU_P 0 +# endif +#else +# define INLINE_SIM_FPU(TYPE) TYPE REGPARM_SIM_FPU +# define EXTERN_SIM_FPU_P 1 +#endif + +#if (SIM_FPU_INLINE & INLINE_LOCALS) +# define STATIC_INLINE_SIM_FPU(TYPE) static INLINE TYPE +#else +# define STATIC_INLINE_SIM_FPU(TYPE) static TYPE REGPARM_SIM_FPU +#endif + +#define STATIC_SIM_FPU(TYPE) static TYPE + + + +/* sim-types */ + +#if (SIM_TYPES_INLINE & REGPARM_MODULE) +# define REGPARM_SIM_TYPES REGPARM +#else +# define REGPARM_SIM_TYPES +#endif + +#if ((H_REVEALS_MODULE_P (SIM_TYPES_INLINE) || defined (SIM_INLINE_C)) \ + && !defined (SIM_TYPES_C) \ + && (REVEAL_MODULE_P (SIM_TYPES_INLINE))) +# if (SIM_TYPES_INLINE & INLINE_GLOBALS) +# define INLINE_SIM_TYPES(TYPE) static INLINE TYPE UNUSED +# define EXTERN_SIM_TYPES_P 0 +# else +# define INLINE_SIM_TYPES(TYPE) static TYPE UNUSED REGPARM_SIM_TYPES +# define EXTERN_SIM_TYPES_P 0 +# endif +#else +# define INLINE_SIM_TYPES(TYPE) TYPE REGPARM_SIM_TYPES +# define EXTERN_SIM_TYPES_P 1 +#endif + +#if (SIM_TYPES_INLINE & INLINE_LOCALS) +# define STATIC_INLINE_SIM_TYPES(TYPE) static INLINE TYPE +#else +# define STATIC_INLINE_SIM_TYPES(TYPE) static TYPE REGPARM_SIM_TYPES +#endif + +#define STATIC_SIM_TYPES(TYPE) static TYPE + + + +/* sim_main */ + +#if !defined (SIM_MAIN_INLINE) && (DEFAULT_INLINE) +# define SIM_MAIN_INLINE (ALL_C_INLINE) +#endif + +#if (SIM_MAIN_INLINE & REGPARM_MODULE) +# define REGPARM_SIM_MAIN REGPARM +#else +# define REGPARM_SIM_MAIN +#endif + +#if ((H_REVEALS_MODULE_P (SIM_MAIN_INLINE) || defined (SIM_INLINE_C)) \ + && !defined (SIM_MAIN_C) \ + && (REVEAL_MODULE_P (SIM_MAIN_INLINE))) +# if (SIM_MAIN_INLINE & INLINE_GLOBALS) +# define INLINE_SIM_MAIN(TYPE) static INLINE TYPE UNUSED +# define EXTERN_SIM_MAIN_P 0 +# else +# define INLINE_SIM_MAIN(TYPE) static TYPE UNUSED REGPARM_SIM_MAIN +# define EXTERN_SIM_MAIN_P 0 +# endif +#else +# define INLINE_SIM_MAIN(TYPE) TYPE REGPARM_SIM_MAIN +# define EXTERN_SIM_MAIN_P 1 +#endif + +#if (SIM_MAIN_INLINE & INLINE_LOCALS) +# define STATIC_INLINE_SIM_MAIN(TYPE) static INLINE TYPE +#else +# define STATIC_INLINE_SIM_MAIN(TYPE) static TYPE REGPARM_SIM_MAIN +#endif + +#define STATIC_SIM_MAIN(TYPE) static TYPE + +/* engine */ + +#if (ENGINE_INLINE & REGPARM_MODULE) +# define REGPARM_ENGINE REGPARM +#else +# define REGPARM_ENGINE +#endif + +#if ((H_REVEALS_MODULE_P (ENGINE_INLINE) || defined (SIM_INLINE_C)) \ + && !defined (ENGINE_C) \ + && (REVEAL_MODULE_P (ENGINE_INLINE))) +# if (ENGINE_INLINE & INLINE_GLOBALS) +# define INLINE_ENGINE(TYPE) static INLINE TYPE UNUSED +# define EXTERN_ENGINE_P 0 +# else +# define INLINE_ENGINE(TYPE) static TYPE UNUSED REGPARM_ENGINE +# define EXTERN_ENGINE_P 0 +# endif +#else +# define INLINE_ENGINE(TYPE) TYPE REGPARM_ENGINE +# define EXTERN_ENGINE_P 1 +#endif + +#if (ENGINE_INLINE & INLINE_LOCALS) +# define STATIC_INLINE_ENGINE(TYPE) static INLINE TYPE +#else +# define STATIC_INLINE_ENGINE(TYPE) static TYPE REGPARM_ENGINE +#endif + +#define STATIC_ENGINE(TYPE) static TYPE + + + +/* icache */ + +#if (ICACHE_INLINE & REGPARM_MODULE) +# define REGPARM_ICACHE REGPARM +#else +# define REGPARM_ICACHE +#endif + +#if ((H_REVEALS_MODULE_P (ICACHE_INLINE) || defined (SIM_INLINE_C)) \ + && !defined (ICACHE_C) \ + && (REVEAL_MODULE_P (ICACHE_INLINE))) +# if (ICACHE_INLINE & INLINE_GLOBALS) +# define INLINE_ICACHE(TYPE) static INLINE TYPE UNUSED +# define EXTERN_ICACHE_P 0 +#else +# define INLINE_ICACHE(TYPE) static TYPE UNUSED REGPARM_ICACHE +# define EXTERN_ICACHE_P 0 +#endif +#else +# define INLINE_ICACHE(TYPE) TYPE REGPARM_ICACHE +# define EXTERN_ICACHE_P 1 +#endif + +#if (ICACHE_INLINE & INLINE_LOCALS) +# define STATIC_INLINE_ICACHE(TYPE) static INLINE TYPE +#else +# define STATIC_INLINE_ICACHE(TYPE) static TYPE REGPARM_ICACHE +#endif + +#define STATIC_ICACHE(TYPE) static TYPE + + + +/* idecode */ + +#if (IDECODE_INLINE & REGPARM_MODULE) +# define REGPARM_IDECODE REGPARM +#else +# define REGPARM_IDECODE +#endif + +#if ((H_REVEALS_MODULE_P (IDECODE_INLINE) || defined (SIM_INLINE_C)) \ + && !defined (IDECODE_C) \ + && (REVEAL_MODULE_P (IDECODE_INLINE))) +# if (IDECODE_INLINE & INLINE_GLOBALS) +# define INLINE_IDECODE(TYPE) static INLINE TYPE UNUSED +# define EXTERN_IDECODE_P 0 +#else +# define INLINE_IDECODE(TYPE) static TYPE UNUSED REGPARM_IDECODE +# define EXTERN_IDECODE_P 0 +#endif +#else +# define INLINE_IDECODE(TYPE) TYPE REGPARM_IDECODE +# define EXTERN_IDECODE_P 1 +#endif + +#if (IDECODE_INLINE & INLINE_LOCALS) +# define STATIC_INLINE_IDECODE(TYPE) static INLINE TYPE +#else +# define STATIC_INLINE_IDECODE(TYPE) static TYPE REGPARM_IDECODE +#endif + +#define STATIC_IDECODE(TYPE) static TYPE + + + +/* semantics */ + +#if (SEMANTICS_INLINE & REGPARM_MODULE) +# define REGPARM_SEMANTICS REGPARM +#else +# define REGPARM_SEMANTICS +#endif + +#if ((H_REVEALS_MODULE_P (SEMANTICS_INLINE) || defined (SIM_INLINE_C)) \ + && !defined (SEMANTICS_C) \ + && (REVEAL_MODULE_P (SEMANTICS_INLINE))) +# if (SEMANTICS_INLINE & INLINE_GLOBALS) +# define INLINE_SEMANTICS(TYPE) static INLINE TYPE UNUSED +# define EXTERN_SEMANTICS_P 0 +#else +# define INLINE_SEMANTICS(TYPE) static TYPE UNUSED REGPARM_SEMANTICS +# define EXTERN_SEMANTICS_P 0 +#endif +#else +# define INLINE_SEMANTICS(TYPE) TYPE REGPARM_SEMANTICS +# define EXTERN_SEMANTICS_P 1 +#endif + +#if EXTERN_SEMANTICS_P +# define EXTERN_SEMANTICS(TYPE) TYPE REGPARM_SEMANTICS +#else +# define EXTERN_SEMANTICS(TYPE) static TYPE UNUSED REGPARM_SEMANTICS +#endif + +#if (SEMANTICS_INLINE & INLINE_LOCALS) +# define STATIC_INLINE_SEMANTICS(TYPE) static INLINE TYPE +#else +# define STATIC_INLINE_SEMANTICS(TYPE) static TYPE REGPARM_SEMANTICS +#endif + +#define STATIC_SEMANTICS(TYPE) static TYPE + + + +/* support */ + +#if !defined (SUPPORT_INLINE) && (DEFAULT_INLINE) +# define SUPPORT_INLINE ALL_C_INLINE +#endif + +#if (SUPPORT_INLINE & REGPARM_MODULE) +# define REGPARM_SUPPORT REGPARM +#else +# define REGPARM_SUPPORT +#endif + +#if ((H_REVEALS_MODULE_P (SUPPORT_INLINE) || defined (SIM_INLINE_C)) \ + && !defined (SUPPORT_C) \ + && (REVEAL_MODULE_P (SUPPORT_INLINE))) +# if (SUPPORT_INLINE & INLINE_GLOBALS) +# define INLINE_SUPPORT(TYPE) static INLINE TYPE UNUSED +# define EXTERN_SUPPORT_P 0 +#else +# define INLINE_SUPPORT(TYPE) static TYPE UNUSED REGPARM_SUPPORT +# define EXTERN_SUPPORT_P 0 +#endif +#else +# define INLINE_SUPPORT(TYPE) TYPE REGPARM_SUPPORT +# define EXTERN_SUPPORT_P 1 +#endif + +#if (SUPPORT_INLINE & INLINE_LOCALS) +# define STATIC_INLINE_SUPPORT(TYPE) static INLINE TYPE +#else +# define STATIC_INLINE_SUPPORT(TYPE) static TYPE REGPARM_SUPPORT +#endif + +#define STATIC_SUPPORT(TYPE) static TYPE + + + +#endif diff --git a/sim/common/sim-io.c b/sim/common/sim-io.c new file mode 100644 index 0000000..f3d2f67 --- /dev/null +++ b/sim/common/sim-io.c @@ -0,0 +1,379 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au> + Copyright (C) 1998, Cygnus Solutions. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#include "sim-main.h" +#include "sim-io.h" +#include "targ-vals.h" + +#include <errno.h> +#if HAVE_FCNTL_H +#include <fcntl.h> +#endif + +#if HAVE_UNISTD_H +#include <unistd.h> +#endif + + +/* See the file include/callbacks.h for a description */ + + +int +sim_io_init(SIM_DESC sd) +{ + return STATE_CALLBACK (sd)->init (STATE_CALLBACK (sd)); +} + + +int +sim_io_shutdown(SIM_DESC sd) +{ + return STATE_CALLBACK (sd)->shutdown (STATE_CALLBACK (sd)); +} + + +int +sim_io_unlink(SIM_DESC sd, + const char *f1) +{ + return STATE_CALLBACK (sd)->unlink (STATE_CALLBACK (sd), f1); +} + + +long +sim_io_time(SIM_DESC sd, + long *t) +{ + return STATE_CALLBACK (sd)->time (STATE_CALLBACK (sd), t); +} + + +int +sim_io_system(SIM_DESC sd, const char *s) +{ + return STATE_CALLBACK (sd)->system (STATE_CALLBACK (sd), s); +} + + +int +sim_io_rename(SIM_DESC sd, + const char *f1, + const char *f2) +{ + return STATE_CALLBACK (sd)->rename (STATE_CALLBACK (sd), f1, f2); +} + + +int +sim_io_write_stdout(SIM_DESC sd, + const char *buf, + int len) +{ + switch (CURRENT_STDIO) { + case DO_USE_STDIO: + return STATE_CALLBACK (sd)->write_stdout (STATE_CALLBACK (sd), buf, len); + break; + case DONT_USE_STDIO: + return STATE_CALLBACK (sd)->write (STATE_CALLBACK (sd), 1, buf, len); + break; + default: + sim_io_error (sd, "sim_io_write_stdout: unaccounted switch\n"); + break; + } + return 0; +} + + +void +sim_io_flush_stdout(SIM_DESC sd) +{ + switch (CURRENT_STDIO) { + case DO_USE_STDIO: + STATE_CALLBACK (sd)->flush_stdout (STATE_CALLBACK (sd)); + break; + case DONT_USE_STDIO: + break; + default: + sim_io_error (sd, "sim_io_flush_stdout: unaccounted switch\n"); + break; + } +} + + +int +sim_io_write_stderr(SIM_DESC sd, + const char *buf, + int len) +{ + switch (CURRENT_STDIO) { + case DO_USE_STDIO: + return STATE_CALLBACK (sd)->write_stderr (STATE_CALLBACK (sd), buf, len); + break; + case DONT_USE_STDIO: + return STATE_CALLBACK (sd)->write (STATE_CALLBACK (sd), 2, buf, len); + break; + default: + sim_io_error (sd, "sim_io_write_stderr: unaccounted switch\n"); + break; + } + return 0; +} + + +void +sim_io_flush_stderr(SIM_DESC sd) +{ + switch (CURRENT_STDIO) { + case DO_USE_STDIO: + STATE_CALLBACK (sd)->flush_stderr (STATE_CALLBACK (sd)); + break; + case DONT_USE_STDIO: + break; + default: + sim_io_error (sd, "sim_io_flush_stderr: unaccounted switch\n"); + break; + } +} + + +int +sim_io_write(SIM_DESC sd, + int fd, + const char *buf, + int len) +{ + return STATE_CALLBACK (sd)->write (STATE_CALLBACK (sd), fd, buf, len); +} + + +int +sim_io_read_stdin(SIM_DESC sd, + char *buf, + int len) +{ + switch (CURRENT_STDIO) { + case DO_USE_STDIO: + return STATE_CALLBACK (sd)->read_stdin (STATE_CALLBACK (sd), buf, len); + break; + case DONT_USE_STDIO: + return STATE_CALLBACK (sd)->read (STATE_CALLBACK (sd), 0, buf, len); + break; + default: + sim_io_error (sd, "sim_io_read_stdin: unaccounted switch\n"); + break; + } + return 0; +} + + +int +sim_io_read(SIM_DESC sd, int fd, + char *buf, + int len) +{ + return STATE_CALLBACK (sd)->read (STATE_CALLBACK (sd), fd, buf, len); +} + + +int +sim_io_open(SIM_DESC sd, + const char *name, + int flags) +{ + return STATE_CALLBACK (sd)->open (STATE_CALLBACK (sd), name, flags); +} + + +int +sim_io_lseek(SIM_DESC sd, + int fd, + long off, + int way) +{ + return STATE_CALLBACK (sd)->lseek (STATE_CALLBACK (sd), fd, off, way); +} + + +int +sim_io_isatty(SIM_DESC sd, + int fd) +{ + return STATE_CALLBACK (sd)->isatty (STATE_CALLBACK (sd), fd); +} + + +int +sim_io_get_errno(SIM_DESC sd) +{ + return STATE_CALLBACK (sd)->get_errno (STATE_CALLBACK (sd)); +} + + +int +sim_io_close(SIM_DESC sd, + int fd) +{ + return STATE_CALLBACK (sd)->close (STATE_CALLBACK (sd), fd); +} + + +void +sim_io_printf(SIM_DESC sd, + const char *fmt, + ...) +{ + va_list ap; + va_start(ap, fmt); + STATE_CALLBACK (sd)->vprintf_filtered (STATE_CALLBACK (sd), fmt, ap); + va_end(ap); +} + + +void +sim_io_vprintf(SIM_DESC sd, + const char *fmt, + va_list ap) +{ + STATE_CALLBACK (sd)->vprintf_filtered (STATE_CALLBACK (sd), fmt, ap); +} + + +void +sim_io_eprintf(SIM_DESC sd, + const char *fmt, + ...) +{ + va_list ap; + va_start(ap, fmt); + STATE_CALLBACK (sd)->evprintf_filtered (STATE_CALLBACK (sd), fmt, ap); + va_end(ap); +} + + +void +sim_io_evprintf(SIM_DESC sd, + const char *fmt, + va_list ap) +{ + STATE_CALLBACK (sd)->evprintf_filtered (STATE_CALLBACK (sd), fmt, ap); +} + + +void +sim_io_error(SIM_DESC sd, + const char *fmt, + ...) +{ + if (sd == NULL || STATE_CALLBACK (sd) == NULL) { + va_list ap; + va_start(ap, fmt); + vfprintf (stderr, fmt, ap); + va_end(ap); + fprintf (stderr, "\n"); + abort (); + } + else { + va_list ap; + va_start(ap, fmt); + STATE_CALLBACK (sd)->evprintf_filtered (STATE_CALLBACK (sd), fmt, ap); + va_end(ap); + STATE_CALLBACK (sd)->error (STATE_CALLBACK (sd), ""); + } +} + + +void +sim_io_poll_quit(SIM_DESC sd) +{ + if (STATE_CALLBACK (sd)->poll_quit != NULL) + if (STATE_CALLBACK (sd)->poll_quit (STATE_CALLBACK (sd))) + sim_stop (sd); +} + + +/* Based on gdb-4.17/sim/ppc/main.c:sim_io_read_stdin(). + + FIXME: Should not be calling fcntl() or grubbing around inside of + ->fdmap and ->errno. + + FIXME: Some completly new mechanism for handling the general + problem of asynchronous IO is needed. + + FIXME: This function does not supress the echoing (ECHO) of input. + Consequently polled input is always displayed. + + FIXME: This function does not perform uncooked reads. + Consequently, data will not be read until an EOLN character has + been entered. A cntrl-d may force the early termination of a line */ + + +int +sim_io_poll_read (SIM_DESC sd, + int sim_io_fd, + char *buf, + int sizeof_buf) +{ +#if defined(O_NDELAY) && defined(F_GETFL) && defined(F_SETFL) + int fd = STATE_CALLBACK (sd)->fdmap[sim_io_fd]; + int flags; + int status; + int nr_read; + int result; + STATE_CALLBACK (sd)->last_errno = 0; + /* get the old status */ + flags = fcntl (fd, F_GETFL, 0); + if (flags == -1) + { + perror ("sim_io_poll_read"); + return 0; + } + /* temp, disable blocking IO */ + status = fcntl (fd, F_SETFL, flags | O_NDELAY); + if (status == -1) + { + perror ("sim_io_read_stdin"); + return 0; + } + /* try for input */ + nr_read = read (fd, buf, sizeof_buf); + if (nr_read >= 0) + { + /* printf ("<nr-read=%d>\n", nr_read); */ + result = nr_read; + } + else + { /* nr_read < 0 */ + result = -1; + STATE_CALLBACK (sd)->last_errno = errno; + } + /* return to regular vewing */ + status = fcntl (fd, F_SETFL, flags); + if (status == -1) + { + perror ("sim_io_read_stdin"); + /* return 0; */ + } + return result; +#else + return sim_io_read (sd, sim_io_fd, buf, sizeof_buf); +#endif +} diff --git a/sim/common/sim-io.h b/sim/common/sim-io.h new file mode 100644 index 0000000..995b623 --- /dev/null +++ b/sim/common/sim-io.h @@ -0,0 +1,84 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef SIM_IO_H +#define SIM_IO_H + +/* See the file include/callbacks.h for a description */ + +int sim_io_init (SIM_DESC sd); + +int sim_io_shutdown (SIM_DESC sd); + +int sim_io_unlink (SIM_DESC sd, const char *); + +long sim_io_time (SIM_DESC sd, long *); + +int sim_io_system (SIM_DESC sd, const char *); + +int sim_io_rename (SIM_DESC sd, const char *, const char *); + +int sim_io_write_stdout (SIM_DESC sd, const char *, int); + +void sim_io_flush_stdout (SIM_DESC sd); + +int sim_io_write_stderr (SIM_DESC sd, const char *, int); + +void sim_io_flush_stderr (SIM_DESC sd); + +int sim_io_write (SIM_DESC sd, int, const char *, int); + +int sim_io_read_stdin (SIM_DESC sd, char *, int); + +int sim_io_read (SIM_DESC sd, int, char *, int); + +int sim_io_open (SIM_DESC sd, const char *, int); + +int sim_io_lseek (SIM_DESC sd, int, long, int); + +int sim_io_isatty (SIM_DESC sd, int); + +int sim_io_get_errno (SIM_DESC sd); + +int sim_io_close (SIM_DESC sd, int); + +void sim_io_printf (SIM_DESC sd, + const char *fmt, + ...) __attribute__ ((format (printf, 2, 3))); + +void sim_io_vprintf (SIM_DESC sd, const char *fmt, va_list ap); + +void sim_io_eprintf (SIM_DESC sd, + const char *fmt, + ...) __attribute__ ((format (printf, 2, 3))); + +void sim_io_evprintf (SIM_DESC sd, const char *fmt, va_list ap); + +void sim_io_error (SIM_DESC sd, + const char *fmt, + ...) __attribute__ ((format (printf, 2, 3))); + +void sim_io_poll_quit (SIM_DESC sd); + +/* Returns -1 and sets (host) EAGAIN if not ready. */ +int sim_io_poll_read (SIM_DESC sd, int, char *, int); + +#endif diff --git a/sim/common/sim-load.c b/sim/common/sim-load.c new file mode 100644 index 0000000..22fb33b --- /dev/null +++ b/sim/common/sim-load.c @@ -0,0 +1,239 @@ +/* Utility to load a file into the simulator. + Copyright (C) 1997 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This is a standalone loader, independent of the sim-basic.h machinery, + as it is used by simulators that don't use it [though that doesn't mean + to suggest that they shouldn't :-)]. */ + +#include "config.h" +#include "ansidecl.h" +#include <stdio.h> /* for NULL */ +#ifdef ANSI_PROTOTYPES +#include <stdarg.h> +#else +#include <varargs.h> +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#include <time.h> + +#include "sim-basics.h" +#include "bfd.h" +#include "sim-utils.h" + +#include "callback.h" +#include "remote-sim.h" + +static void eprintf PARAMS ((host_callback *, const char *, ...)); +static void xprintf PARAMS ((host_callback *, const char *, ...)); +static void report_transfer_performance + PARAMS ((host_callback *, unsigned long, time_t, time_t)); +static void xprintf_bfd_vma PARAMS ((host_callback *, bfd_vma)); + +/* Load program PROG into the simulator using the function DO_LOAD. + If PROG_BFD is non-NULL, the file has already been opened. + If VERBOSE_P is non-zero statistics are printed of each loaded section + and the transfer rate (for consistency with gdb). + If LMA_P is non-zero the program sections are loaded at the LMA + rather than the VMA + If this fails an error message is printed and NULL is returned. + If it succeeds the bfd is returned. + NOTE: For historical reasons, older hardware simulators incorrectly + write the program sections at LMA interpreted as a virtual address. + This is still accommodated for backward compatibility reasons. */ + + +bfd * +sim_load_file (sd, myname, callback, prog, prog_bfd, verbose_p, lma_p, do_write) + SIM_DESC sd; + const char *myname; + host_callback *callback; + char *prog; + bfd *prog_bfd; + int verbose_p; + int lma_p; + sim_write_fn do_write; +{ + asection *s; + /* Record separately as we don't want to close PROG_BFD if it was passed. */ + bfd *result_bfd; + time_t start_time = 0; /* Start and end times of download */ + time_t end_time = 0; + unsigned long data_count = 0; /* Number of bytes transferred to memory */ + int found_loadable_section; + + if (prog_bfd != NULL) + result_bfd = prog_bfd; + else + { + result_bfd = bfd_openr (prog, 0); + if (result_bfd == NULL) + { + eprintf (callback, "%s: can't open \"%s\": %s\n", + myname, prog, bfd_errmsg (bfd_get_error ())); + return NULL; + } + } + + if (!bfd_check_format (result_bfd, bfd_object)) + { + eprintf (callback, "%s: \"%s\" is not an object file: %s\n", + myname, prog, bfd_errmsg (bfd_get_error ())); + /* Only close if we opened it. */ + if (prog_bfd == NULL) + bfd_close (result_bfd); + return NULL; + } + + if (verbose_p) + start_time = time (NULL); + + found_loadable_section = 0; + for (s = result_bfd->sections; s; s = s->next) + { + if (s->flags & SEC_LOAD) + { + bfd_size_type size; + + size = bfd_get_section_size_before_reloc (s); + if (size > 0) + { + char *buffer; + bfd_vma lma; + + buffer = malloc (size); + if (buffer == NULL) + { + eprintf (callback, + "%s: insufficient memory to load \"%s\"\n", + myname, prog); + /* Only close if we opened it. */ + if (prog_bfd == NULL) + bfd_close (result_bfd); + return NULL; + } + if (lma_p) + lma = bfd_section_lma (result_bfd, s); + else + lma = bfd_section_vma (result_bfd, s); + if (verbose_p) + { + xprintf (callback, "Loading section %s, size 0x%lx %s ", + bfd_get_section_name (result_bfd, s), + (unsigned long) size, + (lma_p ? "lma" : "vma")); + xprintf_bfd_vma (callback, lma); + xprintf (callback, "\n"); + } + data_count += size; + bfd_get_section_contents (result_bfd, s, buffer, 0, size); + do_write (sd, lma, buffer, size); + found_loadable_section = 1; + free (buffer); + } + } + } + + if (!found_loadable_section) + { + eprintf (callback, + "%s: no loadable sections \"%s\"\n", + myname, prog); + return NULL; + } + + if (verbose_p) + { + end_time = time (NULL); + xprintf (callback, "Start address "); + xprintf_bfd_vma (callback, bfd_get_start_address (result_bfd)); + xprintf (callback, "\n"); + report_transfer_performance (callback, data_count, start_time, end_time); + } + + return result_bfd; +} + +static void +xprintf VPARAMS ((host_callback *callback, const char *fmt, ...)) +{ +#ifndef ANSI_PROTOTYPES + host_callback *callback; + char *fmt; +#endif + va_list ap; + + VA_START (ap, fmt); +#ifndef ANSI_PROTOTYPES + callback = va_arg (ap, host_callback *); + fmt = va_arg (ap, char *); +#endif + + (*callback->vprintf_filtered) (callback, fmt, ap); + + va_end (ap); +} + +static void +eprintf VPARAMS ((host_callback *callback, const char *fmt, ...)) +{ +#ifndef ANSI_PROTOTYPES + host_callback *callback; + char *fmt; +#endif + va_list ap; + + VA_START (ap, fmt); +#ifndef ANSI_PROTOTYPES + callback = va_arg (ap, host_callback *); + fmt = va_arg (ap, char *); +#endif + + (*callback->evprintf_filtered) (callback, fmt, ap); + + va_end (ap); +} + +/* Report how fast the transfer went. */ + +static void +report_transfer_performance (callback, data_count, start_time, end_time) + host_callback *callback; + unsigned long data_count; + time_t start_time, end_time; +{ + xprintf (callback, "Transfer rate: "); + if (end_time != start_time) + xprintf (callback, "%ld bits/sec", + (data_count * 8) / (end_time - start_time)); + else + xprintf (callback, "%ld bits in <1 sec", (data_count * 8)); + xprintf (callback, ".\n"); +} + +/* Print a bfd_vma. + This is intended to handle the vagaries of 32 vs 64 bits, etc. */ + +static void +xprintf_bfd_vma (callback, vma) + host_callback *callback; + bfd_vma vma; +{ + /* FIXME: for now */ + xprintf (callback, "0x%lx", (unsigned long) vma); +} diff --git a/sim/common/sim-memopt.c b/sim/common/sim-memopt.c new file mode 100644 index 0000000..be52a66 --- /dev/null +++ b/sim/common/sim-memopt.c @@ -0,0 +1,471 @@ +/* Simulator memory option handling. + Copyright (C) 1996-1999 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "sim-main.h" +#include "sim-assert.h" +#include "sim-options.h" + +#ifdef HAVE_STRING_H +#include <string.h> +#else +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif + +/* Memory fill byte */ +static unsigned8 fill_byte_value; +static int fill_byte_flag = 0; + +/* Memory command line options. */ + +enum { + OPTION_MEMORY_DELETE = OPTION_START, + OPTION_MEMORY_REGION, + OPTION_MEMORY_SIZE, + OPTION_MEMORY_INFO, + OPTION_MEMORY_ALIAS, + OPTION_MEMORY_CLEAR, + OPTION_MEMORY_FILL +}; + +static DECLARE_OPTION_HANDLER (memory_option_handler); + +static const OPTION memory_options[] = +{ + { {"memory-delete", required_argument, NULL, OPTION_MEMORY_DELETE }, + '\0', "ADDRESS|all", "Delete memory at ADDRESS (all addresses)", + memory_option_handler }, + { {"delete-memory", required_argument, NULL, OPTION_MEMORY_DELETE }, + '\0', "ADDRESS", NULL, + memory_option_handler }, + + { {"memory-region", required_argument, NULL, OPTION_MEMORY_REGION }, + '\0', "ADDRESS,SIZE[,MODULO]", "Add a memory region", + memory_option_handler }, + + { {"memory-alias", required_argument, NULL, OPTION_MEMORY_ALIAS }, + '\0', "ADDRESS,SIZE{,ADDRESS}", "Add memory shadow", + memory_option_handler }, + + { {"memory-size", required_argument, NULL, OPTION_MEMORY_SIZE }, + '\0', "SIZE", "Add memory at address zero", + memory_option_handler }, + + { {"memory-fill", required_argument, NULL, OPTION_MEMORY_FILL }, + '\0', "VALUE", "Fill subsequently added memory regions", + memory_option_handler }, + + { {"memory-clear", no_argument, NULL, OPTION_MEMORY_CLEAR }, + '\0', NULL, "Clear subsequently added memory regions", + memory_option_handler }, + + { {"memory-info", no_argument, NULL, OPTION_MEMORY_INFO }, + '\0', NULL, "List configurable memory regions", + memory_option_handler }, + { {"info-memory", no_argument, NULL, OPTION_MEMORY_INFO }, + '\0', NULL, NULL, + memory_option_handler }, + + { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL } +}; + + +static sim_memopt * +do_memopt_add (SIM_DESC sd, + int level, + int space, + address_word addr, + address_word nr_bytes, + unsigned modulo, + sim_memopt **entry, + void *buffer) +{ + void *fill_buffer; + unsigned fill_length; + void *free_buffer; + + if (buffer != NULL) + { + /* Buffer already given. sim_memory_uninstall will free it. */ + sim_core_attach (sd, NULL, + level, access_read_write_exec, space, + addr, nr_bytes, modulo, NULL, buffer); + + free_buffer = buffer; + fill_buffer = buffer; + fill_length = (modulo == 0) ? nr_bytes : modulo; + } + else + { + /* Allocate new well-aligned buffer, just as sim_core_attach(). */ + void *aligned_buffer; + int padding = (addr % sizeof (unsigned64)); + unsigned long bytes = (modulo == 0 ? nr_bytes : modulo) + padding; + + /* If filling with non-zero value, do not use clearing allocator. */ + + if (fill_byte_flag && fill_byte_value != 0) + free_buffer = xmalloc (bytes); /* don't clear */ + else + free_buffer = zalloc (bytes); /* clear */ + + aligned_buffer = (char*) free_buffer + padding; + + sim_core_attach (sd, NULL, + level, access_read_write_exec, space, + addr, nr_bytes, modulo, NULL, aligned_buffer); + + fill_buffer = aligned_buffer; + fill_length = (modulo == 0) ? nr_bytes : modulo; + + /* If we just used a clearing allocator, and are about to fill with + zero, truncate the redundant fill operation. */ + + if (fill_byte_flag && fill_byte_value == 0) + fill_length = 1; /* avoid boundary length=0 case */ + } + + if (fill_byte_flag) + { + ASSERT (fill_buffer != 0); + memset ((char*) fill_buffer, fill_byte_value, fill_length); + } + + while ((*entry) != NULL) + entry = &(*entry)->next; + (*entry) = ZALLOC (sim_memopt); + (*entry)->level = level; + (*entry)->space = space; + (*entry)->addr = addr; + (*entry)->nr_bytes = nr_bytes; + (*entry)->modulo = modulo; + (*entry)->buffer = free_buffer; + + return (*entry); +} + +static SIM_RC +do_memopt_delete (SIM_DESC sd, + int level, + int space, + address_word addr) +{ + sim_memopt **entry = &STATE_MEMOPT (sd); + sim_memopt *alias; + while ((*entry) != NULL + && ((*entry)->level != level + || (*entry)->space != space + || (*entry)->addr != addr)) + entry = &(*entry)->next; + if ((*entry) == NULL) + { + sim_io_eprintf (sd, "Memory at 0x%lx not found, not deleted\n", + (long) addr); + return SIM_RC_FAIL; + } + /* delete any buffer */ + if ((*entry)->buffer != NULL) + zfree ((*entry)->buffer); + /* delete it and its aliases */ + alias = *entry; + *entry = (*entry)->next; + while (alias != NULL) + { + sim_memopt *dead = alias; + alias = alias->alias; + sim_core_detach (sd, NULL, dead->level, dead->space, dead->addr); + zfree (dead); + } + return SIM_RC_OK; +} + + +static char * +parse_size (char *chp, + address_word *nr_bytes, + unsigned *modulo) +{ + /* <nr_bytes> [ "%" <modulo> ] */ + *nr_bytes = strtoul (chp, &chp, 0); + if (*chp == '%') + { + *modulo = strtoul (chp + 1, &chp, 0); + } + return chp; +} + +static char * +parse_ulong_value (char *chp, + unsigned long *value) +{ + *value = strtoul (chp, &chp, 0); + return chp; +} + +static char * +parse_addr (char *chp, + int *level, + int *space, + address_word *addr) +{ + /* [ <space> ": " ] <addr> [ "@" <level> ] */ + *addr = (unsigned long) strtoul (chp, &chp, 0); + if (*chp == ':') + { + *space = *addr; + *addr = (unsigned long) strtoul (chp + 1, &chp, 0); + } + if (*chp == '@') + { + *level = strtoul (chp + 1, &chp, 0); + } + return chp; +} + + +static SIM_RC +memory_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt, + char *arg, int is_command) +{ + switch (opt) + { + + case OPTION_MEMORY_DELETE: + if (strcasecmp (arg, "all") == 0) + { + while (STATE_MEMOPT (sd) != NULL) + do_memopt_delete (sd, + STATE_MEMOPT (sd)->level, + STATE_MEMOPT (sd)->space, + STATE_MEMOPT (sd)->addr); + return SIM_RC_OK; + } + else + { + int level = 0; + int space = 0; + address_word addr = 0; + parse_addr (arg, &level, &space, &addr); + return do_memopt_delete (sd, level, space, addr); + } + + case OPTION_MEMORY_REGION: + { + char *chp = arg; + int level = 0; + int space = 0; + address_word addr = 0; + address_word nr_bytes = 0; + unsigned modulo = 0; + /* parse the arguments */ + chp = parse_addr (chp, &level, &space, &addr); + if (*chp != ',') + { + sim_io_eprintf (sd, "Missing size for memory-region\n"); + return SIM_RC_FAIL; + } + chp = parse_size (chp + 1, &nr_bytes, &modulo); + /* old style */ + if (*chp == ',') + modulo = strtoul (chp + 1, &chp, 0); + /* try to attach/insert it */ + do_memopt_add (sd, level, space, addr, nr_bytes, modulo, + &STATE_MEMOPT (sd), NULL); + return SIM_RC_OK; + } + + case OPTION_MEMORY_ALIAS: + { + char *chp = arg; + int level = 0; + int space = 0; + address_word addr = 0; + address_word nr_bytes = 0; + unsigned modulo = 0; + sim_memopt *entry; + /* parse the arguments */ + chp = parse_addr (chp, &level, &space, &addr); + if (*chp != ',') + { + sim_io_eprintf (sd, "Missing size for memory-region\n"); + return SIM_RC_FAIL; + } + chp = parse_size (chp + 1, &nr_bytes, &modulo); + /* try to attach/insert the main record */ + entry = do_memopt_add (sd, level, space, addr, nr_bytes, modulo, + &STATE_MEMOPT (sd), + NULL); + /* now attach all the aliases */ + while (*chp == ',') + { + int a_level = level; + int a_space = space; + address_word a_addr = addr; + chp = parse_addr (chp + 1, &a_level, &a_space, &a_addr); + do_memopt_add (sd, a_level, a_space, a_addr, nr_bytes, modulo, + &entry->alias, entry->buffer); + } + return SIM_RC_OK; + } + + case OPTION_MEMORY_SIZE: + { + int level = 0; + int space = 0; + address_word addr = 0; + address_word nr_bytes = 0; + unsigned modulo = 0; + /* parse the arguments */ + parse_size (arg, &nr_bytes, &modulo); + /* try to attach/insert it */ + do_memopt_add (sd, level, space, addr, nr_bytes, modulo, + &STATE_MEMOPT (sd), NULL); + return SIM_RC_OK; + } + + case OPTION_MEMORY_CLEAR: + { + fill_byte_value = (unsigned8) 0; + fill_byte_flag = 1; + return SIM_RC_OK; + break; + } + + case OPTION_MEMORY_FILL: + { + unsigned long fill_value; + parse_ulong_value (arg, &fill_value); + if (fill_value > 255) + { + sim_io_eprintf (sd, "Missing fill value between 0 and 255\n"); + return SIM_RC_FAIL; + } + fill_byte_value = (unsigned8) fill_value; + fill_byte_flag = 1; + return SIM_RC_OK; + break; + } + + case OPTION_MEMORY_INFO: + { + sim_memopt *entry; + sim_io_printf (sd, "Memory maps:\n"); + for (entry = STATE_MEMOPT (sd); entry != NULL; entry = entry->next) + { + sim_memopt *alias; + sim_io_printf (sd, " memory"); + if (entry->alias == NULL) + sim_io_printf (sd, " region "); + else + sim_io_printf (sd, " alias "); + if (entry->space != 0) + sim_io_printf (sd, "0x%lx:", (long) entry->space); + sim_io_printf (sd, "0x%08lx", (long) entry->addr); + if (entry->level != 0) + sim_io_printf (sd, "@0x%lx", (long) entry->level); + sim_io_printf (sd, ",0x%lx", + (long) entry->nr_bytes); + if (entry->modulo != 0) + sim_io_printf (sd, "%%0x%lx", (long) entry->modulo); + for (alias = entry->alias; + alias != NULL; + alias = alias->next) + { + if (alias->space != 0) + sim_io_printf (sd, "0x%lx:", (long) alias->space); + sim_io_printf (sd, ",0x%08lx", (long) alias->addr); + if (alias->level != 0) + sim_io_printf (sd, "@0x%lx", (long) alias->level); + } + sim_io_printf (sd, "\n"); + } + return SIM_RC_OK; + break; + } + + default: + sim_io_eprintf (sd, "Unknown memory option %d\n", opt); + return SIM_RC_FAIL; + + } + + return SIM_RC_FAIL; +} + + +/* "memory" module install handler. + + This is called via sim_module_install to install the "memory" subsystem + into the simulator. */ + +static MODULE_INIT_FN sim_memory_init; +static MODULE_UNINSTALL_FN sim_memory_uninstall; + +SIM_RC +sim_memopt_install (SIM_DESC sd) +{ + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + sim_add_option_table (sd, NULL, memory_options); + sim_module_add_uninstall_fn (sd, sim_memory_uninstall); + sim_module_add_init_fn (sd, sim_memory_init); + return SIM_RC_OK; +} + + +/* Uninstall the "memory" subsystem from the simulator. */ + +static void +sim_memory_uninstall (SIM_DESC sd) +{ + sim_memopt **entry = &STATE_MEMOPT (sd); + sim_memopt *alias; + + while ((*entry) != NULL) + { + /* delete any buffer */ + if ((*entry)->buffer != NULL) + zfree ((*entry)->buffer); + + /* delete it and its aliases */ + alias = *entry; + while (alias != NULL) + { + sim_memopt *dead = alias; + alias = alias->alias; + sim_core_detach (sd, NULL, dead->level, dead->space, dead->addr); + zfree (dead); + } + + /* next victim */ + *entry = (*entry)->next; + } +} + + +static SIM_RC +sim_memory_init (SIM_DESC sd) +{ + /* FIXME: anything needed? */ + return SIM_RC_OK; +} diff --git a/sim/common/sim-memopt.h b/sim/common/sim-memopt.h new file mode 100644 index 0000000..287c576 --- /dev/null +++ b/sim/common/sim-memopt.h @@ -0,0 +1,46 @@ +/* Header file for simulator memory argument handling. + Copyright (C) 1997 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef SIM_MEMOPT_H +#define SIM_MEMOPT_H + +/* Provides a command line interface for manipulating the memory core */ + +typedef struct _sim_memopt sim_memopt; +struct _sim_memopt { + int level; + int space; + unsigned_word addr; + unsigned_word nr_bytes; + unsigned modulo; + void *buffer; + sim_memopt *alias; /* linked list */ + sim_memopt *next; +}; + + +/* Install the "memopt" module. */ + +SIM_RC sim_memopt_install (SIM_DESC sd); + + +/* Was there a memory command? */ + +#endif diff --git a/sim/common/sim-model.c b/sim/common/sim-model.c new file mode 100644 index 0000000..a126fb1 --- /dev/null +++ b/sim/common/sim-model.c @@ -0,0 +1,208 @@ +/* Model support. + Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "sim-main.h" +#include "libiberty.h" +#include "sim-options.h" +#include "sim-io.h" +#include "sim-assert.h" +#include "bfd.h" + +static void model_set (sim_cpu *, const MODEL *); + +static DECLARE_OPTION_HANDLER (model_option_handler); + +static MODULE_INIT_FN sim_model_init; + +#define OPTION_MODEL (OPTION_START + 0) + +static const OPTION model_options[] = { + { {"model", required_argument, NULL, OPTION_MODEL}, + '\0', "MODEL", "Specify model to simulate", + model_option_handler }, + { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL } +}; + +static SIM_RC +model_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt, + char *arg, int is_command) +{ + switch (opt) + { + case OPTION_MODEL : + { + const MODEL *model = sim_model_lookup (arg); + if (! model) + { + sim_io_eprintf (sd, "unknown model `%s'", arg); + return SIM_RC_FAIL; + } + sim_model_set (sd, cpu, model); + break; + } + } + + return SIM_RC_OK; +} + +SIM_RC +sim_model_install (SIM_DESC sd) +{ + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + + sim_add_option_table (sd, NULL, model_options); + sim_module_add_init_fn (sd, sim_model_init); + + return SIM_RC_OK; +} + +/* Subroutine of sim_model_set to set the model for one cpu. */ + +static void +model_set (sim_cpu *cpu, const MODEL *model) +{ + CPU_MACH (cpu) = MODEL_MACH (model); + CPU_MODEL (cpu) = model; + (* MACH_INIT_CPU (MODEL_MACH (model))) (cpu); + (* MODEL_INIT (model)) (cpu); +} + +/* Set the current model of CPU to MODEL. + If CPU is NULL, all cpus are set to MODEL. */ + +void +sim_model_set (SIM_DESC sd, sim_cpu *cpu, const MODEL *model) +{ + if (! cpu) + { + int c; + + for (c = 0; c < MAX_NR_PROCESSORS; ++c) + if (STATE_CPU (sd, c)) + model_set (STATE_CPU (sd, c), model); + } + else + { + model_set (cpu, model); + } +} + +/* Look up model named NAME. + Result is pointer to MODEL entry or NULL if not found. */ + +const MODEL * +sim_model_lookup (const char *name) +{ + const MACH **machp; + const MODEL *model; + + for (machp = & sim_machs[0]; *machp != NULL; ++machp) + { + for (model = MACH_MODELS (*machp); MODEL_NAME (model) != NULL; ++model) + { + if (strcmp (MODEL_NAME (model), name) == 0) + return model; + } + } + return NULL; +} + +/* Look up machine named NAME. + Result is pointer to MACH entry or NULL if not found. */ + +const MACH * +sim_mach_lookup (const char *name) +{ + const MACH **machp; + + for (machp = & sim_machs[0]; *machp != NULL; ++machp) + { + if (strcmp (MACH_NAME (*machp), name) == 0) + return *machp; + } + return NULL; +} + +/* Look up a machine via its bfd name. + Result is pointer to MACH entry or NULL if not found. */ + +const MACH * +sim_mach_lookup_bfd_name (const char *name) +{ + const MACH **machp; + + for (machp = & sim_machs[0]; *machp != NULL; ++machp) + { + if (strcmp (MACH_BFD_NAME (*machp), name) == 0) + return *machp; + } + return NULL; +} + +/* Initialize model support. */ + +static SIM_RC +sim_model_init (SIM_DESC sd) +{ + SIM_CPU *cpu; + + /* If both cpu model and state architecture are set, ensure they're + compatible. If only one is set, set the other. If neither are set, + use the default model. STATE_ARCHITECTURE is the bfd_arch_info data + for the selected "mach" (bfd terminology). */ + + /* Only check cpu 0. STATE_ARCHITECTURE is for that one only. */ + /* ??? At present this only supports homogeneous multiprocessors. */ + cpu = STATE_CPU (sd, 0); + + if (! STATE_ARCHITECTURE (sd) + && ! CPU_MACH (cpu)) + { + /* Set the default model. */ + const MODEL *model = sim_model_lookup (WITH_DEFAULT_MODEL); + sim_model_set (sd, NULL, model); + } + + if (STATE_ARCHITECTURE (sd) + && CPU_MACH (cpu)) + { + if (strcmp (STATE_ARCHITECTURE (sd)->printable_name, + MACH_BFD_NAME (CPU_MACH (cpu))) != 0) + { + sim_io_eprintf (sd, "invalid model `%s' for `%s'\n", + MODEL_NAME (CPU_MODEL (cpu)), + STATE_ARCHITECTURE (sd)->printable_name); + return SIM_RC_FAIL; + } + } + else if (STATE_ARCHITECTURE (sd)) + { + /* Use the default model for the selected machine. + The default model is the first one in the list. */ + const MACH *mach = sim_mach_lookup_bfd_name (STATE_ARCHITECTURE (sd)->printable_name); + sim_model_set (sd, NULL, MACH_MODELS (mach)); + } + else + { + STATE_ARCHITECTURE (sd) = bfd_scan_arch (MACH_BFD_NAME (CPU_MACH (cpu))); + } + + return SIM_RC_OK; +} diff --git a/sim/common/sim-model.h b/sim/common/sim-model.h new file mode 100644 index 0000000..6f7769a --- /dev/null +++ b/sim/common/sim-model.h @@ -0,0 +1,138 @@ +/* Architecture, machine, and model support. + Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Nomenclature: + architecture = one of sparc, mips, sh, etc. + in the sparc architecture, mach = one of v6, v7, v8, sparclite, etc. + in the v8 mach, model = one of supersparc, etc. +*/ + +/* This file is intended to be included by sim-basics.h. */ + +#ifndef SIM_MODEL_H +#define SIM_MODEL_H + +/* Function unit and instruction timing support. + ??? This is obviously insufficiently general. + It's useful but it needs elaborating upon. */ + +typedef struct { + unsigned char name; /* actually a UNIT_TYPE enum */ + unsigned char issue; + unsigned char done; +} UNIT; + +#ifndef MAX_UNITS +#define MAX_UNITS 1 +#endif + +typedef int (MODEL_FN) (sim_cpu *, void *); + +typedef struct { + /* This is an integer that identifies this insn. + How this works is up to the target. */ + int num; + + /* Function to handle insn-specific profiling. */ + MODEL_FN *model_fn; + + /* Array of function units used by this insn. */ + UNIT units[MAX_UNITS]; +} INSN_TIMING; + +/* Struct to describe various implementation properties of a cpu. + When multiple cpu variants are supported, the sizes of some structs + can vary. */ + +typedef struct { + /* The size of the SIM_CPU struct. */ + int sim_cpu_size; +#define IMP_PROPS_SIM_CPU_SIZE(cpu_props) ((cpu_props)->sim_cpu_size) + /* An SCACHE element can vary in size, depending on the selected cpu. + This is zero if the SCACHE isn't in use for this variant. */ + int scache_elm_size; +#define IMP_PROPS_SCACHE_ELM_SIZE(cpu_props) ((cpu_props)->scache_elm_size) +} MACH_IMP_PROPERTIES; + +/* A machine variant. */ + +typedef struct { + const char *name; +#define MACH_NAME(m) ((m)->name) + /* This is the argument to bfd_scan_arch. */ + const char *bfd_name; +#define MACH_BFD_NAME(m) ((m)->bfd_name) + int word_bitsize; +#define MACH_WORD_BITSIZE(m) ((m)->word_bitsize) + int addr_bitsize; +#define MACH_ADDR_BITSIZE(m) ((m)->addr_bitsize) + + /* Pointer to null-entry terminated table of models of this mach. + The default is the first one. */ + const struct model *models; +#define MACH_MODELS(m) ((m)->models) + + /* Pointer to the implementation properties of this mach. */ + const MACH_IMP_PROPERTIES *imp_props; +#define MACH_IMP_PROPS(m) ((m)->imp_props) + + /* Called by sim_model_set when the model of a cpu is set. */ + void (* init_cpu) (sim_cpu *); +#define MACH_INIT_CPU(m) ((m)->init_cpu) + + /* Initialize the simulator engine for this cpu. + Used by cgen simulators to initialize the insn descriptor table. */ + void (* prepare_run) (sim_cpu *); +#define MACH_PREPARE_RUN(m) ((m)->prepare_run) +} MACH; + +/* A model (implementation) of a machine. */ + +typedef struct model { + const char *name; +#define MODEL_NAME(m) ((m)->name) + const MACH *mach; +#define MODEL_MACH(m) ((m)->mach) + /* An enum that distinguished the model. */ + int num; +#define MODEL_NUM(m) ((m)->num) + /* Pointer to timing table for this model. */ + const INSN_TIMING *timing; +#define MODEL_TIMING(m) ((m)->timing) + void (* init) (sim_cpu *); +#define MODEL_INIT(m) ((m)->init) +} MODEL; + +/* Tables of supported machines. */ +/* ??? In a simulator of multiple architectures, will need multiple copies of + this. Have an `archs' array that contains a pointer to the machs array + for each (which in turn has a pointer to the models array for each). */ +extern const MACH *sim_machs[]; + +/* Model module handlers. */ +extern MODULE_INSTALL_FN sim_model_install; + +/* Support routines. */ +extern void sim_model_set (SIM_DESC sd_, sim_cpu *cpu_, const MODEL *model_); +extern const MODEL * sim_model_lookup (const char *name_); +extern const MACH * sim_mach_lookup (const char *name_); +extern const MACH * sim_mach_lookup_bfd_name (const char *bfd_name_); + +#endif /* SIM_MODEL_H */ diff --git a/sim/common/sim-module.c b/sim/common/sim-module.c new file mode 100644 index 0000000..35eb32a --- /dev/null +++ b/sim/common/sim-module.c @@ -0,0 +1,399 @@ +/* Module support. + Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "sim-main.h" +#include "sim-io.h" +#include "sim-options.h" +#include "sim-assert.h" + +#if WITH_HW +#include "sim-hw.h" +#endif + +#include "libiberty.h" + +/* List of all modules. */ +static MODULE_INSTALL_FN * const modules[] = { + standard_install, + sim_events_install, +#ifdef SIM_HAVE_MODEL + sim_model_install, +#endif +#if WITH_ENGINE + sim_engine_install, +#endif +#if WITH_TRACE + trace_install, +#endif +#if WITH_PROFILE + profile_install, +#endif + sim_core_install, +#ifndef SIM_HAVE_FLATMEM + /* FIXME: should handle flatmem as well FLATMEM */ + sim_memopt_install, +#endif +#if WITH_WATCHPOINTS + sim_watchpoint_install, +#endif +#if WITH_SCACHE + scache_install, +#endif +#ifdef SIM_HAVE_BREAKPOINTS + sim_break_install, +#endif +#if WITH_HW + sim_hw_install, +#endif + /* Configured in [simulator specific] additional modules. */ +#ifdef MODULE_LIST + MODULE_LIST +#endif + 0 +}; + +/* Functions called from sim_open. */ + +/* Initialize common parts before argument processing. */ + +SIM_RC +sim_pre_argv_init (SIM_DESC sd, const char *myname) +{ + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + SIM_ASSERT (STATE_MODULES (sd) == NULL); + + STATE_MY_NAME (sd) = myname + strlen (myname); + while (STATE_MY_NAME (sd) > myname && STATE_MY_NAME (sd)[-1] != '/') + --STATE_MY_NAME (sd); + + /* Set the cpu names to default values. */ + { + int i; + for (i = 0; i < MAX_NR_PROCESSORS; ++i) + { + char *name; + asprintf (&name, "cpu%d", i); + CPU_NAME (STATE_CPU (sd, i)) = name; + } + } + + sim_config_default (sd); + + /* Install all configured in modules. */ + if (sim_module_install (sd) != SIM_RC_OK) + return SIM_RC_FAIL; + + return SIM_RC_OK; +} + +/* Initialize common parts after argument processing. */ + +SIM_RC +sim_post_argv_init (SIM_DESC sd) +{ + int i; + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + SIM_ASSERT (STATE_MODULES (sd) != NULL); + + /* Set the cpu->state backlinks for each cpu. */ + for (i = 0; i < MAX_NR_PROCESSORS; ++i) + { + CPU_STATE (STATE_CPU (sd, i)) = sd; + CPU_INDEX (STATE_CPU (sd, i)) = i; + } + + if (sim_module_init (sd) != SIM_RC_OK) + return SIM_RC_FAIL; + + return SIM_RC_OK; +} + +/* Install all modules. + If this fails, no modules are left installed. */ + +SIM_RC +sim_module_install (SIM_DESC sd) +{ + MODULE_INSTALL_FN * const *modp; + + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + SIM_ASSERT (STATE_MODULES (sd) == NULL); + + STATE_MODULES (sd) = ZALLOC (struct module_list); + for (modp = modules; *modp != NULL; ++modp) + { + if ((*modp) (sd) != SIM_RC_OK) + { + sim_module_uninstall (sd); + SIM_ASSERT (STATE_MODULES (sd) == NULL); + return SIM_RC_FAIL; + } + } + return SIM_RC_OK; +} + +/* Called after all modules have been installed and after argv + has been processed. */ + +SIM_RC +sim_module_init (SIM_DESC sd) +{ + struct module_list *modules = STATE_MODULES (sd); + MODULE_INIT_LIST *modp; + + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + SIM_ASSERT (STATE_MODULES (sd) != NULL); + + for (modp = modules->init_list; modp != NULL; modp = modp->next) + { + if ((*modp->fn) (sd) != SIM_RC_OK) + return SIM_RC_FAIL; + } + return SIM_RC_OK; +} + +/* Called when ever the simulator is resumed */ + +SIM_RC +sim_module_resume (SIM_DESC sd) +{ + struct module_list *modules = STATE_MODULES (sd); + MODULE_RESUME_LIST *modp; + + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + SIM_ASSERT (STATE_MODULES (sd) != NULL); + + for (modp = modules->resume_list; modp != NULL; modp = modp->next) + { + if ((*modp->fn) (sd) != SIM_RC_OK) + return SIM_RC_FAIL; + } + return SIM_RC_OK; +} + +/* Called when ever the simulator is suspended */ + +SIM_RC +sim_module_suspend (SIM_DESC sd) +{ + struct module_list *modules = STATE_MODULES (sd); + MODULE_SUSPEND_LIST *modp; + + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + SIM_ASSERT (STATE_MODULES (sd) != NULL); + + for (modp = modules->suspend_list; modp != NULL; modp = modp->next) + { + if ((*modp->fn) (sd) != SIM_RC_OK) + return SIM_RC_FAIL; + } + return SIM_RC_OK; +} + +/* Uninstall installed modules, called by sim_close. */ + +void +sim_module_uninstall (SIM_DESC sd) +{ + struct module_list *modules = STATE_MODULES (sd); + MODULE_UNINSTALL_LIST *modp; + + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + SIM_ASSERT (STATE_MODULES (sd) != NULL); + + /* Uninstall the modules. */ + for (modp = modules->uninstall_list; modp != NULL; modp = modp->next) + (*modp->fn) (sd); + + /* clean-up init list */ + { + MODULE_INIT_LIST *n, *d; + for (d = modules->init_list; d != NULL; d = n) + { + n = d->next; + zfree (d); + } + } + + /* clean-up resume list */ + { + MODULE_RESUME_LIST *n, *d; + for (d = modules->resume_list; d != NULL; d = n) + { + n = d->next; + zfree (d); + } + } + + /* clean-up suspend list */ + { + MODULE_SUSPEND_LIST *n, *d; + for (d = modules->suspend_list; d != NULL; d = n) + { + n = d->next; + zfree (d); + } + } + + /* clean-up uninstall list */ + { + MODULE_UNINSTALL_LIST *n, *d; + for (d = modules->uninstall_list; d != NULL; d = n) + { + n = d->next; + zfree (d); + } + } + + /* clean-up info list */ + { + MODULE_INFO_LIST *n, *d; + for (d = modules->info_list; d != NULL; d = n) + { + n = d->next; + zfree (d); + } + } + + zfree (modules); + STATE_MODULES (sd) = NULL; +} + +/* Called when ever simulator info is needed */ + +void +sim_module_info (SIM_DESC sd, int verbose) +{ + struct module_list *modules = STATE_MODULES (sd); + MODULE_INFO_LIST *modp; + + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + SIM_ASSERT (STATE_MODULES (sd) != NULL); + + for (modp = modules->info_list; modp != NULL; modp = modp->next) + { + (*modp->fn) (sd, verbose); + } +} + +/* Add FN to the init handler list. + init in the same order as the install. */ + +void +sim_module_add_init_fn (SIM_DESC sd, MODULE_INIT_FN fn) +{ + struct module_list *modules = STATE_MODULES (sd); + MODULE_INIT_LIST *l = ZALLOC (MODULE_INIT_LIST); + MODULE_INIT_LIST **last; + + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + SIM_ASSERT (STATE_MODULES (sd) != NULL); + + last = &modules->init_list; + while (*last != NULL) + last = &((*last)->next); + + l->fn = fn; + l->next = NULL; + *last = l; +} + +/* Add FN to the resume handler list. + resume in the same order as the install. */ + +void +sim_module_add_resume_fn (SIM_DESC sd, MODULE_RESUME_FN fn) +{ + struct module_list *modules = STATE_MODULES (sd); + MODULE_RESUME_LIST *l = ZALLOC (MODULE_RESUME_LIST); + MODULE_RESUME_LIST **last; + + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + SIM_ASSERT (STATE_MODULES (sd) != NULL); + + last = &modules->resume_list; + while (*last != NULL) + last = &((*last)->next); + + l->fn = fn; + l->next = NULL; + *last = l; +} + +/* Add FN to the init handler list. + suspend in the reverse order to install. */ + +void +sim_module_add_suspend_fn (SIM_DESC sd, MODULE_SUSPEND_FN fn) +{ + struct module_list *modules = STATE_MODULES (sd); + MODULE_SUSPEND_LIST *l = ZALLOC (MODULE_SUSPEND_LIST); + MODULE_SUSPEND_LIST **last; + + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + SIM_ASSERT (STATE_MODULES (sd) != NULL); + + last = &modules->suspend_list; + while (*last != NULL) + last = &((*last)->next); + + l->fn = fn; + l->next = modules->suspend_list; + modules->suspend_list = l; +} + +/* Add FN to the uninstall handler list. + Uninstall in reverse order to install. */ + +void +sim_module_add_uninstall_fn (SIM_DESC sd, MODULE_UNINSTALL_FN fn) +{ + struct module_list *modules = STATE_MODULES (sd); + MODULE_UNINSTALL_LIST *l = ZALLOC (MODULE_UNINSTALL_LIST); + + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + SIM_ASSERT (STATE_MODULES (sd) != NULL); + + l->fn = fn; + l->next = modules->uninstall_list; + modules->uninstall_list = l; +} + +/* Add FN to the info handler list. + Report info in the same order as the install. */ + +void +sim_module_add_info_fn (SIM_DESC sd, MODULE_INFO_FN fn) +{ + struct module_list *modules = STATE_MODULES (sd); + MODULE_INFO_LIST *l = ZALLOC (MODULE_INFO_LIST); + MODULE_INFO_LIST **last; + + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + SIM_ASSERT (STATE_MODULES (sd) != NULL); + + last = &modules->info_list; + while (*last != NULL) + last = &((*last)->next); + + l->fn = fn; + l->next = NULL; + *last = l; +} diff --git a/sim/common/sim-module.h b/sim/common/sim-module.h new file mode 100644 index 0000000..cbba350 --- /dev/null +++ b/sim/common/sim-module.h @@ -0,0 +1,125 @@ +/* Module support. + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file is intended to be included by sim-base.h. */ + +#ifndef SIM_MODULES_H +#define SIM_MODULES_H + +/* Modules are addons to the simulator that perform a specific function + (e.g. tracing, profiling, memory subsystem, etc.). Some modules are + builtin, and others are added at configure time. The intent is to + provide a uniform framework for all of the pieces that make up the + simulator. + + TODO: Add facilities for saving/restoring state to/from a file. */ + + +/* Various function types. */ + +typedef SIM_RC (MODULE_INSTALL_FN) (SIM_DESC); +typedef SIM_RC (MODULE_INIT_FN) (SIM_DESC); +typedef SIM_RC (MODULE_RESUME_FN) (SIM_DESC); +typedef SIM_RC (MODULE_SUSPEND_FN) (SIM_DESC); +typedef void (MODULE_UNINSTALL_FN) (SIM_DESC); +typedef void (MODULE_INFO_FN) (SIM_DESC, int); + + +/* Lists of installed handlers. */ + +typedef struct module_init_list { + struct module_init_list *next; + MODULE_INIT_FN *fn; +} MODULE_INIT_LIST; + +typedef struct module_resume_list { + struct module_resume_list *next; + MODULE_RESUME_FN *fn; +} MODULE_RESUME_LIST; + +typedef struct module_suspend_list { + struct module_suspend_list *next; + MODULE_SUSPEND_FN *fn; +} MODULE_SUSPEND_LIST; + +typedef struct module_uninstall_list { + struct module_uninstall_list *next; + MODULE_UNINSTALL_FN *fn; +} MODULE_UNINSTALL_LIST; + +typedef struct module_info_list { + struct module_info_list *next; + MODULE_INFO_FN *fn; +} MODULE_INFO_LIST; + + +/* Functions to register module with various handler lists */ + +SIM_RC sim_module_install (SIM_DESC); +void sim_module_uninstall (SIM_DESC); +void sim_module_add_init_fn (SIM_DESC sd, MODULE_INIT_FN fn); +void sim_module_add_resume_fn (SIM_DESC sd, MODULE_RESUME_FN fn); +void sim_module_add_suspend_fn (SIM_DESC sd, MODULE_SUSPEND_FN fn); +void sim_module_add_uninstall_fn (SIM_DESC sd, MODULE_UNINSTALL_FN fn); +void sim_module_add_info_fn (SIM_DESC sd, MODULE_INFO_FN fn); + + +/* Initialize installed modules before argument processing. + Called by sim_open. */ +SIM_RC sim_pre_argv_init (SIM_DESC sd, const char *myname); + +/* Initialize installed modules after argument processing. + Called by sim_open. */ +SIM_RC sim_post_argv_init (SIM_DESC sd); + +/* Re-initialize the module. Called by sim_create_inferior. */ +SIM_RC sim_module_init (SIM_DESC sd); + +/* Suspend/resume modules. Called by sim_run or sim_resume */ +SIM_RC sim_module_suspend (SIM_DESC sd); +SIM_RC sim_module_resume (SIM_DESC sd); + +/* Report general information on module */ +void sim_module_info (SIM_DESC sd, int verbose); + + +/* Module private data */ + +struct module_list { + + /* List of installed module `init' handlers */ + MODULE_INIT_LIST *init_list; + + /* List of installed module `uninstall' handlers. */ + MODULE_UNINSTALL_LIST *uninstall_list; + + /* List of installed module `resume' handlers. */ + MODULE_RESUME_LIST *resume_list; + + /* List of installed module `suspend' handlers. */ + MODULE_SUSPEND_LIST *suspend_list; + + /* List of installed module `info' handlers. */ + MODULE_INFO_LIST *info_list; + +}; + + +#endif /* SIM_MODULES_H */ diff --git a/sim/common/sim-n-bits.h b/sim/common/sim-n-bits.h new file mode 100644 index 0000000..83157ff --- /dev/null +++ b/sim/common/sim-n-bits.h @@ -0,0 +1,218 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au> + Copyright (C) 1997, Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef N +#error "N must be #defined" +#endif + +#include "symcat.h" + +#if defined(__STDC__) && defined(signed) +/* If signed were defined to be say __signed (ie, some versions of Linux), + then the signedN macro would not work correctly. If we have a standard + compiler, we have signed. */ +#undef signed +#endif + +/* NOTE: See end of file for #undef */ +#define unsignedN XCONCAT2(unsigned,N) +#define signedN XCONCAT2(signed,N) +#define LSMASKn XCONCAT2(LSMASK,N) +#define MSMASKn XCONCAT2(MSMASK,N) +#define LSMASKEDn XCONCAT2(LSMASKED,N) +#define MSMASKEDn XCONCAT2(MSMASKED,N) +#define LSEXTRACTEDn XCONCAT2(LSEXTRACTED,N) +#define MSEXTRACTEDn XCONCAT2(MSEXTRACTED,N) +#define LSINSERTEDn XCONCAT2(LSINSERTED,N) +#define MSINSERTEDn XCONCAT2(MSINSERTED,N) +#define ROTn XCONCAT2(ROT,N) +#define ROTLn XCONCAT2(ROTL,N) +#define ROTRn XCONCAT2(ROTR,N) +#define MSSEXTn XCONCAT2(MSSEXT,N) +#define LSSEXTn XCONCAT2(LSSEXT,N) + +/* TAGS: LSMASKED16 LSMASKED32 LSMASKED64 */ + +INLINE_SIM_BITS\ +(unsignedN) +LSMASKEDn (unsignedN word, + int start, + int stop) +{ + word &= LSMASKn (start, stop); + return word; +} + +/* TAGS: MSMASKED16 MSMASKED32 MSMASKED64 */ + +INLINE_SIM_BITS\ +(unsignedN) +MSMASKEDn (unsignedN word, + int start, + int stop) +{ + word &= MSMASKn (start, stop); + return word; +} + +/* TAGS: LSEXTRACTED16 LSEXTRACTED32 LSEXTRACTED64 */ + +INLINE_SIM_BITS\ +(unsignedN) +LSEXTRACTEDn (unsignedN val, + int start, + int stop) +{ + val <<= (N - 1 - start); /* drop high bits */ + val >>= (N - 1 - start) + (stop); /* drop low bits */ + return val; +} + +/* TAGS: MSEXTRACTED16 MSEXTRACTED32 MSEXTRACTED64 */ + +INLINE_SIM_BITS\ +(unsignedN) +MSEXTRACTEDn (unsignedN val, + int start, + int stop) +{ + val <<= (start); /* drop high bits */ + val >>= (start) + (N - 1 - stop); /* drop low bits */ + return val; +} + +/* TAGS: LSINSERTED16 LSINSERTED32 LSINSERTED64 */ + +INLINE_SIM_BITS\ +(unsignedN) +LSINSERTEDn (unsignedN val, + int start, + int stop) +{ + val <<= stop; + val &= LSMASKn (start, stop); + return val; +} + +/* TAGS: MSINSERTED16 MSINSERTED32 MSINSERTED64 */ + +INLINE_SIM_BITS\ +(unsignedN) +MSINSERTEDn (unsignedN val, + int start, + int stop) +{ + val <<= ((N - 1) - stop); + val &= MSMASKn (start, stop); + return val; +} + +/* TAGS: ROT16 ROT32 ROT64 */ + +INLINE_SIM_BITS\ +(unsignedN) +ROTn (unsignedN val, + int shift) +{ + if (shift > 0) + return ROTRn (val, shift); + else if (shift < 0) + return ROTLn (val, -shift); + else + return val; +} + +/* TAGS: ROTL16 ROTL32 ROTL64 */ + +INLINE_SIM_BITS\ +(unsignedN) +ROTLn (unsignedN val, + int shift) +{ + unsignedN result; + ASSERT (shift <= N); + result = (((val) << (shift)) | ((val) >> ((N)-(shift)))); + return result; +} + +/* TAGS: ROTR16 ROTR32 ROTR64 */ + +INLINE_SIM_BITS\ +(unsignedN) +ROTRn (unsignedN val, + int shift) +{ + unsignedN result; + ASSERT (shift <= N); + result = (((val) >> (shift)) | ((val) << ((N)-(shift)))); + return result; +} + +/* TAGS: LSSEXT16 LSSEXT32 LSSEXT64 */ + +INLINE_SIM_BITS\ +(unsignedN) +LSSEXTn (signedN val, + int sign_bit) +{ + int shift; + /* make the sign-bit most significant and then smear it back into + position */ + ASSERT (sign_bit < N); + shift = ((N - 1) - sign_bit); + val <<= shift; + val >>= shift; + return val; +} + +/* TAGS: MSSEXT16 MSSEXT32 MSSEXT64 */ + +INLINE_SIM_BITS\ +(unsignedN) +MSSEXTn (signedN val, + int sign_bit) +{ + /* make the sign-bit most significant and then smear it back into + position */ + ASSERT (sign_bit < N); + val <<= sign_bit; + val >>= sign_bit; + return val; +} + + +/* NOTE: See start of file for #define */ +#undef LSSEXTn +#undef MSSEXTn +#undef ROTLn +#undef ROTRn +#undef ROTn +#undef LSINSERTEDn +#undef MSINSERTEDn +#undef LSEXTRACTEDn +#undef MSEXTRACTEDn +#undef LSMASKEDn +#undef LSMASKn +#undef MSMASKEDn +#undef MSMASKn +#undef signedN +#undef unsignedN diff --git a/sim/common/sim-n-core.h b/sim/common/sim-n-core.h new file mode 100644 index 0000000..46eca03 --- /dev/null +++ b/sim/common/sim-n-core.h @@ -0,0 +1,417 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef N +#error "N must be #defined" +#endif +#ifndef M +#define M N +#endif + +/* N: The number of bytes of data to transfer. + M: The number of bytes in the type used to transfer the data */ + +#if (N > M) +#error "N (nr bytes of data) must be <= M (nr of bytes in data type)" +#endif + + +#include "symcat.h" + +/* NOTE: see end of file for #undef of these macros */ + +#define unsigned_M XCONCAT2(unsigned_,M) + +#define T2H_M XCONCAT2(T2H_,M) +#define H2T_M XCONCAT2(H2T_,M) +#define SWAP_M XCONCAT2(SWAP_,M) + +#define sim_core_read_aligned_N XCONCAT2(sim_core_read_aligned_,N) +#define sim_core_read_unaligned_N XCONCAT2(sim_core_read_unaligned_,N) +#define sim_core_read_misaligned_N XCONCAT2(sim_core_read_misaligned_,N) +#define sim_core_write_aligned_N XCONCAT2(sim_core_write_aligned_,N) +#define sim_core_write_unaligned_N XCONCAT2(sim_core_write_unaligned_,N) +#define sim_core_write_misaligned_N XCONCAT2(sim_core_write_misaligned_,N) +#define sim_core_trace_M XCONCAT2(sim_core_trace_,M) +#define sim_core_dummy_M XCONCAT2(sim_core_dummy_,M) + + +#if (M == N && N > 1) +/* dummy variable used as a return value when nothing else is + available and the compiler is complaining */ +static unsigned_M sim_core_dummy_M; +#endif + + +/* TAGS: sim_core_trace_1 sim_core_trace_2 */ +/* TAGS: sim_core_trace_4 sim_core_trace_8 */ +/* TAGS: sim_core_trace_16 */ + +#if (M == N) +STATIC_SIM_CORE(void) +sim_core_trace_M (sim_cpu *cpu, + sim_cia cia, + int line_nr, + transfer_type type, + unsigned map, + address_word addr, + unsigned_M val, + int nr_bytes) +{ + const char *transfer = (type == read_transfer ? "read" : "write"); + const char *direction = (type == read_transfer ? "->" : "<-"); + + if (TRACE_DEBUG_P (cpu)) + trace_printf (CPU_STATE (cpu), cpu, "sim-n-core.h:%d: ", line_nr); + +#if (M == 16) + trace_printf (CPU_STATE (cpu), cpu, + "%s-%d %s:0x%08lx %s 0x%08lx%08lx%08lx%08lx\n", + transfer, nr_bytes, + map_to_str (map), + (unsigned long) addr, + direction, + (unsigned long) V4_16 (val, 0), + (unsigned long) V4_16 (val, 1), + (unsigned long) V4_16 (val, 2), + (unsigned long) V4_16 (val, 3)); +#endif +#if (M == 8) + trace_printf (CPU_STATE (cpu), cpu, + "%s-%d %s:0x%08lx %s 0x%08lx%08lx\n", + transfer, nr_bytes, + map_to_str (map), + (unsigned long) addr, + direction, + (unsigned long) V4_8 (val, 0), + (unsigned long) V4_8 (val, 1)); +#endif +#if (M == 4) + trace_printf (CPU_STATE (cpu), cpu, + "%s-%d %s:0x%08lx %s 0x%08lx\n", + transfer, + nr_bytes, + map_to_str (map), + (unsigned long) addr, + direction, + (unsigned long) val); +#endif +#if (M == 2) + trace_printf (CPU_STATE (cpu), cpu, + "%s-%d %s:0x%08lx %s 0x%04lx\n", + transfer, + nr_bytes, + map_to_str (map), + (unsigned long) addr, + direction, + (unsigned long) val); +#endif +#if (M == 1) + trace_printf (CPU_STATE (cpu), cpu, + "%s-%d %s:0x%08lx %s 0x%02lx\n", + transfer, + nr_bytes, + map_to_str (map), + (unsigned long) addr, + direction, + (unsigned long) val); +#endif +} +#endif + + +/* TAGS: sim_core_read_aligned_1 sim_core_read_aligned_2 */ +/* TAGS: sim_core_read_aligned_4 sim_core_read_aligned_8 */ +/* TAGS: sim_core_read_aligned_16 */ + +#if (M == N) +INLINE_SIM_CORE(unsigned_M) +sim_core_read_aligned_N(sim_cpu *cpu, + sim_cia cia, + unsigned map, + address_word xaddr) +{ + sim_cpu_core *cpu_core = CPU_CORE (cpu); + sim_core_common *core = &cpu_core->common; + unsigned_M val; + sim_core_mapping *mapping; + address_word addr; +#if WITH_XOR_ENDIAN != 0 + if (WITH_XOR_ENDIAN) + addr = xaddr ^ cpu_core->xor[(N - 1) % WITH_XOR_ENDIAN]; + else +#endif + addr = xaddr; + mapping = sim_core_find_mapping (core, map, addr, N, read_transfer, 1 /*abort*/, cpu, cia); + do + { +#if (WITH_DEVICES) + if (WITH_CALLBACK_MEMORY && mapping->device != NULL) + { + unsigned_M data; + if (device_io_read_buffer (mapping->device, &data, mapping->space, addr, N, cpu, cia) != N) + device_error (mapping->device, "internal error - %s - io_read_buffer should not fail", + XSTRING (sim_core_read_aligned_N)); + val = T2H_M (data); + break; + } +#endif +#if (WITH_HW) + if (WITH_CALLBACK_MEMORY && mapping->device != NULL) + { + unsigned_M data; + sim_cpu_hw_io_read_buffer (cpu, cia, mapping->device, &data, mapping->space, addr, N); + val = T2H_M (data); + break; + } +#endif + val = T2H_M (*(unsigned_M*) sim_core_translate (mapping, addr)); + } + while (0); + PROFILE_COUNT_CORE (cpu, addr, N, map); + if (TRACE_P (cpu, TRACE_CORE_IDX)) + sim_core_trace_M (cpu, cia, __LINE__, read_transfer, map, addr, val, N); + return val; +} +#endif + +/* TAGS: sim_core_read_unaligned_1 sim_core_read_unaligned_2 */ +/* TAGS: sim_core_read_unaligned_4 sim_core_read_unaligned_8 */ +/* TAGS: sim_core_read_unaligned_16 */ + +#if (M == N && N > 1) +INLINE_SIM_CORE(unsigned_M) +sim_core_read_unaligned_N(sim_cpu *cpu, + sim_cia cia, + unsigned map, + address_word addr) +{ + int alignment = N - 1; + /* if hardwired to forced alignment just do it */ + if (WITH_ALIGNMENT == FORCED_ALIGNMENT) + return sim_core_read_aligned_N (cpu, cia, map, addr & ~alignment); + else if ((addr & alignment) == 0) + return sim_core_read_aligned_N (cpu, cia, map, addr); + else + switch (CURRENT_ALIGNMENT) + { + case STRICT_ALIGNMENT: + SIM_CORE_SIGNAL (CPU_STATE (cpu), cpu, cia, map, N, addr, + read_transfer, sim_core_unaligned_signal); + case NONSTRICT_ALIGNMENT: + { + unsigned_M val; + if (sim_core_xor_read_buffer (CPU_STATE (cpu), cpu, map, &val, addr, N) != N) + SIM_CORE_SIGNAL (CPU_STATE (cpu), cpu, cia, map, N, addr, + read_transfer, sim_core_unaligned_signal); + val = T2H_M(val); + PROFILE_COUNT_CORE (cpu, addr, N, map); + if (TRACE_P (cpu, TRACE_CORE_IDX)) + sim_core_trace_M (cpu, cia, __LINE__, read_transfer, map, addr, val, N); + return val; + } + case FORCED_ALIGNMENT: + return sim_core_read_aligned_N (cpu, cia, map, addr & ~alignment); + case MIXED_ALIGNMENT: + sim_engine_abort (CPU_STATE (cpu), cpu, cia, + "internal error - %s - mixed alignment", + XSTRING (sim_core_read_unaligned_N)); + default: + sim_engine_abort (CPU_STATE (cpu), cpu, cia, + "internal error - %s - bad switch", + XSTRING (sim_core_read_unaligned_N)); + /* to keep some compilers happy, we return a dummy */ + return sim_core_dummy_M; + } +} +#endif + +/* TAGS: sim_core_read_misaligned_3 sim_core_read_misaligned_5 */ +/* TAGS: sim_core_read_misaligned_6 sim_core_read_misaligned_7 */ + +#if (M != N) +INLINE_SIM_CORE(unsigned_M) +sim_core_read_misaligned_N(sim_cpu *cpu, + sim_cia cia, + unsigned map, + address_word addr) +{ + unsigned_M val = 0; + if (sim_core_xor_read_buffer (CPU_STATE (cpu), cpu, map, &val, addr, N) != N) + SIM_CORE_SIGNAL (CPU_STATE (cpu), cpu, cia, map, N, addr, + read_transfer, sim_core_unaligned_signal); + if (CURRENT_HOST_BYTE_ORDER != CURRENT_TARGET_BYTE_ORDER) + val = SWAP_M (val); + if (CURRENT_TARGET_BYTE_ORDER == BIG_ENDIAN) + val >>= (M - N) * 8; + PROFILE_COUNT_CORE (cpu, addr, N, map); + if (TRACE_P (cpu, TRACE_CORE_IDX)) + sim_core_trace_M (cpu, cia, __LINE__, read_transfer, map, addr, val, N); + return val; +} +#endif + +/* TAGS: sim_core_write_aligned_1 sim_core_write_aligned_2 */ +/* TAGS: sim_core_write_aligned_4 sim_core_write_aligned_8 */ +/* TAGS: sim_core_write_aligned_16 */ + +#if (M == N) +INLINE_SIM_CORE(void) +sim_core_write_aligned_N(sim_cpu *cpu, + sim_cia cia, + unsigned map, + address_word xaddr, + unsigned_M val) +{ + sim_cpu_core *cpu_core = CPU_CORE (cpu); + sim_core_common *core = &cpu_core->common; + sim_core_mapping *mapping; + address_word addr; +#if WITH_XOR_ENDIAN != 0 + if (WITH_XOR_ENDIAN) + addr = xaddr ^ cpu_core->xor[(N - 1) % WITH_XOR_ENDIAN]; + else +#endif + addr = xaddr; + mapping = sim_core_find_mapping (core, map, addr, N, write_transfer, 1 /*abort*/, cpu, cia); + do + { +#if (WITH_DEVICES) + if (WITH_CALLBACK_MEMORY && mapping->device != NULL) + { + unsigned_M data = H2T_M (val); + if (device_io_write_buffer (mapping->device, &data, mapping->space, addr, N, cpu, cia) != N) + device_error (mapping->device, "internal error - %s - io_write_buffer should not fail", + XSTRING (sim_core_write_aligned_N)); + break; + } +#endif +#if (WITH_HW) + if (WITH_CALLBACK_MEMORY && mapping->device != NULL) + { + unsigned_M data = H2T_M (val); + sim_cpu_hw_io_write_buffer (cpu, cia, mapping->device, &data, mapping->space, addr, N); + break; + } +#endif + *(unsigned_M*) sim_core_translate (mapping, addr) = H2T_M (val); + } + while (0); + PROFILE_COUNT_CORE (cpu, addr, N, map); + if (TRACE_P (cpu, TRACE_CORE_IDX)) + sim_core_trace_M (cpu, cia, __LINE__, write_transfer, map, addr, val, N); +} +#endif + +/* TAGS: sim_core_write_unaligned_1 sim_core_write_unaligned_2 */ +/* TAGS: sim_core_write_unaligned_4 sim_core_write_unaligned_8 */ +/* TAGS: sim_core_write_unaligned_16 */ + +#if (M == N && N > 1) +INLINE_SIM_CORE(void) +sim_core_write_unaligned_N(sim_cpu *cpu, + sim_cia cia, + unsigned map, + address_word addr, + unsigned_M val) +{ + int alignment = N - 1; + /* if hardwired to forced alignment just do it */ + if (WITH_ALIGNMENT == FORCED_ALIGNMENT) + sim_core_write_aligned_N (cpu, cia, map, addr & ~alignment, val); + else if ((addr & alignment) == 0) + sim_core_write_aligned_N (cpu, cia, map, addr, val); + else + switch (CURRENT_ALIGNMENT) + { + case STRICT_ALIGNMENT: + SIM_CORE_SIGNAL (CPU_STATE (cpu), cpu, cia, map, N, addr, + write_transfer, sim_core_unaligned_signal); + break; + case NONSTRICT_ALIGNMENT: + { + unsigned_M data = H2T_M (val); + if (sim_core_xor_write_buffer (CPU_STATE (cpu), cpu, map, &data, addr, N) != N) + SIM_CORE_SIGNAL (CPU_STATE (cpu), cpu, cia, map, N, addr, + write_transfer, sim_core_unaligned_signal); + PROFILE_COUNT_CORE (cpu, addr, N, map); + if (TRACE_P (cpu, TRACE_CORE_IDX)) + sim_core_trace_M (cpu, cia, __LINE__, write_transfer, map, addr, val, N); + break; + } + case FORCED_ALIGNMENT: + sim_core_write_aligned_N (cpu, cia, map, addr & ~alignment, val); + break; + case MIXED_ALIGNMENT: + sim_engine_abort (CPU_STATE (cpu), cpu, cia, + "internal error - %s - mixed alignment", + XSTRING (sim_core_write_unaligned_N)); + break; + default: + sim_engine_abort (CPU_STATE (cpu), cpu, cia, + "internal error - %s - bad switch", + XSTRING (sim_core_write_unaligned_N)); + break; + } +} +#endif + +/* TAGS: sim_core_write_misaligned_3 sim_core_write_misaligned_5 */ +/* TAGS: sim_core_write_misaligned_6 sim_core_write_misaligned_7 */ + +#if (M != N) +INLINE_SIM_CORE(void) +sim_core_write_misaligned_N(sim_cpu *cpu, + sim_cia cia, + unsigned map, + address_word addr, + unsigned_M val) +{ + unsigned_M data = val; + if (CURRENT_TARGET_BYTE_ORDER == BIG_ENDIAN) + data <<= (M - N) * 8; + if (CURRENT_HOST_BYTE_ORDER != CURRENT_TARGET_BYTE_ORDER) + data = SWAP_M (data); + if (sim_core_xor_write_buffer (CPU_STATE (cpu), cpu, map, &data, addr, N) != N) + SIM_CORE_SIGNAL (CPU_STATE (cpu), cpu, cia, map, N, addr, + write_transfer, sim_core_unaligned_signal); + PROFILE_COUNT_CORE (cpu, addr, N, map); + if (TRACE_P (cpu, TRACE_CORE_IDX)) + sim_core_trace_M (cpu, cia, __LINE__, write_transfer, map, addr, val, N); +} +#endif + + +/* NOTE: see start of file for #define of these macros */ +#undef unsigned_M +#undef T2H_M +#undef H2T_M +#undef SWAP_M +#undef sim_core_read_aligned_N +#undef sim_core_read_unaligned_N +#undef sim_core_read_misaligned_N +#undef sim_core_write_aligned_N +#undef sim_core_write_unaligned_N +#undef sim_core_write_misaligned_N +#undef sim_core_trace_M +#undef sim_core_dummy_M +#undef M +#undef N diff --git a/sim/common/sim-n-endian.h b/sim/common/sim-n-endian.h new file mode 100644 index 0000000..c53e05a --- /dev/null +++ b/sim/common/sim-n-endian.h @@ -0,0 +1,169 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef N +#error "N must be #defined" +#endif + +#include "symcat.h" + +/* NOTE: See end of file for #undef */ +#define unsigned_N XCONCAT2(unsigned_,N) +#define endian_t2h_N XCONCAT2(endian_t2h_,N) +#define endian_h2t_N XCONCAT2(endian_h2t_,N) +#define _SWAP_N XCONCAT2(_SWAP_,N) +#define swap_N XCONCAT2(swap_,N) +#define endian_h2be_N XCONCAT2(endian_h2be_,N) +#define endian_be2h_N XCONCAT2(endian_be2h_,N) +#define endian_h2le_N XCONCAT2(endian_h2le_,N) +#define endian_le2h_N XCONCAT2(endian_le2h_,N) +#define offset_N XCONCAT2(offset_,N) + +/* TAGS: endian_t2h_1 endian_t2h_2 endian_t2h_4 endian_t2h_8 endian_t2h_16 */ + +INLINE_SIM_ENDIAN\ +(unsigned_N) +endian_t2h_N(unsigned_N raw_in) +{ + if (CURRENT_TARGET_BYTE_ORDER == CURRENT_HOST_BYTE_ORDER) { + return raw_in; + } + else { + _SWAP_N(return,raw_in); + } +} + +/* TAGS: endian_h2t_1 endian_h2t_2 endian_h2t_4 endian_h2t_8 endian_h2t_16 */ + +INLINE_SIM_ENDIAN\ +(unsigned_N) +endian_h2t_N(unsigned_N raw_in) +{ + if (CURRENT_TARGET_BYTE_ORDER == CURRENT_HOST_BYTE_ORDER) { + return raw_in; + } + else { + _SWAP_N(return,raw_in); + } +} + +/* TAGS: swap_1 swap_2 swap_4 swap_8 swap_16 */ + +INLINE_SIM_ENDIAN\ +(unsigned_N) +swap_N(unsigned_N raw_in) +{ + _SWAP_N(return,raw_in); +} + +/* TAGS: endian_h2be_1 endian_h2be_2 endian_h2be_4 endian_h2be_8 endian_h2be_16 */ + +INLINE_SIM_ENDIAN\ +(unsigned_N) +endian_h2be_N(unsigned_N raw_in) +{ + if (CURRENT_HOST_BYTE_ORDER == BIG_ENDIAN) { + return raw_in; + } + else { + _SWAP_N(return,raw_in); + } +} + +/* TAGS: endian_be2h_1 endian_be2h_2 endian_be2h_4 endian_be2h_8 endian_be2h_16 */ + +INLINE_SIM_ENDIAN\ +(unsigned_N) +endian_be2h_N(unsigned_N raw_in) +{ + if (CURRENT_HOST_BYTE_ORDER == BIG_ENDIAN) { + return raw_in; + } + else { + _SWAP_N(return,raw_in); + } +} + +/* TAGS: endian_h2le_1 endian_h2le_2 endian_h2le_4 endian_h2le_8 endian_h2le_16 */ + +INLINE_SIM_ENDIAN\ +(unsigned_N) +endian_h2le_N(unsigned_N raw_in) +{ + if (CURRENT_HOST_BYTE_ORDER == LITTLE_ENDIAN) { + return raw_in; + } + else { + _SWAP_N(return,raw_in); + } +} + +/* TAGS: endian_le2h_1 endian_le2h_2 endian_le2h_4 endian_le2h_8 endian_le2h_16 */ + +INLINE_SIM_ENDIAN\ +(unsigned_N) +endian_le2h_N(unsigned_N raw_in) +{ + if (CURRENT_HOST_BYTE_ORDER == LITTLE_ENDIAN) { + return raw_in; + } + else { + _SWAP_N(return,raw_in); + } +} + +/* TAGS: offset_1 offset_2 offset_4 offset_8 offset_16 */ + +INLINE_SIM_ENDIAN\ +(void*) +offset_N (unsigned_N *x, + unsigned sizeof_word, + unsigned word) +{ + char *in = (char*)x; + char *out; + unsigned offset = sizeof_word * word; + ASSERT (offset + sizeof_word <= sizeof(unsigned_N)); + ASSERT (word < (sizeof (unsigned_N) / sizeof_word)); + ASSERT ((sizeof (unsigned_N) % sizeof_word) == 0); + if (WITH_HOST_BYTE_ORDER == LITTLE_ENDIAN) + { + out = in + sizeof (unsigned_N) - offset - sizeof_word; + } + else + { + out = in + offset; + } + return out; +} + + +/* NOTE: See start of file for #define */ +#undef unsigned_N +#undef endian_t2h_N +#undef endian_h2t_N +#undef _SWAP_N +#undef swap_N +#undef endian_h2be_N +#undef endian_be2h_N +#undef endian_h2le_N +#undef endian_le2h_N +#undef offset_N diff --git a/sim/common/sim-options.c b/sim/common/sim-options.c new file mode 100644 index 0000000..b49256b --- /dev/null +++ b/sim/common/sim-options.c @@ -0,0 +1,936 @@ +/* Simulator option handling. + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "sim-main.h" +#ifdef HAVE_STRING_H +#include <string.h> +#else +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#include <ctype.h> +#include "libiberty.h" +#include "sim-options.h" +#include "sim-io.h" +#include "sim-assert.h" + +#include "bfd.h" + +/* Add a set of options to the simulator. + TABLE is an array of OPTIONS terminated by a NULL `opt.name' entry. + This is intended to be called by modules in their `install' handler. */ + +SIM_RC +sim_add_option_table (SIM_DESC sd, sim_cpu *cpu, const OPTION *table) +{ + struct option_list *ol = ((struct option_list *) + xmalloc (sizeof (struct option_list))); + + /* Note: The list is constructed in the reverse order we're called so + later calls will override earlier ones (in case that ever happens). + This is the intended behaviour. */ + + if (cpu) + { + ol->next = CPU_OPTIONS (cpu); + ol->options = table; + CPU_OPTIONS (cpu) = ol; + } + else + { + ol->next = STATE_OPTIONS (sd); + ol->options = table; + STATE_OPTIONS (sd) = ol; + } + + return SIM_RC_OK; +} + +/* Standard option table. + Modules may specify additional ones. + The caller of sim_parse_args may also specify additional options + by calling sim_add_option_table first. */ + +static DECLARE_OPTION_HANDLER (standard_option_handler); + +/* FIXME: We shouldn't print in --help output options that aren't usable. + Some fine tuning will be necessary. One can either move less general + options to another table or use a HAVE_FOO macro to ifdef out unavailable + options. */ + +/* ??? One might want to conditionally compile out the entries that + aren't enabled. There's a distinction, however, between options a + simulator can't support and options that haven't been configured in. + Certainly options a simulator can't support shouldn't appear in the + output of --help. Whether the same thing applies to options that haven't + been configured in or not isn't something I can get worked up over. + [Note that conditionally compiling them out might simply involve moving + the option to another table.] + If you decide to conditionally compile them out as well, delete this + comment and add a comment saying that that is the rule. */ + +typedef enum { + OPTION_DEBUG_INSN = OPTION_START, + OPTION_DEBUG_FILE, + OPTION_DO_COMMAND, + OPTION_ARCHITECTURE, + OPTION_TARGET, + OPTION_ARCHITECTURE_INFO, + OPTION_ENVIRONMENT, + OPTION_ALIGNMENT, + OPTION_VERBOSE, +#if defined (SIM_HAVE_BIENDIAN) + OPTION_ENDIAN, +#endif + OPTION_DEBUG, +#ifdef SIM_HAVE_FLATMEM + OPTION_MEM_SIZE, +#endif + OPTION_HELP, +#ifdef SIM_H8300 /* FIXME: Should be movable to h8300 dir. */ + OPTION_H8300, +#endif +} STANDARD_OPTIONS; + +static const OPTION standard_options[] = +{ + { {"verbose", no_argument, NULL, OPTION_VERBOSE}, + 'v', NULL, "Verbose output", + standard_option_handler }, + +#if defined (SIM_HAVE_BIENDIAN) /* ??? && WITH_TARGET_BYTE_ORDER == 0 */ + { {"endian", required_argument, NULL, OPTION_ENDIAN}, + 'E', "big|little", "Set endianness", + standard_option_handler }, +#endif + +#ifdef SIM_HAVE_ENVIRONMENT + /* This option isn't supported unless all choices are supported in keeping + with the goal of not printing in --help output things the simulator can't + do [as opposed to things that just haven't been configured in]. */ + { {"environment", required_argument, NULL, OPTION_ENVIRONMENT}, + '\0', "user|virtual|operating", "Set running environment", + standard_option_handler }, +#endif + + { {"alignment", required_argument, NULL, OPTION_ALIGNMENT}, + '\0', "strict|nonstrict|forced", "Set memory access alignment", + standard_option_handler }, + + { {"debug", no_argument, NULL, OPTION_DEBUG}, + 'D', NULL, "Print debugging messages", + standard_option_handler }, + { {"debug-insn", no_argument, NULL, OPTION_DEBUG_INSN}, + '\0', NULL, "Print instruction debugging messages", + standard_option_handler }, + { {"debug-file", required_argument, NULL, OPTION_DEBUG_FILE}, + '\0', "FILE NAME", "Specify debugging output file", + standard_option_handler }, + +#ifdef SIM_H8300 /* FIXME: Should be movable to h8300 dir. */ + { {"h8300h", no_argument, NULL, OPTION_H8300}, + 'h', NULL, "Indicate the CPU is h8/300h or h8/300s", + standard_option_handler }, +#endif + +#ifdef SIM_HAVE_FLATMEM + { {"mem-size", required_argument, NULL, OPTION_MEM_SIZE}, + 'm', "MEMORY SIZE", "Specify memory size", + standard_option_handler }, +#endif + + { {"do-command", required_argument, NULL, OPTION_DO_COMMAND}, + '\0', "COMMAND", ""/*undocumented*/, + standard_option_handler }, + + { {"help", no_argument, NULL, OPTION_HELP}, + 'H', NULL, "Print help information", + standard_option_handler }, + + { {"architecture", required_argument, NULL, OPTION_ARCHITECTURE}, + '\0', "MACHINE", "Specify the architecture to use", + standard_option_handler }, + { {"architecture-info", no_argument, NULL, OPTION_ARCHITECTURE_INFO}, + '\0', NULL, "List supported architectures", + standard_option_handler }, + { {"info-architecture", no_argument, NULL, OPTION_ARCHITECTURE_INFO}, + '\0', NULL, NULL, + standard_option_handler }, + + { {"target", required_argument, NULL, OPTION_TARGET}, + '\0', "BFDNAME", "Specify the object-code format for the object files", + standard_option_handler }, + + { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL } +}; + +static SIM_RC +standard_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt, + char *arg, int is_command) +{ + int i,n; + + switch ((STANDARD_OPTIONS) opt) + { + case OPTION_VERBOSE: + STATE_VERBOSE_P (sd) = 1; + break; + +#ifdef SIM_HAVE_BIENDIAN + case OPTION_ENDIAN: + if (strcmp (arg, "big") == 0) + { + if (WITH_TARGET_BYTE_ORDER == LITTLE_ENDIAN) + { + sim_io_eprintf (sd, "Simulator compiled for little endian only.\n"); + return SIM_RC_FAIL; + } + /* FIXME:wip: Need to set something in STATE_CONFIG. */ + current_target_byte_order = BIG_ENDIAN; + } + else if (strcmp (arg, "little") == 0) + { + if (WITH_TARGET_BYTE_ORDER == BIG_ENDIAN) + { + sim_io_eprintf (sd, "Simulator compiled for big endian only.\n"); + return SIM_RC_FAIL; + } + /* FIXME:wip: Need to set something in STATE_CONFIG. */ + current_target_byte_order = LITTLE_ENDIAN; + } + else + { + sim_io_eprintf (sd, "Invalid endian specification `%s'\n", arg); + return SIM_RC_FAIL; + } + break; +#endif + + case OPTION_ENVIRONMENT: + if (strcmp (arg, "user") == 0) + STATE_ENVIRONMENT (sd) = USER_ENVIRONMENT; + else if (strcmp (arg, "virtual") == 0) + STATE_ENVIRONMENT (sd) = VIRTUAL_ENVIRONMENT; + else if (strcmp (arg, "operating") == 0) + STATE_ENVIRONMENT (sd) = OPERATING_ENVIRONMENT; + else + { + sim_io_eprintf (sd, "Invalid environment specification `%s'\n", arg); + return SIM_RC_FAIL; + } + if (WITH_ENVIRONMENT != ALL_ENVIRONMENT + && WITH_ENVIRONMENT != STATE_ENVIRONMENT (sd)) + { + char *type; + switch (WITH_ENVIRONMENT) + { + case USER_ENVIRONMENT: type = "user"; break; + case VIRTUAL_ENVIRONMENT: type = "virtual"; break; + case OPERATING_ENVIRONMENT: type = "operating"; break; + } + sim_io_eprintf (sd, "Simulator compiled for the %s environment only.\n", + type); + return SIM_RC_FAIL; + } + break; + + case OPTION_ALIGNMENT: + if (strcmp (arg, "strict") == 0) + { + if (WITH_ALIGNMENT == 0 || WITH_ALIGNMENT == STRICT_ALIGNMENT) + { + current_alignment = STRICT_ALIGNMENT; + break; + } + } + else if (strcmp (arg, "nonstrict") == 0) + { + if (WITH_ALIGNMENT == 0 || WITH_ALIGNMENT == NONSTRICT_ALIGNMENT) + { + current_alignment = NONSTRICT_ALIGNMENT; + break; + } + } + else if (strcmp (arg, "forced") == 0) + { + if (WITH_ALIGNMENT == 0 || WITH_ALIGNMENT == FORCED_ALIGNMENT) + { + current_alignment = FORCED_ALIGNMENT; + break; + } + } + else + { + sim_io_eprintf (sd, "Invalid alignment specification `%s'\n", arg); + return SIM_RC_FAIL; + } + switch (WITH_ALIGNMENT) + { + case STRICT_ALIGNMENT: + sim_io_eprintf (sd, "Simulator compiled for strict alignment only.\n"); + break; + case NONSTRICT_ALIGNMENT: + sim_io_eprintf (sd, "Simulator compiled for nonstrict alignment only.\n"); + break; + case FORCED_ALIGNMENT: + sim_io_eprintf (sd, "Simulator compiled for forced alignment only.\n"); + break; + } + return SIM_RC_FAIL; + + case OPTION_DEBUG: + if (! WITH_DEBUG) + sim_io_eprintf (sd, "Debugging not compiled in, `-D' ignored\n"); + else + { + for (n = 0; n < MAX_NR_PROCESSORS; ++n) + for (i = 0; i < MAX_DEBUG_VALUES; ++i) + CPU_DEBUG_FLAGS (STATE_CPU (sd, n))[i] = 1; + } + break; + + case OPTION_DEBUG_INSN : + if (! WITH_DEBUG) + sim_io_eprintf (sd, "Debugging not compiled in, `--debug-insn' ignored\n"); + else + { + for (n = 0; n < MAX_NR_PROCESSORS; ++n) + CPU_DEBUG_FLAGS (STATE_CPU (sd, n))[DEBUG_INSN_IDX] = 1; + } + break; + + case OPTION_DEBUG_FILE : + if (! WITH_DEBUG) + sim_io_eprintf (sd, "Debugging not compiled in, `--debug-file' ignored\n"); + else + { + FILE *f = fopen (arg, "w"); + + if (f == NULL) + { + sim_io_eprintf (sd, "Unable to open debug output file `%s'\n", arg); + return SIM_RC_FAIL; + } + for (n = 0; n < MAX_NR_PROCESSORS; ++n) + CPU_DEBUG_FILE (STATE_CPU (sd, n)) = f; + } + break; + +#ifdef SIM_H8300 /* FIXME: Can be moved to h8300 dir. */ + case OPTION_H8300: + set_h8300h (1); + break; +#endif + +#ifdef SIM_HAVE_FLATMEM + case OPTION_MEM_SIZE: + { + unsigned long ul = strtol (arg, NULL, 0); + /* 16384: some minimal amount */ + if (! isdigit (arg[0]) || ul < 16384) + { + sim_io_eprintf (sd, "Invalid memory size `%s'", arg); + return SIM_RC_FAIL; + } + STATE_MEM_SIZE (sd) = ul; + } + break; +#endif + + case OPTION_DO_COMMAND: + sim_do_command (sd, arg); + break; + + case OPTION_ARCHITECTURE: + { + const struct bfd_arch_info *ap = bfd_scan_arch (arg); + if (ap == NULL) + { + sim_io_eprintf (sd, "Architecture `%s' unknown\n", arg); + return SIM_RC_FAIL; + } + STATE_ARCHITECTURE (sd) = ap; + break; + } + + case OPTION_ARCHITECTURE_INFO: + { + const char **list = bfd_arch_list(); + const char **lp; + if (list == NULL) + abort (); + sim_io_printf (sd, "Possible architectures:"); + for (lp = list; *lp != NULL; lp++) + sim_io_printf (sd, " %s", *lp); + sim_io_printf (sd, "\n"); + free (list); + break; + } + + case OPTION_TARGET: + { + STATE_TARGET (sd) = xstrdup (arg); + break; + } + + case OPTION_HELP: + sim_print_help (sd, is_command); + if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE) + exit (0); + /* FIXME: 'twould be nice to do something similar if gdb. */ + break; + } + + return SIM_RC_OK; +} + +/* Add the standard option list to the simulator. */ + +SIM_RC +standard_install (SIM_DESC sd) +{ + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + if (sim_add_option_table (sd, NULL, standard_options) != SIM_RC_OK) + return SIM_RC_FAIL; + return SIM_RC_OK; +} + +/* Return non-zero if arg is a duplicate argument. + If ARG is NULL, initialize. */ + +#define ARG_HASH_SIZE 97 +#define ARG_HASH(a) ((256 * (unsigned char) a[0] + (unsigned char) a[1]) % ARG_HASH_SIZE) + +static int +dup_arg_p (arg) + char *arg; +{ + int hash; + static char **arg_table = NULL; + + if (arg == NULL) + { + if (arg_table == NULL) + arg_table = (char **) xmalloc (ARG_HASH_SIZE * sizeof (char *)); + memset (arg_table, 0, ARG_HASH_SIZE * sizeof (char *)); + return 0; + } + + hash = ARG_HASH (arg); + while (arg_table[hash] != NULL) + { + if (strcmp (arg, arg_table[hash]) == 0) + return 1; + /* We assume there won't be more than ARG_HASH_SIZE arguments so we + don't check if the table is full. */ + if (++hash == ARG_HASH_SIZE) + hash = 0; + } + arg_table[hash] = arg; + return 0; +} + +/* Called by sim_open to parse the arguments. */ + +SIM_RC +sim_parse_args (sd, argv) + SIM_DESC sd; + char **argv; +{ + int c, i, argc, num_opts; + char *p, *short_options; + /* The `val' option struct entry is dynamically assigned for options that + only come in the long form. ORIG_VAL is used to get the original value + back. */ + int *orig_val; + struct option *lp, *long_options; + const struct option_list *ol; + const OPTION *opt; + OPTION_HANDLER **handlers; + sim_cpu **opt_cpu; + + /* Count the number of arguments. */ + for (argc = 0; argv[argc] != NULL; ++argc) + continue; + + /* Count the number of options. */ + num_opts = 0; + for (ol = STATE_OPTIONS (sd); ol != NULL; ol = ol->next) + for (opt = ol->options; OPTION_VALID_P (opt); ++opt) + ++num_opts; + for (i = 0; i < MAX_NR_PROCESSORS; ++i) + for (ol = CPU_OPTIONS (STATE_CPU (sd, i)); ol != NULL; ol = ol->next) + for (opt = ol->options; OPTION_VALID_P (opt); ++opt) + ++num_opts; + + /* Initialize duplicate argument checker. */ + (void) dup_arg_p (NULL); + + /* Build the option table for getopt. */ + + long_options = NZALLOC (struct option, num_opts + 1); + lp = long_options; + short_options = NZALLOC (char, num_opts * 3 + 1); + p = short_options; + handlers = NZALLOC (OPTION_HANDLER *, OPTION_START + num_opts); + orig_val = NZALLOC (int, OPTION_START + num_opts); + opt_cpu = NZALLOC (sim_cpu *, OPTION_START + num_opts); + + /* Set '+' as first char so argument permutation isn't done. This + is done to stop getopt_long returning options that appear after + the target program. Such options should be passed unchanged into + the program image. */ + *p++ = '+'; + + for (i = OPTION_START, ol = STATE_OPTIONS (sd); ol != NULL; ol = ol->next) + for (opt = ol->options; OPTION_VALID_P (opt); ++opt) + { + if (dup_arg_p (opt->opt.name)) + continue; + if (opt->shortopt != 0) + { + *p++ = opt->shortopt; + if (opt->opt.has_arg == required_argument) + *p++ = ':'; + else if (opt->opt.has_arg == optional_argument) + { *p++ = ':'; *p++ = ':'; } + handlers[(unsigned char) opt->shortopt] = opt->handler; + if (opt->opt.val != 0) + orig_val[(unsigned char) opt->shortopt] = opt->opt.val; + else + orig_val[(unsigned char) opt->shortopt] = opt->shortopt; + } + if (opt->opt.name != NULL) + { + *lp = opt->opt; + /* Dynamically assign `val' numbers for long options. */ + lp->val = i++; + handlers[lp->val] = opt->handler; + orig_val[lp->val] = opt->opt.val; + opt_cpu[lp->val] = NULL; + ++lp; + } + } + + for (c = 0; c < MAX_NR_PROCESSORS; ++c) + { + sim_cpu *cpu = STATE_CPU (sd, c); + for (ol = CPU_OPTIONS (cpu); ol != NULL; ol = ol->next) + for (opt = ol->options; OPTION_VALID_P (opt); ++opt) + { +#if 0 /* Each option is prepended with --<cpuname>- so this greatly cuts down + on the need for dup_arg_p checking. Maybe in the future it'll be + needed so this is just commented out, and not deleted. */ + if (dup_arg_p (opt->opt.name)) + continue; +#endif + /* Don't allow short versions of cpu specific options for now. */ + if (opt->shortopt != 0) + { + sim_io_eprintf (sd, "internal error, short cpu specific option"); + return SIM_RC_FAIL; + } + if (opt->opt.name != NULL) + { + char *name; + *lp = opt->opt; + /* Prepend --<cpuname>- to the option. */ + asprintf (&name, "%s-%s", CPU_NAME (cpu), lp->name); + lp->name = name; + /* Dynamically assign `val' numbers for long options. */ + lp->val = i++; + handlers[lp->val] = opt->handler; + orig_val[lp->val] = opt->opt.val; + opt_cpu[lp->val] = cpu; + ++lp; + } + } + } + + /* Terminate the short and long option lists. */ + *p = 0; + lp->name = NULL; + + /* Ensure getopt is initialized. */ + optind = 0; + + while (1) + { + int longind, optc; + + optc = getopt_long (argc, argv, short_options, long_options, &longind); + if (optc == -1) + { + if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE) + STATE_PROG_ARGV (sd) = dupargv (argv + optind); + break; + } + if (optc == '?') + return SIM_RC_FAIL; + + if ((*handlers[optc]) (sd, opt_cpu[optc], orig_val[optc], optarg, 0/*!is_command*/) == SIM_RC_FAIL) + return SIM_RC_FAIL; + } + + return SIM_RC_OK; +} + +/* Utility of sim_print_help to print a list of option tables. */ + +static void +print_help (SIM_DESC sd, sim_cpu *cpu, const struct option_list *ol, int is_command) +{ + const OPTION *opt; + + for ( ; ol != NULL; ol = ol->next) + for (opt = ol->options; OPTION_VALID_P (opt); ++opt) + { + const int indent = 30; + int comma, len; + const OPTION *o; + + if (dup_arg_p (opt->opt.name)) + continue; + + if (opt->doc == NULL) + continue; + + if (opt->doc_name != NULL && opt->doc_name [0] == '\0') + continue; + + sim_io_printf (sd, " "); + + comma = 0; + len = 2; + + /* list any short options (aliases) for the current OPT */ + if (!is_command) + { + o = opt; + do + { + if (o->shortopt != '\0') + { + sim_io_printf (sd, "%s-%c", comma ? ", " : "", o->shortopt); + len += (comma ? 2 : 0) + 2; + if (o->arg != NULL) + { + if (o->opt.has_arg == optional_argument) + { + sim_io_printf (sd, "[%s]", o->arg); + len += 1 + strlen (o->arg) + 1; + } + else + { + sim_io_printf (sd, " %s", o->arg); + len += 1 + strlen (o->arg); + } + } + comma = 1; + } + ++o; + } + while (OPTION_VALID_P (o) && o->doc == NULL); + } + + /* list any long options (aliases) for the current OPT */ + o = opt; + do + { + const char *name; + const char *cpu_prefix = cpu ? CPU_NAME (cpu) : NULL; + if (o->doc_name != NULL) + name = o->doc_name; + else + name = o->opt.name; + if (name != NULL) + { + sim_io_printf (sd, "%s%s%s%s%s", + comma ? ", " : "", + is_command ? "" : "--", + cpu ? cpu_prefix : "", + cpu ? "-" : "", + name); + len += ((comma ? 2 : 0) + + (is_command ? 0 : 2) + + strlen (name)); + if (o->arg != NULL) + { + if (o->opt.has_arg == optional_argument) + { + sim_io_printf (sd, " [%s]", o->arg); + len += 2 + strlen (o->arg) + 1; + } + else + { + sim_io_printf (sd, " %s", o->arg); + len += 1 + strlen (o->arg); + } + } + comma = 1; + } + ++o; + } + while (OPTION_VALID_P (o) && o->doc == NULL); + + if (len >= indent) + { + sim_io_printf (sd, "\n%*s", indent, ""); + } + else + sim_io_printf (sd, "%*s", indent - len, ""); + + /* print the description, word wrap long lines */ + { + const char *chp = opt->doc; + unsigned doc_width = 80 - indent; + while (strlen (chp) >= doc_width) /* some slack */ + { + const char *end = chp + doc_width - 1; + while (end > chp && !isspace (*end)) + end --; + if (end == chp) + end = chp + doc_width - 1; + sim_io_printf (sd, "%.*s\n%*s", end - chp, chp, indent, ""); + chp = end; + while (isspace (*chp) && *chp != '\0') + chp++; + } + sim_io_printf (sd, "%s\n", chp); + } + } +} + +/* Print help messages for the options. */ + +void +sim_print_help (sd, is_command) + SIM_DESC sd; + int is_command; +{ + if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE) + sim_io_printf (sd, "Usage: %s [options] program [program args]\n", + STATE_MY_NAME (sd)); + + /* Initialize duplicate argument checker. */ + (void) dup_arg_p (NULL); + + if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE) + sim_io_printf (sd, "Options:\n"); + else + sim_io_printf (sd, "Commands:\n"); + + print_help (sd, NULL, STATE_OPTIONS (sd), is_command); + sim_io_printf (sd, "\n"); + + /* Print cpu-specific options. */ + { + int i; + + for (i = 0; i < MAX_NR_PROCESSORS; ++i) + { + sim_cpu *cpu = STATE_CPU (sd, i); + if (CPU_OPTIONS (cpu) == NULL) + continue; + sim_io_printf (sd, "CPU %s specific options:\n", CPU_NAME (cpu)); + print_help (sd, cpu, CPU_OPTIONS (cpu), is_command); + sim_io_printf (sd, "\n"); + } + } + + sim_io_printf (sd, "Note: Depending on the simulator configuration some %ss\n", + STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE ? "option" : "command"); + sim_io_printf (sd, " may not be applicable\n"); + + if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE) + { + sim_io_printf (sd, "\n"); + sim_io_printf (sd, "program args Arguments to pass to simulated program.\n"); + sim_io_printf (sd, " Note: Very few simulators support this.\n"); + } +} + +/* Utility of sim_args_command to find the closest match for a command. + Commands that have "-" in them can be specified as separate words. + e.g. sim memory-region 0x800000,0x4000 + or sim memory region 0x800000,0x4000 + If CPU is non-null, use its option table list, otherwise use the main one. + *PARGI is where to start looking in ARGV. It is updated to point past + the found option. */ + +static const OPTION * +find_match (SIM_DESC sd, sim_cpu *cpu, char *argv[], int *pargi) +{ + const struct option_list *ol; + const OPTION *opt; + /* most recent option match */ + const OPTION *matching_opt = NULL; + int matching_argi = -1; + + if (cpu) + ol = CPU_OPTIONS (cpu); + else + ol = STATE_OPTIONS (sd); + + /* Skip passed elements specified by *PARGI. */ + argv += *pargi; + + for ( ; ol != NULL; ol = ol->next) + for (opt = ol->options; OPTION_VALID_P (opt); ++opt) + { + int argi = 0; + const char *name = opt->opt.name; + if (name == NULL) + continue; + while (argv [argi] != NULL + && strncmp (name, argv [argi], strlen (argv [argi])) == 0) + { + name = &name [strlen (argv[argi])]; + if (name [0] == '-') + { + /* leading match ...<a-b-c>-d-e-f - continue search */ + name ++; /* skip `-' */ + argi ++; + continue; + } + else if (name [0] == '\0') + { + /* exact match ...<a-b-c-d-e-f> - better than before? */ + if (argi > matching_argi) + { + matching_argi = argi; + matching_opt = opt; + } + break; + } + else + break; + } + } + + *pargi = matching_argi; + return matching_opt; +} + +SIM_RC +sim_args_command (SIM_DESC sd, char *cmd) +{ + /* something to do? */ + if (cmd == NULL) + return SIM_RC_OK; /* FIXME - perhaphs help would be better */ + + if (cmd [0] == '-') + { + /* user specified -<opt> ... form? */ + char **argv = buildargv (cmd); + SIM_RC rc = sim_parse_args (sd, argv); + freeargv (argv); + return rc; + } + else + { + char **argv = buildargv (cmd); + const OPTION *matching_opt = NULL; + int matching_argi; + sim_cpu *cpu; + + if (argv [0] == NULL) + return SIM_RC_OK; /* FIXME - perhaphs help would be better */ + + /* First check for a cpu selector. */ + { + char *cpu_name = xstrdup (argv[0]); + char *hyphen = strchr (cpu_name, '-'); + if (hyphen) + *hyphen = 0; + cpu = sim_cpu_lookup (sd, cpu_name); + if (cpu) + { + /* If <cpuname>-<command>, point argv[0] at <command>. */ + if (hyphen) + { + matching_argi = 0; + argv[0] += hyphen - cpu_name + 1; + } + else + matching_argi = 1; + matching_opt = find_match (sd, cpu, argv, &matching_argi); + /* If hyphen found restore argv[0]. */ + if (hyphen) + argv[0] -= hyphen - cpu_name + 1; + } + free (cpu_name); + } + + /* If that failed, try the main table. */ + if (matching_opt == NULL) + { + matching_argi = 0; + matching_opt = find_match (sd, NULL, argv, &matching_argi); + } + + if (matching_opt != NULL) + { + switch (matching_opt->opt.has_arg) + { + case no_argument: + if (argv [matching_argi + 1] == NULL) + matching_opt->handler (sd, cpu, matching_opt->opt.val, + NULL, 1/*is_command*/); + else + sim_io_eprintf (sd, "Command `%s' takes no arguments\n", + matching_opt->opt.name); + break; + case optional_argument: + if (argv [matching_argi + 1] == NULL) + matching_opt->handler (sd, cpu, matching_opt->opt.val, + NULL, 1/*is_command*/); + else if (argv [matching_argi + 2] == NULL) + matching_opt->handler (sd, cpu, matching_opt->opt.val, + argv [matching_argi + 1], 1/*is_command*/); + else + sim_io_eprintf (sd, "Command `%s' requires no more than one argument\n", + matching_opt->opt.name); + break; + case required_argument: + if (argv [matching_argi + 1] == NULL) + sim_io_eprintf (sd, "Command `%s' requires an argument\n", + matching_opt->opt.name); + else if (argv [matching_argi + 2] == NULL) + matching_opt->handler (sd, cpu, matching_opt->opt.val, + argv [matching_argi + 1], 1/*is_command*/); + else + sim_io_eprintf (sd, "Command `%s' requires only one argument\n", + matching_opt->opt.name); + } + freeargv (argv); + return SIM_RC_OK; + } + + freeargv (argv); + } + + /* didn't find anything that remotly matched */ + return SIM_RC_FAIL; +} diff --git a/sim/common/sim-options.h b/sim/common/sim-options.h new file mode 100644 index 0000000..78cad56 --- /dev/null +++ b/sim/common/sim-options.h @@ -0,0 +1,149 @@ +/* Header file for simulator argument handling. + Copyright (C) 1997, 1998 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef SIM_OPTIONS_H +#define SIM_OPTIONS_H + +#include "getopt.h" + +/* ARGV option support. + + Options for the standalone simulator are parsed by sim_open since + sim_open handles the large majority of them and it also parses the + options when invoked by gdb [or any external program]. + + For OPTION_HANDLER: arg#2 is the processor to apply to option to + (all if NULL); arg#3 is the option index; arg#4 is the option's + argument, NULL if optional and missing; arg#5 is nonzero if a + command is being interpreted. */ + +typedef SIM_RC (OPTION_HANDLER) PARAMS ((SIM_DESC, sim_cpu *, int, char *, int)); + +/* Declare option handlers with a macro so it's usable on k&r systems. */ +#define DECLARE_OPTION_HANDLER(fn) SIM_RC fn PARAMS ((SIM_DESC, sim_cpu *, int, char *, int)) + +typedef struct { + + /* The long option information. */ + + struct option opt; + + /* The short option with the same meaning ('\0' if none). + + For short options, when OPT.VAL is non-zero, it, instead of + SHORTOPT is passed to HANDLER. + + For example, for the below: + + { {"dc", no_argument, NULL, OPTION_VALUE}, + 'd', NULL, "<<description>>", HANDLER}, + { {NULL, no_argument, NULL, OPTION_VALUE}, + 'e', NULL, "<<description>>", HANDLER}, + + the options --dc, -d and -e all result in OPTION_VALUE being + passed into HANDLER. */ + + char shortopt; + + /* The name of the argument (NULL if none). */ + + const char *arg; + + /* The documentation string. + + If DOC is NULL, this option name is listed as a synonym for the + previous option. + + If DOC and DOC_NAME are the empty string (i.e. ""), this option + is not listed in usage and help messages. + + For example, given the aliased options --dc, --dp and -d, then: + + { {"dc", no_argument, NULL, OPTION_DC}, + 'd', NULL, "<<description>>", HANDLER}, + { {"dp", no_argument, NULL, OPTION_DP}, + '\0', NULL, NULL, HANDLER}, + + will list ``-d, --dc, --dp <<description>>'' */ + + const char *doc; + + /* A function to process the option. */ + + OPTION_HANDLER *handler; + + /* The documentation name. Used when generating usage and help + messages. + + If DOC and DOC_NAME are the empty string (i.e. ""), this option + is not listed in usage and help messages. + + If DOC_NAME is a non-empty string then it, insted of OPT.NAME, is + listed as the name of the option in usage and help messages. + + For example, given the options --set-pc and --set-sp, then: + + { {"set-pc", no_argument, NULL, OPTION_SET_PC}, + '\0', NULL, "<<description>>", HANDLER, "--set-REGNAME" }, + { {"set-sp", no_argument, NULL, OPTION_SET_SP}, + '\0', NULL, "", HANDLER, "" }, + + will list ``--set-REGNAME <<description>>". */ + + const char *doc_name; + +} OPTION; + +/* All options that don't have a short form equivalent begin with this for + `val'. 130 isn't special, just some non-ASCII value to begin at. + Modules needn't worry about collisions here, the code dynamically assigned + the actual numbers used and then passes the original value to the option + handler. */ +#define OPTION_START 130 + +/* Identify valid option in the table */ +#define OPTION_VALID_P(O) ((O)->opt.name != NULL || (O)->shortopt != '\0') + +/* List of options added by various modules. */ +typedef struct option_list { + struct option_list *next; + const OPTION *options; +} OPTION_LIST; + +/* Add a set of options to the simulator. + CPU is the cpu the options apply to or NULL for all cpus. + TABLE is an array of OPTIONS terminated by a NULL `opt.name' entry. */ +SIM_RC sim_add_option_table PARAMS ((SIM_DESC sd, sim_cpu *cpu, const OPTION *table)); + +/* Install handler for the standard options. */ +MODULE_INSTALL_FN standard_install; + +/* Called by sim_open to parse the arguments. */ +SIM_RC sim_parse_args PARAMS ((SIM_DESC sd, char **argv)); + +/* Print help messages for the options. IS_COMMAND is non-zero when + this function is called from the command line interpreter. */ +void sim_print_help PARAMS ((SIM_DESC sd, int is_command)); + +/* Try to parse the command as if it is an option, Only fail when + totally unsuccessful */ +SIM_RC sim_args_command PARAMS ((SIM_DESC sd, char *cmd)); + +#endif /* SIM_OPTIONS_H */ diff --git a/sim/common/sim-profile.c b/sim/common/sim-profile.c new file mode 100644 index 0000000..5d075d1 --- /dev/null +++ b/sim/common/sim-profile.c @@ -0,0 +1,1175 @@ +/* Default profiling support. + Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "sim-main.h" +#include "sim-io.h" +#include "sim-options.h" +#include "sim-assert.h" + +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif + +#ifdef HAVE_STRING_H +#include <string.h> +#else +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#endif + +#define COMMAS(n) sim_add_commas (comma_buf, sizeof (comma_buf), (n)) + +static MODULE_INIT_FN profile_init; +static MODULE_UNINSTALL_FN profile_uninstall; + +static DECLARE_OPTION_HANDLER (profile_option_handler); + +enum { + OPTION_PROFILE_INSN = OPTION_START, + OPTION_PROFILE_MEMORY, + OPTION_PROFILE_MODEL, + OPTION_PROFILE_FILE, + OPTION_PROFILE_CORE, + OPTION_PROFILE_PC, + OPTION_PROFILE_PC_RANGE, + OPTION_PROFILE_PC_GRANULARITY, + OPTION_PROFILE_RANGE, + OPTION_PROFILE_FUNCTION +}; + +static const OPTION profile_options[] = { + { {"profile", optional_argument, NULL, 'p'}, + 'p', "on|off", "Perform profiling", + profile_option_handler }, + { {"profile-insn", optional_argument, NULL, OPTION_PROFILE_INSN}, + '\0', "on|off", "Perform instruction profiling", + profile_option_handler }, + { {"profile-memory", optional_argument, NULL, OPTION_PROFILE_MEMORY}, + '\0', "on|off", "Perform memory profiling", + profile_option_handler }, + { {"profile-core", optional_argument, NULL, OPTION_PROFILE_CORE}, + '\0', "on|off", "Perform CORE profiling", + profile_option_handler }, + { {"profile-model", optional_argument, NULL, OPTION_PROFILE_MODEL}, + '\0', "on|off", "Perform model profiling", + profile_option_handler }, + + { {"profile-file", required_argument, NULL, OPTION_PROFILE_FILE}, + '\0', "FILE NAME", "Specify profile output file", + profile_option_handler }, + + { {"profile-pc", optional_argument, NULL, OPTION_PROFILE_PC}, + '\0', "on|off", "Perform PC profiling", + profile_option_handler }, + { {"profile-pc-frequency", required_argument, NULL, 'F'}, + 'F', "PC PROFILE FREQUENCY", "Specified PC profiling frequency", + profile_option_handler }, + { {"profile-pc-size", required_argument, NULL, 'S'}, + 'S', "PC PROFILE SIZE", "Specify PC profiling size", + profile_option_handler }, + { {"profile-pc-granularity", required_argument, NULL, OPTION_PROFILE_PC_GRANULARITY}, + '\0', "PC PROFILE GRANULARITY", "Specify PC profiling sample coverage", + profile_option_handler }, + { {"profile-pc-range", required_argument, NULL, OPTION_PROFILE_PC_RANGE}, + '\0', "BASE,BOUND", "Specify PC profiling address range", + profile_option_handler }, + +#ifdef SIM_HAVE_ADDR_RANGE + { {"profile-range", required_argument, NULL, OPTION_PROFILE_RANGE}, + '\0', "START,END", "Specify range of addresses for instruction and model profiling", + profile_option_handler }, +#if 0 /*wip*/ + { {"profile-function", required_argument, NULL, OPTION_PROFILE_FUNCTION}, + '\0', "FUNCTION", "Specify function to profile", + profile_option_handler }, +#endif +#endif + + { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL } +}; + +/* Set/reset the profile options indicated in MASK. */ + +static SIM_RC +set_profile_option_mask (SIM_DESC sd, const char *name, int mask, const char *arg) +{ + int profile_nr; + int cpu_nr; + int profile_val = 1; + + if (arg != NULL) + { + if (strcmp (arg, "yes") == 0 + || strcmp (arg, "on") == 0 + || strcmp (arg, "1") == 0) + profile_val = 1; + else if (strcmp (arg, "no") == 0 + || strcmp (arg, "off") == 0 + || strcmp (arg, "0") == 0) + profile_val = 0; + else + { + sim_io_eprintf (sd, "Argument `%s' for `--profile%s' invalid, one of `on', `off', `yes', `no' expected\n", arg, name); + return SIM_RC_FAIL; + } + } + + /* update applicable profile bits */ + for (profile_nr = 0; profile_nr < MAX_PROFILE_VALUES; ++profile_nr) + { + if ((mask & (1 << profile_nr)) == 0) + continue; + +#if 0 /* see sim-trace.c, set flags in STATE here if/when there are any */ + /* Set non-cpu specific values. */ + switch (profile_nr) + { + case ??? : + break; + } +#endif + + /* Set cpu values. */ + for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; cpu_nr++) + { + CPU_PROFILE_FLAGS (STATE_CPU (sd, cpu_nr))[profile_nr] = profile_val; + } + } + + /* Re-compute the cpu profile summary. */ + if (profile_val) + { + for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; cpu_nr++) + CPU_PROFILE_DATA (STATE_CPU (sd, cpu_nr))->profile_any_p = 1; + } + else + { + for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; cpu_nr++) + { + CPU_PROFILE_DATA (STATE_CPU (sd, cpu_nr))->profile_any_p = 0; + for (profile_nr = 0; profile_nr < MAX_PROFILE_VALUES; ++profile_nr) + { + if (CPU_PROFILE_FLAGS (STATE_CPU (sd, cpu_nr))[profile_nr]) + { + CPU_PROFILE_DATA (STATE_CPU (sd, cpu_nr))->profile_any_p = 1; + break; + } + } + } + } + + return SIM_RC_OK; +} + +/* Set one profile option based on its IDX value. + Not static as cgen-scache.c uses it. */ + +SIM_RC +sim_profile_set_option (SIM_DESC sd, const char *name, int idx, const char *arg) +{ + return set_profile_option_mask (sd, name, 1 << idx, arg); +} + +static SIM_RC +profile_option_handler (SIM_DESC sd, + sim_cpu *cpu, + int opt, + char *arg, + int is_command) +{ + int cpu_nr,prof_nr; + + /* FIXME: Need to handle `cpu' arg. */ + + switch (opt) + { + case 'p' : + if (! WITH_PROFILE) + sim_io_eprintf (sd, "Profiling not compiled in, `-p' ignored\n"); + else + return set_profile_option_mask (sd, "profile", PROFILE_USEFUL_MASK, + arg); + break; + + case OPTION_PROFILE_INSN : + if (WITH_PROFILE_INSN_P) + return sim_profile_set_option (sd, "-insn", PROFILE_INSN_IDX, arg); + else + sim_io_eprintf (sd, "Instruction profiling not compiled in, `--profile-insn' ignored\n"); + break; + + case OPTION_PROFILE_MEMORY : + if (WITH_PROFILE_MEMORY_P) + return sim_profile_set_option (sd, "-memory", PROFILE_MEMORY_IDX, arg); + else + sim_io_eprintf (sd, "Memory profiling not compiled in, `--profile-memory' ignored\n"); + break; + + case OPTION_PROFILE_CORE : + if (WITH_PROFILE_CORE_P) + return sim_profile_set_option (sd, "-core", PROFILE_CORE_IDX, arg); + else + sim_io_eprintf (sd, "CORE profiling not compiled in, `--profile-core' ignored\n"); + break; + + case OPTION_PROFILE_MODEL : + if (WITH_PROFILE_MODEL_P) + return sim_profile_set_option (sd, "-model", PROFILE_MODEL_IDX, arg); + else + sim_io_eprintf (sd, "Model profiling not compiled in, `--profile-model' ignored\n"); + break; + + case OPTION_PROFILE_FILE : + /* FIXME: Might want this to apply to pc profiling only, + or have two profile file options. */ + if (! WITH_PROFILE) + sim_io_eprintf (sd, "Profiling not compiled in, `--profile-file' ignored\n"); + else + { + FILE *f = fopen (arg, "w"); + + if (f == NULL) + { + sim_io_eprintf (sd, "Unable to open profile output file `%s'\n", arg); + return SIM_RC_FAIL; + } + for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; ++cpu_nr) + PROFILE_FILE (CPU_PROFILE_DATA (STATE_CPU (sd, cpu_nr))) = f; + } + break; + + case OPTION_PROFILE_PC: + if (WITH_PROFILE_PC_P) + return sim_profile_set_option (sd, "-pc", PROFILE_PC_IDX, arg); + else + sim_io_eprintf (sd, "PC profiling not compiled in, `--profile-pc' ignored\n"); + break; + + case 'F' : + if (WITH_PROFILE_PC_P) + { + /* FIXME: Validate arg. */ + int val = atoi (arg); + for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; ++cpu_nr) + PROFILE_PC_FREQ (CPU_PROFILE_DATA (STATE_CPU (sd, cpu_nr))) = val; + for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; ++cpu_nr) + CPU_PROFILE_FLAGS (STATE_CPU (sd, cpu_nr))[PROFILE_PC_IDX] = 1; + } + else + sim_io_eprintf (sd, "PC profiling not compiled in, `--profile-pc-frequency' ignored\n"); + break; + + case 'S' : + if (WITH_PROFILE_PC_P) + { + /* FIXME: Validate arg. */ + int val = atoi (arg); + for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; ++cpu_nr) + PROFILE_PC_NR_BUCKETS (CPU_PROFILE_DATA (STATE_CPU (sd, cpu_nr))) = val; + for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; ++cpu_nr) + CPU_PROFILE_FLAGS (STATE_CPU (sd, cpu_nr))[PROFILE_PC_IDX] = 1; + } + else + sim_io_eprintf (sd, "PC profiling not compiled in, `--profile-pc-size' ignored\n"); + break; + + case OPTION_PROFILE_PC_GRANULARITY: + if (WITH_PROFILE_PC_P) + { + int shift; + int val = atoi (arg); + /* check that the granularity is a power of two */ + shift = 0; + while (val > (1 << shift)) + { + shift += 1; + } + if (val != (1 << shift)) + { + sim_io_eprintf (sd, "PC profiling granularity not a power of two\n"); + return SIM_RC_FAIL; + } + if (shift == 0) + { + sim_io_eprintf (sd, "PC profiling granularity too small"); + return SIM_RC_FAIL; + } + for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; ++cpu_nr) + PROFILE_PC_SHIFT (CPU_PROFILE_DATA (STATE_CPU (sd, cpu_nr))) = shift; + for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; ++cpu_nr) + CPU_PROFILE_FLAGS (STATE_CPU (sd, cpu_nr))[PROFILE_PC_IDX] = 1; + } + else + sim_io_eprintf (sd, "PC profiling not compiled in, `--profile-pc-granularity' ignored\n"); + break; + + case OPTION_PROFILE_PC_RANGE: + if (WITH_PROFILE_PC_P) + { + /* FIXME: Validate args */ + char *chp = arg; + unsigned long base; + unsigned long bound; + base = strtoul (chp, &chp, 0); + if (*chp != ',') + { + sim_io_eprintf (sd, "--profile-pc-range missing BOUND argument\n"); + return SIM_RC_FAIL; + } + bound = strtoul (chp + 1, NULL, 0); + for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; ++cpu_nr) + { + PROFILE_PC_START (CPU_PROFILE_DATA (STATE_CPU (sd, cpu_nr))) = base; + PROFILE_PC_END (CPU_PROFILE_DATA (STATE_CPU (sd, cpu_nr))) = bound; + } + for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; ++cpu_nr) + CPU_PROFILE_FLAGS (STATE_CPU (sd, cpu_nr))[PROFILE_PC_IDX] = 1; + } + else + sim_io_eprintf (sd, "PC profiling not compiled in, `--profile-pc-range' ignored\n"); + break; + +#ifdef SIM_HAVE_ADDR_RANGE + case OPTION_PROFILE_RANGE : + if (WITH_PROFILE) + { + char *chp = arg; + unsigned long start,end; + start = strtoul (chp, &chp, 0); + if (*chp != ',') + { + sim_io_eprintf (sd, "--profile-range missing END argument\n"); + return SIM_RC_FAIL; + } + end = strtoul (chp + 1, NULL, 0); + /* FIXME: Argument validation. */ + if (cpu != NULL) + sim_addr_range_add (PROFILE_RANGE (CPU_PROFILE_DATA (cpu)), + start, end); + else + for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; ++cpu_nr) + sim_addr_range_add (PROFILE_RANGE (CPU_PROFILE_DATA (STATE_CPU (sd, cpu_nr))), + start, end); + } + else + sim_io_eprintf (sd, "Profiling not compiled in, `--profile-range' ignored\n"); + break; + + case OPTION_PROFILE_FUNCTION : + if (WITH_PROFILE) + { + /*wip: need to compute function range given name*/ + } + else + sim_io_eprintf (sd, "Profiling not compiled in, `--profile-function' ignored\n"); + break; +#endif /* SIM_HAVE_ADDR_RANGE */ + } + + return SIM_RC_OK; +} + +/* PC profiling support */ + +#if WITH_PROFILE_PC_P + +static void +profile_pc_cleanup (SIM_DESC sd) +{ + int n; + for (n = 0; n < MAX_NR_PROCESSORS; n++) + { + sim_cpu *cpu = STATE_CPU (sd, n); + PROFILE_DATA *data = CPU_PROFILE_DATA (cpu); + if (PROFILE_PC_COUNT (data) != NULL) + zfree (PROFILE_PC_COUNT (data)); + PROFILE_PC_COUNT (data) = NULL; + if (PROFILE_PC_EVENT (data) != NULL) + sim_events_deschedule (sd, PROFILE_PC_EVENT (data)); + PROFILE_PC_EVENT (data) = NULL; + } +} + + +static void +profile_pc_uninstall (SIM_DESC sd) +{ + profile_pc_cleanup (sd); +} + +static void +profile_pc_event (SIM_DESC sd, + void *data) +{ + sim_cpu *cpu = (sim_cpu*) data; + PROFILE_DATA *profile = CPU_PROFILE_DATA (cpu); + address_word pc; + unsigned i; + switch (STATE_WATCHPOINTS (sd)->sizeof_pc) + { + case 2: pc = *(unsigned_2*)(STATE_WATCHPOINTS (sd)->pc) ; break; + case 4: pc = *(unsigned_4*)(STATE_WATCHPOINTS (sd)->pc) ; break; + case 8: pc = *(unsigned_8*)(STATE_WATCHPOINTS (sd)->pc) ; break; + default: pc = 0; + } + i = (pc - PROFILE_PC_START (profile)) >> PROFILE_PC_SHIFT (profile); + if (i < PROFILE_PC_NR_BUCKETS (profile)) + PROFILE_PC_COUNT (profile) [i] += 1; /* Overflow? */ + else + PROFILE_PC_COUNT (profile) [PROFILE_PC_NR_BUCKETS (profile)] += 1; + PROFILE_PC_EVENT (profile) = + sim_events_schedule (sd, PROFILE_PC_FREQ (profile), profile_pc_event, cpu); +} + +static SIM_RC +profile_pc_init (SIM_DESC sd) +{ + int n; + profile_pc_cleanup (sd); + for (n = 0; n < MAX_NR_PROCESSORS; n++) + { + sim_cpu *cpu = STATE_CPU (sd, n); + PROFILE_DATA *data = CPU_PROFILE_DATA (cpu); + if (CPU_PROFILE_FLAGS (STATE_CPU (sd, n))[PROFILE_PC_IDX] + && STATE_WATCHPOINTS (sd)->pc != NULL) + { + int bucket_size; + /* fill in the frequency if not specified */ + if (PROFILE_PC_FREQ (data) == 0) + PROFILE_PC_FREQ (data) = 256; + /* fill in the start/end if not specified */ + if (PROFILE_PC_END (data) == 0) + { + PROFILE_PC_START (data) = STATE_TEXT_START (sd); + PROFILE_PC_END (data) = STATE_TEXT_END (sd); + } + /* Compute the number of buckets if not specified. */ + if (PROFILE_PC_NR_BUCKETS (data) == 0) + { + if (PROFILE_PC_BUCKET_SIZE (data) == 0) + PROFILE_PC_NR_BUCKETS (data) = 16; + else + { + if (PROFILE_PC_END (data) == 0) + { + /* nr_buckets = (full-address-range / 2) / (bucket_size / 2) */ + PROFILE_PC_NR_BUCKETS (data) = + ((1 << (STATE_WATCHPOINTS (sd)->sizeof_pc) * (8 - 1)) + / (PROFILE_PC_BUCKET_SIZE (data) / 2)); + } + else + { + PROFILE_PC_NR_BUCKETS (data) = + ((PROFILE_PC_END (data) + - PROFILE_PC_START (data) + + PROFILE_PC_BUCKET_SIZE (data) - 1) + / PROFILE_PC_BUCKET_SIZE (data)); + } + } + } + /* Compute the bucket size if not specified. Ensure that it + is rounded up to the next power of two */ + if (PROFILE_PC_BUCKET_SIZE (data) == 0) + { + if (PROFILE_PC_END (data) == 0) + /* bucket_size = (full-address-range / 2) / (nr_buckets / 2) */ + bucket_size = ((1 << ((STATE_WATCHPOINTS (sd)->sizeof_pc * 8) - 1)) + / (PROFILE_PC_NR_BUCKETS (data) / 2)); + else + bucket_size = ((PROFILE_PC_END (data) + - PROFILE_PC_START (data) + + PROFILE_PC_NR_BUCKETS (data) - 1) + / PROFILE_PC_NR_BUCKETS (data)); + PROFILE_PC_SHIFT (data) = 0; + while (bucket_size < PROFILE_PC_BUCKET_SIZE (data)) + { + PROFILE_PC_SHIFT (data) += 1; + } + } + /* Align the end address with bucket size */ + if (PROFILE_PC_END (data) != 0) + PROFILE_PC_END (data) = (PROFILE_PC_START (data) + + (PROFILE_PC_BUCKET_SIZE (data) + * PROFILE_PC_NR_BUCKETS (data))); + /* create the relevant buffers */ + PROFILE_PC_COUNT (data) = + NZALLOC (unsigned, PROFILE_PC_NR_BUCKETS (data) + 1); + PROFILE_PC_EVENT (data) = + sim_events_schedule (sd, + PROFILE_PC_FREQ (data), + profile_pc_event, + cpu); + } + } + return SIM_RC_OK; +} + +static void +profile_print_pc (sim_cpu *cpu, int verbose) +{ + SIM_DESC sd = CPU_STATE (cpu); + PROFILE_DATA *profile = CPU_PROFILE_DATA (cpu); + char comma_buf[20]; + unsigned max_val; + unsigned total; + unsigned i; + + if (PROFILE_PC_COUNT (profile) == 0) + return; + + sim_io_printf (sd, "Program Counter Statistics:\n\n"); + + /* First pass over data computes various things. */ + max_val = 0; + total = 0; + for (i = 0; i <= PROFILE_PC_NR_BUCKETS (profile); ++i) + { + total += PROFILE_PC_COUNT (profile) [i]; + if (PROFILE_PC_COUNT (profile) [i] > max_val) + max_val = PROFILE_PC_COUNT (profile) [i]; + } + + sim_io_printf (sd, " Total samples: %s\n", + COMMAS (total)); + sim_io_printf (sd, " Granularity: %s bytes per bucket\n", + COMMAS (PROFILE_PC_BUCKET_SIZE (profile))); + sim_io_printf (sd, " Size: %s buckets\n", + COMMAS (PROFILE_PC_NR_BUCKETS (profile))); + sim_io_printf (sd, " Frequency: %s cycles per sample\n", + COMMAS (PROFILE_PC_FREQ (profile))); + + if (PROFILE_PC_END (profile) != 0) + sim_io_printf (sd, " Range: 0x%lx 0x%lx\n", + (long) PROFILE_PC_START (profile), + (long) PROFILE_PC_END (profile)); + + if (verbose && max_val != 0) + { + /* Now we can print the histogram. */ + sim_io_printf (sd, "\n"); + for (i = 0; i <= PROFILE_PC_NR_BUCKETS (profile); ++i) + { + if (PROFILE_PC_COUNT (profile) [i] != 0) + { + sim_io_printf (sd, " "); + if (i == PROFILE_PC_NR_BUCKETS (profile)) + sim_io_printf (sd, "%10s:", "overflow"); + else + sim_io_printf (sd, "0x%08lx:", + (long) (PROFILE_PC_START (profile) + + (i * PROFILE_PC_BUCKET_SIZE (profile)))); + sim_io_printf (sd, " %*s", + max_val < 10000 ? 5 : 10, + COMMAS (PROFILE_PC_COUNT (profile) [i])); + sim_io_printf (sd, " %4.1f", + (PROFILE_PC_COUNT (profile) [i] * 100.0) / total); + sim_io_printf (sd, ": "); + sim_profile_print_bar (sd, PROFILE_HISTOGRAM_WIDTH, + PROFILE_PC_COUNT (profile) [i], + max_val); + sim_io_printf (sd, "\n"); + } + } + } + + /* dump the histogram to the file "gmon.out" using BSD's gprof file + format */ + /* Since a profile data file is in the native format of the host on + which the profile is being, endian issues are not considered in + the code below. */ + /* FIXME: Is this the best place for this code? */ + { + FILE *pf = fopen ("gmon.out", "wb"); + + if (pf == NULL) + sim_io_eprintf (sd, "Failed to open \"gmon.out\" profile file\n"); + else + { + int ok; + /* FIXME: what if the target has a 64 bit PC? */ + unsigned32 header[3]; + unsigned loop; + if (PROFILE_PC_END (profile) != 0) + { + header[0] = PROFILE_PC_START (profile); + header[1] = PROFILE_PC_END (profile); + } + else + { + header[0] = 0; + header[1] = 0; + } + /* size of sample buffer (+ header) */ + header[2] = PROFILE_PC_NR_BUCKETS (profile) * 2 + sizeof (header); + ok = fwrite (&header, sizeof (header), 1, pf); + for (loop = 0; + ok && (loop < PROFILE_PC_NR_BUCKETS (profile)); + loop++) + { + signed16 sample; + if (PROFILE_PC_COUNT (profile) [loop] >= 0xffff) + sample = 0xffff; + else + sample = PROFILE_PC_COUNT (profile) [loop]; + ok = fwrite (&sample, sizeof (sample), 1, pf); + } + if (ok == 0) + sim_io_eprintf (sd, "Failed to write to \"gmon.out\" profile file\n"); + fclose(pf); + } + } + + sim_io_printf (sd, "\n"); +} + +#endif + +/* Summary printing support. */ + +#if WITH_PROFILE_INSN_P + +static SIM_RC +profile_insn_init (SIM_DESC sd) +{ + int c; + + for (c = 0; c < MAX_NR_PROCESSORS; ++c) + { + sim_cpu *cpu = STATE_CPU (sd, c); + + if (CPU_MAX_INSNS (cpu) > 0) + PROFILE_INSN_COUNT (CPU_PROFILE_DATA (cpu)) = NZALLOC (unsigned int, CPU_MAX_INSNS (cpu)); + } + + return SIM_RC_OK; +} + +static void +profile_print_insn (sim_cpu *cpu, int verbose) +{ + unsigned int i, n, total, max_val, max_name_len; + SIM_DESC sd = CPU_STATE (cpu); + PROFILE_DATA *data = CPU_PROFILE_DATA (cpu); + char comma_buf[20]; + + /* If MAX_INSNS not set, insn profiling isn't supported. */ + if (CPU_MAX_INSNS (cpu) == 0) + return; + + sim_io_printf (sd, "Instruction Statistics"); +#ifdef SIM_HAVE_ADDR_RANGE + if (PROFILE_RANGE (data)->ranges) + sim_io_printf (sd, " (for selected address range(s))"); +#endif + sim_io_printf (sd, "\n\n"); + + /* First pass over data computes various things. */ + max_val = 0; + total = 0; + max_name_len = 0; + for (i = 0; i < CPU_MAX_INSNS (cpu); ++i) + { + const char *name = (*CPU_INSN_NAME (cpu)) (cpu, i); + + if (name == NULL) + continue; + total += PROFILE_INSN_COUNT (data) [i]; + if (PROFILE_INSN_COUNT (data) [i] > max_val) + max_val = PROFILE_INSN_COUNT (data) [i]; + n = strlen (name); + if (n > max_name_len) + max_name_len = n; + } + /* set the total insn count, in case client is being lazy */ + if (! PROFILE_TOTAL_INSN_COUNT (data)) + PROFILE_TOTAL_INSN_COUNT (data) = total; + + sim_io_printf (sd, " Total: %s insns\n", COMMAS (total)); + + if (verbose && max_val != 0) + { + /* Now we can print the histogram. */ + sim_io_printf (sd, "\n"); + for (i = 0; i < CPU_MAX_INSNS (cpu); ++i) + { + const char *name = (*CPU_INSN_NAME (cpu)) (cpu, i); + + if (name == NULL) + continue; + if (PROFILE_INSN_COUNT (data) [i] != 0) + { + sim_io_printf (sd, " %*s: %*s: ", + max_name_len, name, + max_val < 10000 ? 5 : 10, + COMMAS (PROFILE_INSN_COUNT (data) [i])); + sim_profile_print_bar (sd, PROFILE_HISTOGRAM_WIDTH, + PROFILE_INSN_COUNT (data) [i], + max_val); + sim_io_printf (sd, "\n"); + } + } + } + + sim_io_printf (sd, "\n"); +} + +#endif + +#if WITH_PROFILE_MEMORY_P + +static void +profile_print_memory (sim_cpu *cpu, int verbose) +{ + unsigned int i, n; + unsigned int total_read, total_write; + unsigned int max_val, max_name_len; + /* FIXME: Need to add smp support. */ + SIM_DESC sd = CPU_STATE (cpu); + PROFILE_DATA *data = CPU_PROFILE_DATA (cpu); + char comma_buf[20]; + + sim_io_printf (sd, "Memory Access Statistics\n\n"); + + /* First pass over data computes various things. */ + max_val = total_read = total_write = max_name_len = 0; + for (i = 0; i < MODE_TARGET_MAX; ++i) + { + total_read += PROFILE_READ_COUNT (data) [i]; + total_write += PROFILE_WRITE_COUNT (data) [i]; + if (PROFILE_READ_COUNT (data) [i] > max_val) + max_val = PROFILE_READ_COUNT (data) [i]; + if (PROFILE_WRITE_COUNT (data) [i] > max_val) + max_val = PROFILE_WRITE_COUNT (data) [i]; + n = strlen (MODE_NAME (i)); + if (n > max_name_len) + max_name_len = n; + } + + /* One could use PROFILE_LABEL_WIDTH here. I chose not to. */ + sim_io_printf (sd, " Total read: %s accesses\n", + COMMAS (total_read)); + sim_io_printf (sd, " Total write: %s accesses\n", + COMMAS (total_write)); + + if (verbose && max_val != 0) + { + /* FIXME: Need to separate instruction fetches from data fetches + as the former swamps the latter. */ + /* Now we can print the histogram. */ + sim_io_printf (sd, "\n"); + for (i = 0; i < MODE_TARGET_MAX; ++i) + { + if (PROFILE_READ_COUNT (data) [i] != 0) + { + sim_io_printf (sd, " %*s read: %*s: ", + max_name_len, MODE_NAME (i), + max_val < 10000 ? 5 : 10, + COMMAS (PROFILE_READ_COUNT (data) [i])); + sim_profile_print_bar (sd, PROFILE_HISTOGRAM_WIDTH, + PROFILE_READ_COUNT (data) [i], + max_val); + sim_io_printf (sd, "\n"); + } + if (PROFILE_WRITE_COUNT (data) [i] != 0) + { + sim_io_printf (sd, " %*s write: %*s: ", + max_name_len, MODE_NAME (i), + max_val < 10000 ? 5 : 10, + COMMAS (PROFILE_WRITE_COUNT (data) [i])); + sim_profile_print_bar (sd, PROFILE_HISTOGRAM_WIDTH, + PROFILE_WRITE_COUNT (data) [i], + max_val); + sim_io_printf (sd, "\n"); + } + } + } + + sim_io_printf (sd, "\n"); +} + +#endif + +#if WITH_PROFILE_CORE_P + +static void +profile_print_core (sim_cpu *cpu, int verbose) +{ + unsigned int total; + unsigned int max_val; + /* FIXME: Need to add smp support. */ + SIM_DESC sd = CPU_STATE (cpu); + PROFILE_DATA *data = CPU_PROFILE_DATA (cpu); + char comma_buf[20]; + + sim_io_printf (sd, "CORE Statistics\n\n"); + + /* First pass over data computes various things. */ + { + unsigned map; + total = 0; + max_val = 0; + for (map = 0; map < nr_maps; map++) + { + total += PROFILE_CORE_COUNT (data) [map]; + if (PROFILE_CORE_COUNT (data) [map] > max_val) + max_val = PROFILE_CORE_COUNT (data) [map]; + } + } + + /* One could use PROFILE_LABEL_WIDTH here. I chose not to. */ + sim_io_printf (sd, " Total: %s accesses\n", + COMMAS (total)); + + if (verbose && max_val != 0) + { + unsigned map; + /* Now we can print the histogram. */ + sim_io_printf (sd, "\n"); + for (map = 0; map < nr_maps; map++) + { + if (PROFILE_CORE_COUNT (data) [map] != 0) + { + sim_io_printf (sd, "%10s:", map_to_str (map)); + sim_io_printf (sd, "%*s: ", + max_val < 10000 ? 5 : 10, + COMMAS (PROFILE_CORE_COUNT (data) [map])); + sim_profile_print_bar (sd, PROFILE_HISTOGRAM_WIDTH, + PROFILE_CORE_COUNT (data) [map], + max_val); + sim_io_printf (sd, "\n"); + } + } + } + + sim_io_printf (sd, "\n"); +} + +#endif + +#if WITH_PROFILE_MODEL_P + +static void +profile_print_model (sim_cpu *cpu, int verbose) +{ + SIM_DESC sd = CPU_STATE (cpu); + PROFILE_DATA *data = CPU_PROFILE_DATA (cpu); + unsigned long cti_stall_cycles = PROFILE_MODEL_CTI_STALL_CYCLES (data); + unsigned long load_stall_cycles = PROFILE_MODEL_LOAD_STALL_CYCLES (data); + unsigned long total_cycles = PROFILE_MODEL_TOTAL_CYCLES (data); + char comma_buf[20]; + + sim_io_printf (sd, "Model %s Timing Information", + MODEL_NAME (CPU_MODEL (cpu))); +#ifdef SIM_HAVE_ADDR_RANGE + if (PROFILE_RANGE (data)->ranges) + sim_io_printf (sd, " (for selected address range(s))"); +#endif + sim_io_printf (sd, "\n\n"); + sim_io_printf (sd, " %-*s %s\n", + PROFILE_LABEL_WIDTH, "Taken branches:", + COMMAS (PROFILE_MODEL_TAKEN_COUNT (data))); + sim_io_printf (sd, " %-*s %s\n", + PROFILE_LABEL_WIDTH, "Untaken branches:", + COMMAS (PROFILE_MODEL_UNTAKEN_COUNT (data))); + sim_io_printf (sd, " %-*s %s\n", + PROFILE_LABEL_WIDTH, "Cycles stalled due to branches:", + COMMAS (cti_stall_cycles)); + sim_io_printf (sd, " %-*s %s\n", + PROFILE_LABEL_WIDTH, "Cycles stalled due to loads:", + COMMAS (load_stall_cycles)); + sim_io_printf (sd, " %-*s %s\n", + PROFILE_LABEL_WIDTH, "Total cycles (*approximate*):", + COMMAS (total_cycles)); + sim_io_printf (sd, "\n"); +} + +#endif + +void +sim_profile_print_bar (SIM_DESC sd, unsigned int width, + unsigned int val, unsigned int max_val) +{ + unsigned int i, count; + + count = ((double) val / (double) max_val) * (double) width; + + for (i = 0; i < count; ++i) + sim_io_printf (sd, "*"); +} + +/* Print the simulator's execution speed for CPU. */ + +static void +profile_print_speed (sim_cpu *cpu) +{ + SIM_DESC sd = CPU_STATE (cpu); + PROFILE_DATA *data = CPU_PROFILE_DATA (cpu); + unsigned long milliseconds = sim_events_elapsed_time (sd); + unsigned long total = PROFILE_TOTAL_INSN_COUNT (data); + char comma_buf[20]; + + sim_io_printf (sd, "Simulator Execution Speed\n\n"); + + if (total != 0) + sim_io_printf (sd, " Total instructions: %s\n", COMMAS (total)); + + if (milliseconds < 1000) + sim_io_printf (sd, " Total execution time: < 1 second\n\n"); + else + { + /* The printing of the time rounded to 2 decimal places makes the speed + calculation seem incorrect [even though it is correct]. So round + MILLISECONDS first. This can marginally affect the result, but it's + better that the user not perceive there's a math error. */ + double secs = (double) milliseconds / 1000; + secs = ((double) (unsigned long) (secs * 100 + .5)) / 100; + sim_io_printf (sd, " Total execution time: %.2f seconds\n", secs); + /* Don't confuse things with data that isn't useful. + If we ran for less than 2 seconds, only use the data if we + executed more than 100,000 insns. */ + if (secs >= 2 || total >= 100000) + sim_io_printf (sd, " Simulator speed: %s insns/second\n\n", + COMMAS ((unsigned long) ((double) total / secs))); + } +} + +/* Print selected address ranges. */ + +static void +profile_print_addr_ranges (sim_cpu *cpu) +{ + ADDR_SUBRANGE *asr = PROFILE_RANGE (CPU_PROFILE_DATA (cpu))->ranges; + SIM_DESC sd = CPU_STATE (cpu); + + if (asr) + { + sim_io_printf (sd, "Selected address ranges\n\n"); + while (asr != NULL) + { + sim_io_printf (sd, " 0x%lx - 0x%lx\n", + (long) asr->start, (long) asr->end); + asr = asr->next; + } + sim_io_printf (sd, "\n"); + } +} + +/* Top level function to print all summary profile information. + It is [currently] intended that all such data is printed by this function. + I'd rather keep it all in one place for now. To that end, MISC_CPU and + MISC are callbacks used to print any miscellaneous data. + + One might want to add a user option that allows printing by type or by cpu + (i.e. print all insn data for each cpu first, or print data cpu by cpu). + This may be a case of featuritis so it's currently left out. + + Note that results are indented two spaces to distinguish them from + section titles. */ + +static void +profile_info (SIM_DESC sd, int verbose) +{ + int i,c; + int print_title_p = 0; + + /* Only print the title if some data has been collected. */ + /* ??? Why don't we just exit if no data collected? */ + /* FIXME: If the number of processors can be selected on the command line, + then MAX_NR_PROCESSORS will need to take an argument of `sd'. */ + + for (c = 0; c < MAX_NR_PROCESSORS; ++c) + { + sim_cpu *cpu = STATE_CPU (sd, c); + PROFILE_DATA *data = CPU_PROFILE_DATA (cpu); + + for (i = 0; i < MAX_PROFILE_VALUES; ++i) + if (PROFILE_FLAGS (data) [i]) + print_title_p = 1; + /* One could break out early if print_title_p is set. */ + } + if (print_title_p) + sim_io_printf (sd, "Summary profiling results:\n\n"); + + /* Loop, cpu by cpu, printing results. */ + + for (c = 0; c < MAX_NR_PROCESSORS; ++c) + { + sim_cpu *cpu = STATE_CPU (sd, c); + PROFILE_DATA *data = CPU_PROFILE_DATA (cpu); + + if (MAX_NR_PROCESSORS > 1 + && (0 +#if WITH_PROFILE_INSN_P + || PROFILE_FLAGS (data) [PROFILE_INSN_IDX] +#endif +#if WITH_PROFILE_MEMORY_P + || PROFILE_FLAGS (data) [PROFILE_MEMORY_IDX] +#endif +#if WITH_PROFILE_CORE_P + || PROFILE_FLAGS (data) [PROFILE_CORE_IDX] +#endif +#if WITH_PROFILE_MODEL_P + || PROFILE_FLAGS (data) [PROFILE_MODEL_IDX] +#endif +#if WITH_PROFILE_SCACHE_P && WITH_SCACHE + || PROFILE_FLAGS (data) [PROFILE_SCACHE_IDX] +#endif +#if WITH_PROFILE_PC_P + || PROFILE_FLAGS (data) [PROFILE_PC_IDX] +#endif + )) + { + sim_io_printf (sd, "CPU %d\n\n", c); + } + +#ifdef SIM_HAVE_ADDR_RANGE + if (print_title_p + && (PROFILE_INSN_P (cpu) + || PROFILE_MODEL_P (cpu))) + profile_print_addr_ranges (cpu); +#endif + +#if WITH_PROFILE_INSN_P + if (PROFILE_FLAGS (data) [PROFILE_INSN_IDX]) + profile_print_insn (cpu, verbose); +#endif + +#if WITH_PROFILE_MEMORY_P + if (PROFILE_FLAGS (data) [PROFILE_MEMORY_IDX]) + profile_print_memory (cpu, verbose); +#endif + +#if WITH_PROFILE_CORE_P + if (PROFILE_FLAGS (data) [PROFILE_CORE_IDX]) + profile_print_core (cpu, verbose); +#endif + +#if WITH_PROFILE_MODEL_P + if (PROFILE_FLAGS (data) [PROFILE_MODEL_IDX]) + profile_print_model (cpu, verbose); +#endif + +#if WITH_PROFILE_SCACHE_P && WITH_SCACHE + if (PROFILE_FLAGS (data) [PROFILE_SCACHE_IDX]) + scache_print_profile (cpu, verbose); +#endif + +#if WITH_PROFILE_PC_P + if (PROFILE_FLAGS (data) [PROFILE_PC_IDX]) + profile_print_pc (cpu, verbose); +#endif + + /* Print cpu-specific data before the execution speed. */ + if (PROFILE_INFO_CPU_CALLBACK (data) != NULL) + PROFILE_INFO_CPU_CALLBACK (data) (cpu, verbose); + + /* Always try to print execution time and speed. */ + if (verbose + || PROFILE_FLAGS (data) [PROFILE_INSN_IDX]) + profile_print_speed (cpu); + } + + /* Finally print non-cpu specific miscellaneous data. */ + if (STATE_PROFILE_INFO_CALLBACK (sd)) + STATE_PROFILE_INFO_CALLBACK (sd) (sd, verbose); + +} + +/* Install profiling support in the simulator. */ + +SIM_RC +profile_install (SIM_DESC sd) +{ + int i; + + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + sim_add_option_table (sd, NULL, profile_options); + for (i = 0; i < MAX_NR_PROCESSORS; ++i) + memset (CPU_PROFILE_DATA (STATE_CPU (sd, i)), 0, + sizeof (* CPU_PROFILE_DATA (STATE_CPU (sd, i)))); +#if WITH_PROFILE_INSN_P + sim_module_add_init_fn (sd, profile_insn_init); +#endif +#if WITH_PROFILE_PC_P + sim_module_add_uninstall_fn (sd, profile_pc_uninstall); + sim_module_add_init_fn (sd, profile_pc_init); +#endif + sim_module_add_init_fn (sd, profile_init); + sim_module_add_uninstall_fn (sd, profile_uninstall); + sim_module_add_info_fn (sd, profile_info); + return SIM_RC_OK; +} + +static SIM_RC +profile_init (SIM_DESC sd) +{ +#ifdef SIM_HAVE_ADDR_RANGE + /* Check if a range has been specified without specifying what to + collect. */ + { + int i; + + for (i = 0; i < MAX_NR_PROCESSORS; ++i) + { + sim_cpu *cpu = STATE_CPU (sd, i); + + if (ADDR_RANGE_RANGES (PROFILE_RANGE (CPU_PROFILE_DATA (cpu))) + && ! (PROFILE_INSN_P (cpu) + || PROFILE_MODEL_P (cpu))) + { + sim_io_eprintf_cpu (cpu, "Profiling address range specified without --profile-insn or --profile-model.\n"); + sim_io_eprintf_cpu (cpu, "Address range ignored.\n"); + sim_addr_range_delete (PROFILE_RANGE (CPU_PROFILE_DATA (cpu)), + 0, ~ (address_word) 0); + } + } + } +#endif + + return SIM_RC_OK; +} + +static void +profile_uninstall (SIM_DESC sd) +{ + int i,j; + + for (i = 0; i < MAX_NR_PROCESSORS; ++i) + { + sim_cpu *cpu = STATE_CPU (sd, i); + PROFILE_DATA *data = CPU_PROFILE_DATA (cpu); + + if (PROFILE_FILE (data) != NULL) + { + /* If output from different cpus is going to the same file, + avoid closing the file twice. */ + for (j = 0; j < i; ++j) + if (PROFILE_FILE (CPU_PROFILE_DATA (STATE_CPU (sd, j))) + == PROFILE_FILE (data)) + break; + if (i == j) + fclose (PROFILE_FILE (data)); + } + + if (PROFILE_INSN_COUNT (data) != NULL) + zfree (PROFILE_INSN_COUNT (data)); + } +} diff --git a/sim/common/sim-profile.h b/sim/common/sim-profile.h new file mode 100644 index 0000000..8f8d95f --- /dev/null +++ b/sim/common/sim-profile.h @@ -0,0 +1,289 @@ +/* Profile header for simulators using common framework. + Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef SIM_PROFILE_H +#define SIM_PROFILE_H + +#ifndef WITH_PROFILE +Error, WITH_PROFILE not defined. +#endif + +/* Standard profilable entities. */ + +enum { + /* Profile insn usage. */ + PROFILE_INSN_IDX = 1, + + /* Profile memory usage. */ + PROFILE_MEMORY_IDX, + + /* Profile the cpu model (cycles, etc.). */ + PROFILE_MODEL_IDX, + + /* Profile the simulator's execution cache. */ + PROFILE_SCACHE_IDX, + + /* Profile the PC. */ + PROFILE_PC_IDX, + + /* Profile sim-core.c stuff. */ + /* ??? The difference between this and PROFILE_MEMORY_IDX is ... ? */ + PROFILE_CORE_IDX, + + /* Simulator specific profile bits begin here. */ + PROFILE_NEXT_IDX +}; + +/* Maximum number of profilable entities. */ +#ifndef MAX_PROFILE_VALUES +#define MAX_PROFILE_VALUES 32 +#endif + +/* The -p option only prints useful values. It's easy to type and shouldn't + splat on the screen everything under the sun making nothing easy to + find. */ +#define PROFILE_USEFUL_MASK \ +((1 << PROFILE_INSN_IDX) \ + | (1 << PROFILE_MEMORY_IDX) \ + | (1 << PROFILE_MODEL_IDX) \ + | (1 << PROFILE_CORE_IDX)) + +/* Utility to parse a --profile-<foo> option. */ +/* ??? On the one hand all calls could be confined to sim-profile.c, but + on the other hand keeping a module's profiling option with the module's + source is cleaner. */ + +SIM_RC sim_profile_set_option (SIM_DESC sd_, const char *name_, int idx_, + const char *arg_); + +/* Masks so WITH_PROFILE can have symbolic values. + The case choice here is on purpose. The lowercase parts are args to + --with-profile. */ +#define PROFILE_insn (1 << PROFILE_INSN_IDX) +#define PROFILE_memory (1 << PROFILE_MEMORY_IDX) +#define PROFILE_model (1 << PROFILE_MODEL_IDX) +#define PROFILE_scache (1 << PROFILE_SCACHE_IDX) +#define PROFILE_pc (1 << PROFILE_PC_IDX) +#define PROFILE_core (1 << PROFILE_CORE_IDX) + +/* Preprocessor macros to simplify tests of WITH_PROFILE. */ +#define WITH_PROFILE_INSN_P (WITH_PROFILE & PROFILE_insn) +#define WITH_PROFILE_MEMORY_P (WITH_PROFILE & PROFILE_memory) +#define WITH_PROFILE_MODEL_P (WITH_PROFILE & PROFILE_model) +#define WITH_PROFILE_SCACHE_P (WITH_PROFILE & PROFILE_scache) +#define WITH_PROFILE_PC_P (WITH_PROFILE & PROFILE_pc) +#define WITH_PROFILE_CORE_P (WITH_PROFILE & PROFILE_core) + +/* If MAX_TARGET_MODES isn't defined, we can't do memory profiling. + ??? It is intended that this is a temporary occurence. Normally + MAX_TARGET_MODES is defined. */ +#ifndef MAX_TARGET_MODES +#undef WITH_PROFILE_MEMORY_P +#define WITH_PROFILE_MEMORY_P 0 +#endif + +/* Only build MODEL code when the target simulator has support for it */ +#ifndef SIM_HAVE_MODEL +#undef WITH_PROFILE_MODEL_P +#define WITH_PROFILE_MODEL_P 0 +#endif + +/* Profiling install handler. */ +MODULE_INSTALL_FN profile_install; + +/* Output format macros. */ +#ifndef PROFILE_HISTOGRAM_WIDTH +#define PROFILE_HISTOGRAM_WIDTH 40 +#endif +#ifndef PROFILE_LABEL_WIDTH +#define PROFILE_LABEL_WIDTH 32 +#endif + +/* Callbacks for internal profile_info. + The callbacks may be NULL meaning there isn't one. + Note that results are indented two spaces to distinguish them from + section titles. + If non-NULL, PROFILE_CALLBACK is called to print extra non-cpu related data. + If non-NULL, PROFILE_CPU_CALLBACK is called to print extra cpu related data. + */ + +typedef void (PROFILE_INFO_CALLBACK_FN) (SIM_DESC, int); +struct _sim_cpu; /* forward reference */ +typedef void (PROFILE_INFO_CPU_CALLBACK_FN) (struct _sim_cpu *cpu, int verbose); + + +/* Struct containing most profiling data. + It doesn't contain all profiling data because for example scache data + is kept with the rest of scache support. */ + +typedef struct { + /* Global summary of all the current profiling options. */ + char profile_any_p; + + /* Boolean array of specified profiling flags. */ + char profile_flags[MAX_PROFILE_VALUES]; +#define PROFILE_FLAGS(p) ((p)->profile_flags) + + /* The total insn count is tracked separately. + It is always computed, regardless of insn profiling. */ + unsigned long total_insn_count; +#define PROFILE_TOTAL_INSN_COUNT(p) ((p)->total_insn_count) + +#if WITH_PROFILE_INSN_P + unsigned int *insn_count; +#define PROFILE_INSN_COUNT(p) ((p)->insn_count) +#endif + +#if WITH_PROFILE_MEMORY_P + unsigned int read_count[MAX_TARGET_MODES]; +#define PROFILE_READ_COUNT(p) ((p)->read_count) + unsigned int write_count[MAX_TARGET_MODES]; +#define PROFILE_WRITE_COUNT(p) ((p)->write_count) +#endif + +#if WITH_PROFILE_CORE_P + /* Count read/write/exec accesses separatly. */ + unsigned int core_count[nr_maps]; +#define PROFILE_CORE_COUNT(p) ((p)->core_count) +#endif + +#if WITH_PROFILE_MODEL_P + /* ??? Quick hack until more elaborate scheme is finished. */ + /* Total cycle count, including stalls. */ + unsigned long total_cycles; +#define PROFILE_MODEL_TOTAL_CYCLES(p) ((p)->total_cycles) + /* Stalls due to branches. */ + unsigned long cti_stall_cycles; +#define PROFILE_MODEL_CTI_STALL_CYCLES(p) ((p)->cti_stall_cycles) + unsigned long load_stall_cycles; +#define PROFILE_MODEL_LOAD_STALL_CYCLES(p) ((p)->load_stall_cycles) + /* Number of cycles the current instruction took. */ + unsigned long cur_insn_cycles; +#define PROFILE_MODEL_CUR_INSN_CYCLES(p) ((p)->cur_insn_cycles) + + /* Taken and not-taken branches (and other cti's). */ + unsigned long taken_count, untaken_count; +#define PROFILE_MODEL_TAKEN_COUNT(p) ((p)->taken_count) +#define PROFILE_MODEL_UNTAKEN_COUNT(p) ((p)->untaken_count) +#endif + +#if WITH_PROFILE_PC_P + /* PC profiling attempts to determine function usage by sampling the PC + every so many instructions. */ + unsigned int profile_pc_freq; +#define PROFILE_PC_FREQ(p) ((p)->profile_pc_freq) + unsigned int profile_pc_nr_buckets; +#define PROFILE_PC_NR_BUCKETS(p) ((p)->profile_pc_nr_buckets) + address_word profile_pc_start; +#define PROFILE_PC_START(p) ((p)->profile_pc_start) + address_word profile_pc_end; +#define PROFILE_PC_END(p) ((p)->profile_pc_end) + unsigned profile_pc_shift; +#define PROFILE_PC_SHIFT(p) ((p)->profile_pc_shift) +#define PROFILE_PC_BUCKET_SIZE(p) (PROFILE_PC_SHIFT (p) ? (1 << PROFILE_PC_SHIFT (p)) : 0) + unsigned *profile_pc_count; +#define PROFILE_PC_COUNT(p) ((p)->profile_pc_count) + sim_event *profile_pc_event; +#define PROFILE_PC_EVENT(p) ((p)->profile_pc_event) +#endif + + /* Profile output goes to this or stderr if NULL. + We can't store `stderr' here as stderr goes through a callback. */ + FILE *profile_file; +#define PROFILE_FILE(p) ((p)->profile_file) + + /* When reporting a profile summary, hook to include per-processor + target specific profile information */ + PROFILE_INFO_CPU_CALLBACK_FN *info_cpu_callback; +#define PROFILE_INFO_CPU_CALLBACK(p) ((p)->info_cpu_callback) + + /* When reporting a profile summary, hook to include common target + specific profile information */ + PROFILE_INFO_CALLBACK_FN *info_callback; +#define STATE_PROFILE_INFO_CALLBACK(sd) \ +(CPU_PROFILE_DATA (STATE_CPU (sd, 0))->info_callback) + + /* Profile range. + ??? Not all cpu's support this. */ + ADDR_RANGE range; +#define PROFILE_RANGE(p) (& (p)->range) +} PROFILE_DATA; + +/* Predicates. */ + +#define CPU_PROFILE_FLAGS(cpu) PROFILE_FLAGS (CPU_PROFILE_DATA (cpu)) + +/* Return non-zero if tracing of IDX is enabled for CPU. */ +#define PROFILE_P(cpu,idx) \ +((WITH_PROFILE & (1 << (idx))) != 0 \ + && CPU_PROFILE_FLAGS (cpu)[idx] != 0) + +/* Non-zero if --profile-<xxxx> was specified for CPU. */ +#define PROFILE_ANY_P(cpu) ((WITH_PROFILE) && (CPU_PROFILE_DATA (cpu)->profile_any_p)) +#define PROFILE_INSN_P(cpu) PROFILE_P (cpu, PROFILE_INSN_IDX) +#define PROFILE_MEMORY_P(cpu) PROFILE_P (cpu, PROFILE_MEMORY_IDX) +#define PROFILE_MODEL_P(cpu) PROFILE_P (cpu, PROFILE_MODEL_IDX) +#define PROFILE_SCACHE_P(cpu) PROFILE_P (cpu, PROFILE_SCACHE_IDX) +#define PROFILE_PC_P(cpu) PROFILE_P (cpu, PROFILE_PC_IDX) +#define PROFILE_CORE_P(cpu) PROFILE_P (cpu, PROFILE_CORE_IDX) + +/* Usage macros. */ + +#if WITH_PROFILE_INSN_P +#define PROFILE_COUNT_INSN(cpu, pc, insn_num) \ +do { \ + if (PROFILE_INSN_P (cpu)) \ + ++ PROFILE_INSN_COUNT (CPU_PROFILE_DATA (cpu)) [insn_num]; \ +} while (0) +#else +#define PROFILE_COUNT_INSN(cpu, pc, insn_num) +#endif /* ! insn */ + +#if WITH_PROFILE_MEMORY_P +#define PROFILE_COUNT_READ(cpu, addr, mode_num) \ +do { \ + if (PROFILE_MEMORY_P (cpu)) \ + ++ PROFILE_READ_COUNT (CPU_PROFILE_DATA (cpu)) [mode_num]; \ +} while (0) +#define PROFILE_COUNT_WRITE(cpu, addr, mode_num) \ +do { \ + if (PROFILE_MEMORY_P (cpu)) \ + ++ PROFILE_WRITE_COUNT (CPU_PROFILE_DATA (cpu)) [mode_num]; \ +} while (0) +#else +#define PROFILE_COUNT_READ(cpu, addr, mode_num) +#define PROFILE_COUNT_WRITE(cpu, addr, mode_num) +#endif /* ! memory */ + +#if WITH_PROFILE_CORE_P +#define PROFILE_COUNT_CORE(cpu, addr, size, map) \ +do { \ + if (PROFILE_CORE_P (cpu)) \ + PROFILE_CORE_COUNT (CPU_PROFILE_DATA (cpu)) [map] += 1; \ +} while (0) +#else +#define PROFILE_COUNT_CORE(cpu, addr, size, map) +#endif /* ! core */ + +/* Misc. utilities. */ + +extern void sim_profile_print_bar (SIM_DESC, unsigned int, unsigned int, unsigned int); + +#endif /* SIM_PROFILE_H */ diff --git a/sim/common/sim-reason.c b/sim/common/sim-reason.c new file mode 100644 index 0000000..b540df3 --- /dev/null +++ b/sim/common/sim-reason.c @@ -0,0 +1,57 @@ +/* Generic simulator stop_reason. + Copyright (C) 1997 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "sim-main.h" +#include "sim-assert.h" + +/* Generic implementation of sim_stop_reason */ + +void +sim_stop_reason (SIM_DESC sd, enum sim_stop *reason, int *sigrc) +{ + sim_engine *engine = NULL; + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + engine = STATE_ENGINE (sd); + *reason = engine->reason; + switch (*reason) + { + case sim_exited : + *sigrc = engine->sigrc; + break; + case sim_signalled : + /* ??? See the comment below case `sim_signalled' in + gdb/remote-sim.c:gdbsim_wait. + ??? Consider the case of the target requesting that it + kill(2) itself with SIGNAL. That SIGNAL, being target + specific, will not correspond to either of the SIM_SIGNAL + enum nor the HOST_SIGNAL. A mapping from TARGET_SIGNAL to + HOST_SIGNAL is needed. */ + *sigrc = sim_signal_to_host (sd, engine->sigrc); + break; + case sim_stopped : + /* The gdb/simulator interface calls for us to return the host + version of the signal which gdb then converts into the + target's version. This is obviously a bit clumsy. */ + *sigrc = sim_signal_to_host (sd, engine->sigrc); + break; + default : + abort (); + } +} diff --git a/sim/common/sim-reg.c b/sim/common/sim-reg.c new file mode 100644 index 0000000..3f3dc41 --- /dev/null +++ b/sim/common/sim-reg.c @@ -0,0 +1,52 @@ +/* Generic register read/write. + Copyright (C) 1998 Free Software Foundation, Inc. + Contributed by Cygnus Solutions. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "sim-main.h" +#include "sim-assert.h" + +/* Generic implementation of sim_fetch_register for simulators using + CPU_REG_FETCH. + The contents of BUF are in target byte order. */ +/* ??? Obviously the interface needs to be extended to handle multiple + cpus. */ + +int +sim_fetch_register (SIM_DESC sd, int rn, unsigned char *buf, int length) +{ + SIM_CPU *cpu = STATE_CPU (sd, 0); + + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + return (* CPU_REG_FETCH (cpu)) (cpu, rn, buf, length); +} + +/* Generic implementation of sim_fetch_register for simulators using + CPU_REG_FETCH. + The contents of BUF are in target byte order. */ +/* ??? Obviously the interface needs to be extended to handle multiple + cpus. */ + +int +sim_store_register (SIM_DESC sd, int rn, unsigned char *buf, int length) +{ + SIM_CPU *cpu = STATE_CPU (sd, 0); + + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + return (* CPU_REG_STORE (cpu)) (cpu, rn, buf, length); +} diff --git a/sim/common/sim-resume.c b/sim/common/sim-resume.c new file mode 100644 index 0000000..09b475e --- /dev/null +++ b/sim/common/sim-resume.c @@ -0,0 +1,85 @@ +/* Generic simulator resume. + Copyright (C) 1997 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "sim-main.h" +#include "sim-assert.h" + +/* Halt the simulator after just one instruction */ + +static void +has_stepped (SIM_DESC sd, + void *data) +{ + ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_stopped, SIM_SIGTRAP); +} + + +/* Generic resume - assumes the existance of sim_engine_run */ + +void +sim_resume (SIM_DESC sd, + int step, + int siggnal) +{ + sim_engine *engine = STATE_ENGINE (sd); + jmp_buf buf; + int jmpval; + + ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + + /* we only want to be single stepping the simulator once */ + if (engine->stepper != NULL) + { + sim_events_deschedule (sd, engine->stepper); + engine->stepper = NULL; + } + if (step) + engine->stepper = sim_events_schedule (sd, 1, has_stepped, sd); + + sim_module_resume (sd); + + /* run/resume the simulator */ + engine->jmpbuf = &buf; + jmpval = setjmp (buf); + if (jmpval == sim_engine_start_jmpval + || jmpval == sim_engine_restart_jmpval) + { + int last_cpu_nr = sim_engine_last_cpu_nr (sd); + int next_cpu_nr = sim_engine_next_cpu_nr (sd); + int nr_cpus = sim_engine_nr_cpus (sd); + + sim_events_preprocess (sd, last_cpu_nr >= nr_cpus, next_cpu_nr >= nr_cpus); + if (next_cpu_nr >= nr_cpus) + next_cpu_nr = 0; + +#ifdef SIM_CPU_EXCEPTION_RESUME + { + sim_cpu* cpu = STATE_CPU (sd, next_cpu_nr); + SIM_CPU_EXCEPTION_RESUME(sd, cpu, siggnal); + } +#endif + + sim_engine_run (sd, next_cpu_nr, nr_cpus, siggnal); + } + engine->jmpbuf = NULL; + + sim_module_suspend (sd); +} diff --git a/sim/common/sim-run.c b/sim/common/sim-run.c new file mode 100644 index 0000000..55f7290 --- /dev/null +++ b/sim/common/sim-run.c @@ -0,0 +1,51 @@ +/* Generic simulator run. + Copyright (C) 1997 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "sim-main.h" +#include "sim-assert.h" + +/* Generic implementation of sim_engine_run that works within the + sim_engine setjmp/longjmp framework. */ + +#define IMEM XCONCAT + +void +sim_engine_run (SIM_DESC sd, + int next_cpu_nr, /* ignore */ + int nr_cpus, /* ignore */ + int siggnal) /* ignore */ +{ + sim_cia cia; + sim_cpu *cpu; + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + cpu = STATE_CPU (sd, 0); + cia = CIA_GET (cpu); + while (1) + { + instruction_word insn = IMEM32 (cia); + cia = idecode_issue (sd, insn, cia); + /* process any events */ + if (sim_events_tick (sd)) + { + CIA_SET (cpu, cia); + sim_events_process (sd); + } + } +} diff --git a/sim/common/sim-signal.c b/sim/common/sim-signal.c new file mode 100644 index 0000000..77709b1 --- /dev/null +++ b/sim/common/sim-signal.c @@ -0,0 +1,96 @@ +/* Simulator signal support + Copyright (C) 1997 Free Software Foundation, Inc. + Contributed by Cygnus Support + +This file is part of the GNU Simulators. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <signal.h> +#include "sim-main.h" + +/* Convert SIM_SIGFOO to SIGFOO. + What to do when the host doesn't have SIGFOO is handled on a case by case + basis. Generally, in the case of passing a value back to gdb, we want gdb + to not think the process has died (so it can be debugged at the point of + failure). */ + +#ifdef _MSC_VER +#ifndef SIGTRAP +#define SIGTRAP 5 +#endif +#ifndef SIGBUS +#define SIGBUS 10 +#endif +#ifndef SIGQUIT +#define SIGQUIT 3 +#endif +#endif + +int +sim_signal_to_host (SIM_DESC sd, SIM_SIGNAL sig) +{ + switch (sig) + { + case SIM_SIGINT : + return SIGINT; + + case SIM_SIGABRT : + return SIGABRT; + + case SIM_SIGILL : +#ifdef SIGILL + return SIGILL; +#else + return SIGSEGV; +#endif + + case SIM_SIGTRAP : + return SIGTRAP; + + case SIM_SIGBUS : +#ifdef SIGBUS + return SIGBUS; +#else + return SIGSEGV; +#endif + + case SIM_SIGSEGV : + return SIGSEGV; + + case SIM_SIGXCPU : +#ifdef SIGXCPU + return SIGXCPU; +#endif + break; + + case SIM_SIGFPE: +#ifdef SIGXCPU + return SIGFPE; +#endif + break; + + case SIM_SIGNONE: + return 0; + break; + } + + sim_io_eprintf (sd, "sim_signal_to_host: unknown signal: %d\n", sig); +#ifdef SIGHUP + return SIGHUP; /* FIXME: Suggestions? */ +#else + return 1; +#endif +} diff --git a/sim/common/sim-signal.h b/sim/common/sim-signal.h new file mode 100644 index 0000000..272e17d --- /dev/null +++ b/sim/common/sim-signal.h @@ -0,0 +1,49 @@ +/* Simulator signal support + Copyright (C) 1997 Free Software Foundation, Inc. + Contributed by Cygnus Support + +This file is part of the GNU Simulators. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef SIM_SIGNAL_H +#define SIM_SIGNAL_H + +/* Signals we use. + This provides a layer between our values and host/target values. */ + +typedef enum { + SIM_SIGNONE = 64, + /* illegal insn */ + SIM_SIGILL, + /* breakpoint */ + SIM_SIGTRAP, + /* misaligned memory access */ + SIM_SIGBUS, + /* tried to read/write memory that's not readable/writable */ + SIM_SIGSEGV, + /* cpu limit exceeded */ + SIM_SIGXCPU, + /* simulation interrupted (sim_stop called) */ + SIM_SIGINT, + /* Floating point or integer divide */ + SIM_SIGFPE, + /* simulation aborted */ + SIM_SIGABRT +} SIM_SIGNAL; + +int sim_signal_to_host (SIM_DESC sd, SIM_SIGNAL); + +#endif /* SIM_SIGNAL_H */ diff --git a/sim/common/sim-stop.c b/sim/common/sim-stop.c new file mode 100644 index 0000000..cde9315 --- /dev/null +++ b/sim/common/sim-stop.c @@ -0,0 +1,43 @@ +/* Generic simulator stop. + Copyright (C) 1997 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "sim-main.h" +#include "sim-assert.h" + +/* Generic implementation of sim_stop. */ + +static void +control_c_simulation (SIM_DESC sd, + void *data) +{ + ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_stopped, SIM_SIGINT); +} + +int +sim_stop (SIM_DESC sd) +{ + ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + sim_events_schedule_after_signal(sd, + 0 /*NOW*/, + control_c_simulation, + sd /*data*/); + return 1; +} diff --git a/sim/common/sim-trace.c b/sim/common/sim-trace.c new file mode 100644 index 0000000..0fa2313 --- /dev/null +++ b/sim/common/sim-trace.c @@ -0,0 +1,1341 @@ +/* Simulator tracing/debugging support. + Copyright (C) 1997, 1998 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "sim-main.h" +#include "sim-io.h" +#include "sim-options.h" +#include "sim-fpu.h" + +#include "bfd.h" +#include "libiberty.h" + +#include "sim-assert.h" + +#ifdef HAVE_STRING_H +#include <string.h> +#else +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif + +#ifndef SIZE_PHASE +#define SIZE_PHASE 8 +#endif + +#ifndef SIZE_LOCATION +#define SIZE_LOCATION 20 +#endif + +#ifndef SIZE_PC +#define SIZE_PC 6 +#endif + +#ifndef SIZE_LINE_NUMBER +#define SIZE_LINE_NUMBER 4 +#endif + +static MODULE_INIT_FN trace_init; +static MODULE_UNINSTALL_FN trace_uninstall; + +static DECLARE_OPTION_HANDLER (trace_option_handler); + +enum { + OPTION_TRACE_INSN = OPTION_START, + OPTION_TRACE_DECODE, + OPTION_TRACE_EXTRACT, + OPTION_TRACE_LINENUM, + OPTION_TRACE_MEMORY, + OPTION_TRACE_MODEL, + OPTION_TRACE_ALU, + OPTION_TRACE_CORE, + OPTION_TRACE_EVENTS, + OPTION_TRACE_FPU, + OPTION_TRACE_BRANCH, + OPTION_TRACE_SEMANTICS, + OPTION_TRACE_RANGE, + OPTION_TRACE_FUNCTION, + OPTION_TRACE_DEBUG, + OPTION_TRACE_FILE +}; + +static const OPTION trace_options[] = +{ + /* This table is organized to group related instructions together. */ + { {"trace", optional_argument, NULL, 't'}, + 't', "on|off", "Trace useful things", + trace_option_handler }, + { {"trace-insn", optional_argument, NULL, OPTION_TRACE_INSN}, + '\0', "on|off", "Perform instruction tracing", + trace_option_handler }, + { {"trace-decode", optional_argument, NULL, OPTION_TRACE_DECODE}, + '\0', "on|off", "Trace instruction decoding", + trace_option_handler }, + { {"trace-extract", optional_argument, NULL, OPTION_TRACE_EXTRACT}, + '\0', "on|off", "Trace instruction extraction", + trace_option_handler }, + { {"trace-linenum", optional_argument, NULL, OPTION_TRACE_LINENUM}, + '\0', "on|off", "Perform line number tracing (implies --trace-insn)", + trace_option_handler }, + { {"trace-memory", optional_argument, NULL, OPTION_TRACE_MEMORY}, + '\0', "on|off", "Trace memory operations", + trace_option_handler }, + { {"trace-alu", optional_argument, NULL, OPTION_TRACE_ALU}, + '\0', "on|off", "Trace ALU operations", + trace_option_handler }, + { {"trace-fpu", optional_argument, NULL, OPTION_TRACE_FPU}, + '\0', "on|off", "Trace FPU operations", + trace_option_handler }, + { {"trace-branch", optional_argument, NULL, OPTION_TRACE_BRANCH}, + '\0', "on|off", "Trace branching", + trace_option_handler }, + { {"trace-semantics", optional_argument, NULL, OPTION_TRACE_SEMANTICS}, + '\0', "on|off", "Perform ALU, FPU, MEMORY, and BRANCH tracing", + trace_option_handler }, + { {"trace-model", optional_argument, NULL, OPTION_TRACE_MODEL}, + '\0', "on|off", "Include model performance data", + trace_option_handler }, + { {"trace-core", optional_argument, NULL, OPTION_TRACE_CORE}, + '\0', "on|off", "Trace core operations", + trace_option_handler }, + { {"trace-events", optional_argument, NULL, OPTION_TRACE_EVENTS}, + '\0', "on|off", "Trace events", + trace_option_handler }, +#ifdef SIM_HAVE_ADDR_RANGE + { {"trace-range", required_argument, NULL, OPTION_TRACE_RANGE}, + '\0', "START,END", "Specify range of addresses for instruction tracing", + trace_option_handler }, +#if 0 /*wip*/ + { {"trace-function", required_argument, NULL, OPTION_TRACE_FUNCTION}, + '\0', "FUNCTION", "Specify function to trace", + trace_option_handler }, +#endif +#endif + { {"trace-debug", optional_argument, NULL, OPTION_TRACE_DEBUG}, + '\0', "on|off", "Add information useful for debugging the simulator to the tracing output", + trace_option_handler }, + { {"trace-file", required_argument, NULL, OPTION_TRACE_FILE}, + '\0', "FILE NAME", "Specify tracing output file", + trace_option_handler }, + { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL } +}; + +/* Set/reset the trace options indicated in MASK. */ + +static SIM_RC +set_trace_option_mask (sd, name, mask, arg) + SIM_DESC sd; + const char *name; + int mask; + const char *arg; +{ + int trace_nr; + int cpu_nr; + int trace_val = 1; + + if (arg != NULL) + { + if (strcmp (arg, "yes") == 0 + || strcmp (arg, "on") == 0 + || strcmp (arg, "1") == 0) + trace_val = 1; + else if (strcmp (arg, "no") == 0 + || strcmp (arg, "off") == 0 + || strcmp (arg, "0") == 0) + trace_val = 0; + else + { + sim_io_eprintf (sd, "Argument `%s' for `--trace%s' invalid, one of `on', `off', `yes', `no' expected\n", arg, name); + return SIM_RC_FAIL; + } + } + + /* update applicable trace bits */ + for (trace_nr = 0; trace_nr < MAX_TRACE_VALUES; ++trace_nr) + { + if ((mask & (1 << trace_nr)) == 0) + continue; + + /* Set non-cpu specific values. */ + switch (trace_nr) + { + case TRACE_EVENTS_IDX: + STATE_EVENTS (sd)->trace = trace_val; + break; + case TRACE_DEBUG_IDX: + STATE_TRACE_FLAGS (sd)[trace_nr] = trace_val; + break; + } + + /* Set cpu values. */ + for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; cpu_nr++) + { + CPU_TRACE_FLAGS (STATE_CPU (sd, cpu_nr))[trace_nr] = trace_val; + } + } + + /* Re-compute the cpu trace summary. */ + if (trace_val) + { + for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; cpu_nr++) + CPU_TRACE_DATA (STATE_CPU (sd, cpu_nr))->trace_any_p = 1; + } + else + { + for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; cpu_nr++) + { + CPU_TRACE_DATA (STATE_CPU (sd, cpu_nr))->trace_any_p = 0; + for (trace_nr = 0; trace_nr < MAX_TRACE_VALUES; ++trace_nr) + { + if (CPU_TRACE_FLAGS (STATE_CPU (sd, cpu_nr))[trace_nr]) + { + CPU_TRACE_DATA (STATE_CPU (sd, cpu_nr))->trace_any_p = 1; + break; + } + } + } + } + + return SIM_RC_OK; +} + +/* Set one trace option based on its IDX value. */ + +static SIM_RC +set_trace_option (sd, name, idx, arg) + SIM_DESC sd; + const char *name; + int idx; + const char *arg; +{ + return set_trace_option_mask (sd, name, 1 << idx, arg); +} + + +static SIM_RC +trace_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt, + char *arg, int is_command) +{ + int n; + int cpu_nr; + + switch (opt) + { + case 't' : + if (! WITH_TRACE) + sim_io_eprintf (sd, "Tracing not compiled in, `-t' ignored\n"); + else + return set_trace_option_mask (sd, "trace", TRACE_USEFUL_MASK, arg); + break; + + case OPTION_TRACE_INSN : + if (WITH_TRACE_INSN_P) + return set_trace_option (sd, "-insn", TRACE_INSN_IDX, arg); + else + sim_io_eprintf (sd, "Instruction tracing not compiled in, `--trace-insn' ignored\n"); + break; + + case OPTION_TRACE_DECODE : + if (WITH_TRACE_DECODE_P) + return set_trace_option (sd, "-decode", TRACE_DECODE_IDX, arg); + else + sim_io_eprintf (sd, "Decode tracing not compiled in, `--trace-decode' ignored\n"); + break; + + case OPTION_TRACE_EXTRACT : + if (WITH_TRACE_EXTRACT_P) + return set_trace_option (sd, "-extract", TRACE_EXTRACT_IDX, arg); + else + sim_io_eprintf (sd, "Extract tracing not compiled in, `--trace-extract' ignored\n"); + break; + + case OPTION_TRACE_LINENUM : + if (WITH_TRACE_LINENUM_P && WITH_TRACE_INSN_P) + { + if (set_trace_option (sd, "-linenum", TRACE_LINENUM_IDX, arg) != SIM_RC_OK + || set_trace_option (sd, "-linenum", TRACE_INSN_IDX, arg) != SIM_RC_OK) + return SIM_RC_FAIL; + } + else + sim_io_eprintf (sd, "Line number or instruction tracing not compiled in, `--trace-linenum' ignored\n"); + break; + + case OPTION_TRACE_MEMORY : + if (WITH_TRACE_MEMORY_P) + return set_trace_option (sd, "-memory", TRACE_MEMORY_IDX, arg); + else + sim_io_eprintf (sd, "Memory tracing not compiled in, `--trace-memory' ignored\n"); + break; + + case OPTION_TRACE_MODEL : + if (WITH_TRACE_MODEL_P) + return set_trace_option (sd, "-model", TRACE_MODEL_IDX, arg); + else + sim_io_eprintf (sd, "Model tracing not compiled in, `--trace-model' ignored\n"); + break; + + case OPTION_TRACE_ALU : + if (WITH_TRACE_ALU_P) + return set_trace_option (sd, "-alu", TRACE_ALU_IDX, arg); + else + sim_io_eprintf (sd, "ALU tracing not compiled in, `--trace-alu' ignored\n"); + break; + + case OPTION_TRACE_CORE : + if (WITH_TRACE_CORE_P) + return set_trace_option (sd, "-core", TRACE_CORE_IDX, arg); + else + sim_io_eprintf (sd, "CORE tracing not compiled in, `--trace-core' ignored\n"); + break; + + case OPTION_TRACE_EVENTS : + if (WITH_TRACE_EVENTS_P) + return set_trace_option (sd, "-events", TRACE_EVENTS_IDX, arg); + else + sim_io_eprintf (sd, "EVENTS tracing not compiled in, `--trace-events' ignored\n"); + break; + + case OPTION_TRACE_FPU : + if (WITH_TRACE_FPU_P) + return set_trace_option (sd, "-fpu", TRACE_FPU_IDX, arg); + else + sim_io_eprintf (sd, "FPU tracing not compiled in, `--trace-fpu' ignored\n"); + break; + + case OPTION_TRACE_BRANCH : + if (WITH_TRACE_BRANCH_P) + return set_trace_option (sd, "-branch", TRACE_BRANCH_IDX, arg); + else + sim_io_eprintf (sd, "Branch tracing not compiled in, `--trace-branch' ignored\n"); + break; + + case OPTION_TRACE_SEMANTICS : + if (WITH_TRACE_ALU_P + && WITH_TRACE_FPU_P + && WITH_TRACE_MEMORY_P + && WITH_TRACE_BRANCH_P) + { + if (set_trace_option (sd, "-semantics", TRACE_ALU_IDX, arg) != SIM_RC_OK + || set_trace_option (sd, "-semantics", TRACE_FPU_IDX, arg) != SIM_RC_OK + || set_trace_option (sd, "-semantics", TRACE_MEMORY_IDX, arg) != SIM_RC_OK + || set_trace_option (sd, "-semantics", TRACE_BRANCH_IDX, arg) != SIM_RC_OK) + return SIM_RC_FAIL; + } + else + sim_io_eprintf (sd, "Alu, fpu, memory, and/or branch tracing not compiled in, `--trace-semantics' ignored\n"); + break; + +#ifdef SIM_HAVE_ADDR_RANGE + case OPTION_TRACE_RANGE : + if (WITH_TRACE) + { + char *chp = arg; + unsigned long start,end; + start = strtoul (chp, &chp, 0); + if (*chp != ',') + { + sim_io_eprintf (sd, "--trace-range missing END argument\n"); + return SIM_RC_FAIL; + } + end = strtoul (chp + 1, NULL, 0); + /* FIXME: Argument validation. */ + if (cpu != NULL) + sim_addr_range_add (TRACE_RANGE (CPU_PROFILE_DATA (cpu)), + start, end); + else + for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; ++cpu_nr) + sim_addr_range_add (TRACE_RANGE (CPU_TRACE_DATA (STATE_CPU (sd, cpu_nr))), + start, end); + } + else + sim_io_eprintf (sd, "Tracing not compiled in, `--trace-range' ignored\n"); + break; + + case OPTION_TRACE_FUNCTION : + if (WITH_TRACE) + { + /*wip: need to compute function range given name*/ + } + else + sim_io_eprintf (sd, "Tracing not compiled in, `--trace-function' ignored\n"); + break; +#endif /* SIM_HAVE_ADDR_RANGE */ + + case OPTION_TRACE_DEBUG : + if (WITH_TRACE_DEBUG_P) + return set_trace_option (sd, "-debug", TRACE_DEBUG_IDX, arg); + else + sim_io_eprintf (sd, "Tracing debug support not compiled in, `--trace-debug' ignored\n"); + break; + + case OPTION_TRACE_FILE : + if (! WITH_TRACE) + sim_io_eprintf (sd, "Tracing not compiled in, `--trace-file' ignored\n"); + else + { + FILE *f = fopen (arg, "w"); + + if (f == NULL) + { + sim_io_eprintf (sd, "Unable to open trace output file `%s'\n", arg); + return SIM_RC_FAIL; + } + for (n = 0; n < MAX_NR_PROCESSORS; ++n) + TRACE_FILE (CPU_TRACE_DATA (STATE_CPU (sd, n))) = f; + TRACE_FILE (STATE_TRACE_DATA (sd)) = f; + } + break; + } + + return SIM_RC_OK; +} + +/* Install tracing support. */ + +SIM_RC +trace_install (SIM_DESC sd) +{ + int i; + + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + + sim_add_option_table (sd, NULL, trace_options); + memset (STATE_TRACE_DATA (sd), 0, sizeof (* STATE_TRACE_DATA (sd))); + for (i = 0; i < MAX_NR_PROCESSORS; ++i) + memset (CPU_TRACE_DATA (STATE_CPU (sd, i)), 0, + sizeof (* CPU_TRACE_DATA (STATE_CPU (sd, i)))); + sim_module_add_init_fn (sd, trace_init); + sim_module_add_uninstall_fn (sd, trace_uninstall); + return SIM_RC_OK; +} + +static SIM_RC +trace_init (SIM_DESC sd) +{ +#ifdef SIM_HAVE_ADDR_RANGE + /* Check if a range has been specified without specifying what to + collect. */ + { + int i; + + for (i = 0; i < MAX_NR_PROCESSORS; ++i) + { + sim_cpu *cpu = STATE_CPU (sd, i); + + if (ADDR_RANGE_RANGES (TRACE_RANGE (CPU_TRACE_DATA (cpu))) + && ! TRACE_INSN_P (cpu)) + { + sim_io_eprintf_cpu (cpu, "Tracing address range specified without --trace-insn.\n"); + sim_io_eprintf_cpu (cpu, "Address range ignored.\n"); + sim_addr_range_delete (TRACE_RANGE (CPU_TRACE_DATA (cpu)), + 0, ~ (address_word) 0); + } + } + } +#endif + + return SIM_RC_OK; +} + +static void +trace_uninstall (SIM_DESC sd) +{ + int i,j; + FILE *sfile = TRACE_FILE (STATE_TRACE_DATA (sd)); + + if (sfile != NULL) + fclose (sfile); + + for (i = 0; i < MAX_NR_PROCESSORS; ++i) + { + FILE *cfile = TRACE_FILE (CPU_TRACE_DATA (STATE_CPU (sd, i))); + if (cfile != NULL && cfile != sfile) + { + /* If output from different cpus is going to the same file, + avoid closing the file twice. */ + for (j = 0; j < i; ++j) + if (TRACE_FILE (CPU_TRACE_DATA (STATE_CPU (sd, j))) == cfile) + break; + if (i == j) + fclose (cfile); + } + } +} + +typedef enum { + trace_fmt_invalid, + trace_fmt_word, + trace_fmt_fp, + trace_fmt_fpu, + trace_fmt_string, + trace_fmt_bool, + trace_fmt_addr, + trace_fmt_instruction_incomplete, +} data_fmt; + +/* compute the nr of trace data units consumed by data */ +static int +save_data_size (TRACE_DATA *data, + long size) +{ + return ((size + sizeof (TRACE_INPUT_DATA (data) [0]) - 1) + / sizeof (TRACE_INPUT_DATA (data) [0])); +} + + +/* Archive DATA into the trace buffer */ +static void +save_data (SIM_DESC sd, + TRACE_DATA *data, + data_fmt fmt, + long size, + void *buf) +{ + int i = TRACE_INPUT_IDX (data); + if (i == sizeof (TRACE_INPUT_FMT (data))) + sim_io_error (sd, "trace buffer overflow"); + TRACE_INPUT_FMT (data) [i] = fmt; + TRACE_INPUT_SIZE (data) [i] = size; + memcpy (&TRACE_INPUT_DATA (data) [i], buf, size); + i += save_data_size (data, size); + TRACE_INPUT_IDX (data) = i; +} + +static void +print_data (SIM_DESC sd, + sim_cpu *cpu, + data_fmt fmt, + long size, + void *data) +{ + switch (fmt) + { + case trace_fmt_instruction_incomplete: + trace_printf (sd, cpu, " (instruction incomplete)"); + break; + case trace_fmt_word: + case trace_fmt_addr: + { + switch (size) + { + case sizeof (unsigned32): + trace_printf (sd, cpu, " 0x%08lx", (long) * (unsigned32*) data); + break; + case sizeof (unsigned64): + trace_printf (sd, cpu, " 0x%08lx%08lx", + (long) ((* (unsigned64*) data) >> 32), + (long) * (unsigned64*) data); + break; + default: + abort (); + } + break; + } + case trace_fmt_bool: + { + SIM_ASSERT (size == sizeof (int)); + trace_printf (sd, cpu, " %-8s", + (* (int*) data) ? "true" : "false"); + break; + } + case trace_fmt_fp: + { + sim_fpu fp; + switch (size) + { + /* FIXME: Assumes sizeof float == 4; sizeof double == 8 */ + case 4: + sim_fpu_32to (&fp, *(unsigned32*)data); + break; + case 8: + sim_fpu_64to (&fp, *(unsigned64*)data); + break; + default: + abort (); + } + trace_printf (sd, cpu, " %8g", sim_fpu_2d (&fp)); + switch (size) + { + case 4: + trace_printf (sd, cpu, " (0x%08lx)", + (long) *(unsigned32*)data); + break; + case 8: + trace_printf (sd, cpu, " (0x%08lx%08lx)", + (long) (*(unsigned64*)data >> 32), + (long) (*(unsigned64*)data)); + break; + default: + abort (); + } + break; + } + case trace_fmt_fpu: + /* FIXME: At present sim_fpu data is stored as a double */ + trace_printf (sd, cpu, " %8g", * (double*) data); + break; + case trace_fmt_string: + trace_printf (sd, cpu, " %-8s", (char*) data); + break; + default: + abort (); + } +} + +static const char * +trace_idx_to_str (int trace_idx) +{ + static char num[8]; + switch (trace_idx) + { + case TRACE_ALU_IDX: return "alu: "; + case TRACE_INSN_IDX: return "insn: "; + case TRACE_DECODE_IDX: return "decode: "; + case TRACE_EXTRACT_IDX: return "extract: "; + case TRACE_MEMORY_IDX: return "memory: "; + case TRACE_CORE_IDX: return "core: "; + case TRACE_EVENTS_IDX: return "events: "; + case TRACE_FPU_IDX: return "fpu: "; + case TRACE_BRANCH_IDX: return "branch: "; + default: + sprintf (num, "?%d?", trace_idx); + return num; + } +} + +static void +trace_results (SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + int last_input) +{ + TRACE_DATA *data = CPU_TRACE_DATA (cpu); + int nr_out; + int i; + + /* cross check trace_idx against TRACE_IDX (data)? */ + + /* prefix */ + trace_printf (sd, cpu, "%s %s", + trace_idx_to_str (TRACE_IDX (data)), + TRACE_PREFIX (data)); + TRACE_IDX (data) = 0; + + for (i = 0, nr_out = 0; + i < TRACE_INPUT_IDX (data); + i += save_data_size (data, TRACE_INPUT_SIZE (data) [i]), nr_out++) + { + if (i == last_input) + { + int pad = (strlen (" 0x") + sizeof (unsigned_word) * 2); + int padding = pad * (3 - nr_out); + if (padding < 0) + padding = 0; + padding += strlen (" ::"); + trace_printf (sd, cpu, "%*s", padding, " ::"); + } + print_data (sd, cpu, + TRACE_INPUT_FMT (data) [i], + TRACE_INPUT_SIZE (data) [i], + &TRACE_INPUT_DATA (data) [i]); + } + trace_printf (sd, cpu, "\n"); +} + +void +trace_prefix (SIM_DESC sd, + sim_cpu *cpu, + sim_cia cia, + address_word pc, + int line_p, + const char *filename, + int linenum, + const char *fmt, + ...) +{ + TRACE_DATA *data = CPU_TRACE_DATA (cpu); + va_list ap; + char *prefix = TRACE_PREFIX (data); + char *chp; + /* FIXME: The TRACE_PREFIX_WIDTH should be determined at build time using + known information about the disassembled instructions. */ +#ifndef TRACE_PREFIX_WIDTH +#define TRACE_PREFIX_WIDTH 48 +#endif + int width = TRACE_PREFIX_WIDTH; + + /* if the previous trace data wasn't flushed, flush it now with a + note indicating that the trace was incomplete. */ + if (TRACE_IDX (data) != 0) + { + int last_input = TRACE_INPUT_IDX (data); + save_data (sd, data, trace_fmt_instruction_incomplete, 1, ""); + trace_results (sd, cpu, TRACE_IDX (data), last_input); + } + TRACE_IDX (data) = 0; + TRACE_INPUT_IDX (data) = 0; + + /* Create the text prefix for this new instruction: */ + if (!line_p) + { + if (filename) + { + sprintf (prefix, "%s:%-*d 0x%.*lx ", + filename, + SIZE_LINE_NUMBER, linenum, + SIZE_PC, (long) pc); + } + else + { + sprintf (prefix, "0x%.*lx ", + SIZE_PC, (long) pc); + /* Shrink the width by the amount that we didn't print. */ + width -= SIZE_LINE_NUMBER + SIZE_PC + 8; + } + chp = strchr (prefix, '\0'); + va_start (ap, fmt); + vsprintf (chp, fmt, ap); + va_end (ap); + } + else + { + char buf[256]; + buf[0] = 0; + if (STATE_TEXT_SECTION (CPU_STATE (cpu)) + && pc >= STATE_TEXT_START (CPU_STATE (cpu)) + && pc < STATE_TEXT_END (CPU_STATE (cpu))) + { + const char *pc_filename = (const char *)0; + const char *pc_function = (const char *)0; + unsigned int pc_linenum = 0; + bfd *abfd; + asymbol **asymbols; + + abfd = STATE_PROG_BFD (CPU_STATE (cpu)); + asymbols = STATE_PROG_SYMS (CPU_STATE (cpu)); + if (asymbols == NULL) + { + long symsize; + long symbol_count; + + symsize = bfd_get_symtab_upper_bound (abfd); + if (symsize < 0) + { + sim_engine_abort (sd, cpu, cia, "could not read symbols"); + } + asymbols = (asymbol **) xmalloc (symsize); + symbol_count = bfd_canonicalize_symtab (abfd, asymbols); + if (symbol_count < 0) + { + sim_engine_abort (sd, cpu, cia, "could not canonicalize symbols"); + } + STATE_PROG_SYMS (CPU_STATE (cpu)) = asymbols; + } + + if (bfd_find_nearest_line (abfd, + STATE_TEXT_SECTION (CPU_STATE (cpu)), + asymbols, + pc - STATE_TEXT_START (CPU_STATE (cpu)), + &pc_filename, &pc_function, &pc_linenum)) + { + char *p = buf; + if (pc_linenum) + { + sprintf (p, "#%-*d ", SIZE_LINE_NUMBER, pc_linenum); + p += strlen (p); + } + else + { + sprintf (p, "%-*s ", SIZE_LINE_NUMBER+1, "---"); + p += SIZE_LINE_NUMBER+2; + } + + if (pc_function) + { + sprintf (p, "%s ", pc_function); + p += strlen (p); + } + else if (pc_filename) + { + char *q = (char *) strrchr (pc_filename, '/'); + sprintf (p, "%s ", (q) ? q+1 : pc_filename); + p += strlen (p); + } + + if (*p == ' ') + *p = '\0'; + } + } + + sprintf (prefix, "0x%.*x %-*.*s ", + SIZE_PC, (unsigned) pc, + SIZE_LOCATION, SIZE_LOCATION, buf); + chp = strchr (prefix, '\0'); + va_start (ap, fmt); + vsprintf (chp, fmt, ap); + va_end (ap); + } + + /* Pad it out to TRACE_PREFIX_WIDTH. */ + chp = strchr (prefix, '\0'); + if (chp - prefix < width) + { + memset (chp, ' ', width - (chp - prefix)); + chp = &prefix [width]; + *chp = '\0'; + } + strcpy (chp, " -"); + + /* check that we've not over flowed the prefix buffer */ + if (strlen (prefix) >= sizeof (TRACE_PREFIX (data))) + abort (); +} + +void +trace_generic (SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + const char *fmt, + ...) +{ + va_list ap; + trace_printf (sd, cpu, "%s %s", + trace_idx_to_str (trace_idx), + TRACE_PREFIX (CPU_TRACE_DATA (cpu))); + va_start (ap, fmt); + trace_vprintf (sd, cpu, fmt, ap); + va_end (ap); + trace_printf (sd, cpu, "\n"); +} + +void +trace_input0 (SIM_DESC sd, + sim_cpu *cpu, + int trace_idx) +{ + TRACE_DATA *data = CPU_TRACE_DATA (cpu); + TRACE_IDX (data) = trace_idx; +} + +void +trace_input_word1 (SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + unsigned_word d0) +{ + TRACE_DATA *data = CPU_TRACE_DATA (cpu); + TRACE_IDX (data) = trace_idx; + save_data (sd, data, trace_fmt_word, sizeof (unsigned_word), &d0); +} + +void +trace_input_word2 (SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + unsigned_word d0, + unsigned_word d1) +{ + TRACE_DATA *data = CPU_TRACE_DATA (cpu); + TRACE_IDX (data) = trace_idx; + save_data (sd, data, trace_fmt_word, sizeof (unsigned_word), &d0); + save_data (sd, data, trace_fmt_word, sizeof (unsigned_word), &d1); +} + +void +trace_input_word3 (SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + unsigned_word d0, + unsigned_word d1, + unsigned_word d2) +{ + TRACE_DATA *data = CPU_TRACE_DATA (cpu); + TRACE_IDX (data) = trace_idx; + save_data (sd, data, trace_fmt_word, sizeof (unsigned_word), &d0); + save_data (sd, data, trace_fmt_word, sizeof (unsigned_word), &d1); + save_data (sd, data, trace_fmt_word, sizeof (unsigned_word), &d2); +} + +void +trace_input_word4 (SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + unsigned_word d0, + unsigned_word d1, + unsigned_word d2, + unsigned_word d3) +{ + TRACE_DATA *data = CPU_TRACE_DATA (cpu); + TRACE_IDX (data) = trace_idx; + save_data (sd, data, trace_fmt_word, sizeof (d0), &d0); + save_data (sd, data, trace_fmt_word, sizeof (d1), &d1); + save_data (sd, data, trace_fmt_word, sizeof (d2), &d2); + save_data (sd, data, trace_fmt_word, sizeof (d3), &d3); +} + +void +trace_input_bool1 (SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + int d0) +{ + TRACE_DATA *data = CPU_TRACE_DATA (cpu); + TRACE_IDX (data) = trace_idx; + save_data (sd, data, trace_fmt_bool, sizeof (d0), &d0); +} + +void +trace_input_addr1 (SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + address_word d0) +{ + TRACE_DATA *data = CPU_TRACE_DATA (cpu); + TRACE_IDX (data) = trace_idx; + save_data (sd, data, trace_fmt_addr, sizeof (d0), &d0); +} + +void +trace_input_fp1 (SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + fp_word f0) +{ + TRACE_DATA *data = CPU_TRACE_DATA (cpu); + TRACE_IDX (data) = trace_idx; + save_data (sd, data, trace_fmt_fp, sizeof (fp_word), &f0); +} + +void +trace_input_fp2 (SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + fp_word f0, + fp_word f1) +{ + TRACE_DATA *data = CPU_TRACE_DATA (cpu); + TRACE_IDX (data) = trace_idx; + save_data (sd, data, trace_fmt_fp, sizeof (fp_word), &f0); + save_data (sd, data, trace_fmt_fp, sizeof (fp_word), &f1); +} + +void +trace_input_fp3 (SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + fp_word f0, + fp_word f1, + fp_word f2) +{ + TRACE_DATA *data = CPU_TRACE_DATA (cpu); + TRACE_IDX (data) = trace_idx; + save_data (sd, data, trace_fmt_fp, sizeof (fp_word), &f0); + save_data (sd, data, trace_fmt_fp, sizeof (fp_word), &f1); + save_data (sd, data, trace_fmt_fp, sizeof (fp_word), &f2); +} + +void +trace_input_fpu1 (SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + sim_fpu *f0) +{ + double d; + TRACE_DATA *data = CPU_TRACE_DATA (cpu); + TRACE_IDX (data) = trace_idx; + d = sim_fpu_2d (f0); + save_data (sd, data, trace_fmt_fp, sizeof (double), &d); +} + +void +trace_input_fpu2 (SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + sim_fpu *f0, + sim_fpu *f1) +{ + double d; + TRACE_DATA *data = CPU_TRACE_DATA (cpu); + TRACE_IDX (data) = trace_idx; + d = sim_fpu_2d (f0); + save_data (sd, data, trace_fmt_fp, sizeof (double), &d); + d = sim_fpu_2d (f1); + save_data (sd, data, trace_fmt_fp, sizeof (double), &d); +} + +void +trace_input_fpu3 (SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + sim_fpu *f0, + sim_fpu *f1, + sim_fpu *f2) +{ + double d; + TRACE_DATA *data = CPU_TRACE_DATA (cpu); + TRACE_IDX (data) = trace_idx; + d = sim_fpu_2d (f0); + save_data (sd, data, trace_fmt_fp, sizeof (double), &d); + d = sim_fpu_2d (f1); + save_data (sd, data, trace_fmt_fp, sizeof (double), &d); + d = sim_fpu_2d (f2); + save_data (sd, data, trace_fmt_fp, sizeof (double), &d); +} + +void +trace_result_word1 (SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + unsigned_word r0) +{ + TRACE_DATA *data = CPU_TRACE_DATA (cpu); + int last_input; + + /* Append any results to the end of the inputs */ + last_input = TRACE_INPUT_IDX (data); + save_data (sd, data, trace_fmt_word, sizeof (unsigned_word), &r0); + + trace_results (sd, cpu, trace_idx, last_input); +} + +void +trace_result0 (SIM_DESC sd, + sim_cpu *cpu, + int trace_idx) +{ + TRACE_DATA *data = CPU_TRACE_DATA (cpu); + int last_input; + + /* Append any results to the end of the inputs */ + last_input = TRACE_INPUT_IDX (data); + + trace_results (sd, cpu, trace_idx, last_input); +} + +void +trace_result_word2 (SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + unsigned_word r0, + unsigned_word r1) +{ + TRACE_DATA *data = CPU_TRACE_DATA (cpu); + int last_input; + + /* Append any results to the end of the inputs */ + last_input = TRACE_INPUT_IDX (data); + save_data (sd, data, trace_fmt_word, sizeof (r0), &r0); + save_data (sd, data, trace_fmt_word, sizeof (r1), &r1); + + trace_results (sd, cpu, trace_idx, last_input); +} + +void +trace_result_word4 (SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + unsigned_word r0, + unsigned_word r1, + unsigned_word r2, + unsigned_word r3) +{ + TRACE_DATA *data = CPU_TRACE_DATA (cpu); + int last_input; + + /* Append any results to the end of the inputs */ + last_input = TRACE_INPUT_IDX (data); + save_data (sd, data, trace_fmt_word, sizeof (r0), &r0); + save_data (sd, data, trace_fmt_word, sizeof (r1), &r1); + save_data (sd, data, trace_fmt_word, sizeof (r2), &r2); + save_data (sd, data, trace_fmt_word, sizeof (r3), &r3); + + trace_results (sd, cpu, trace_idx, last_input); +} + +void +trace_result_bool1 (SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + int r0) +{ + TRACE_DATA *data = CPU_TRACE_DATA (cpu); + int last_input; + + /* Append any results to the end of the inputs */ + last_input = TRACE_INPUT_IDX (data); + save_data (sd, data, trace_fmt_bool, sizeof (r0), &r0); + + trace_results (sd, cpu, trace_idx, last_input); +} + +void +trace_result_addr1 (SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + address_word r0) +{ + TRACE_DATA *data = CPU_TRACE_DATA (cpu); + int last_input; + + /* Append any results to the end of the inputs */ + last_input = TRACE_INPUT_IDX (data); + save_data (sd, data, trace_fmt_addr, sizeof (r0), &r0); + + trace_results (sd, cpu, trace_idx, last_input); +} + +void +trace_result_fp1 (SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + fp_word f0) +{ + TRACE_DATA *data = CPU_TRACE_DATA (cpu); + int last_input; + + /* Append any results to the end of the inputs */ + last_input = TRACE_INPUT_IDX (data); + save_data (sd, data, trace_fmt_fp, sizeof (fp_word), &f0); + + trace_results (sd, cpu, trace_idx, last_input); +} + +void +trace_result_fp2 (SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + fp_word f0, + fp_word f1) +{ + TRACE_DATA *data = CPU_TRACE_DATA (cpu); + int last_input; + + /* Append any results to the end of the inputs */ + last_input = TRACE_INPUT_IDX (data); + save_data (sd, data, trace_fmt_fp, sizeof (f0), &f0); + save_data (sd, data, trace_fmt_fp, sizeof (f1), &f1); + + trace_results (sd, cpu, trace_idx, last_input); +} + +void +trace_result_fpu1 (SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + sim_fpu *f0) +{ + double d; + TRACE_DATA *data = CPU_TRACE_DATA (cpu); + int last_input; + + /* Append any results to the end of the inputs */ + last_input = TRACE_INPUT_IDX (data); + d = sim_fpu_2d (f0); + save_data (sd, data, trace_fmt_fp, sizeof (double), &d); + + trace_results (sd, cpu, trace_idx, last_input); +} + +void +trace_result_string1 (SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + char *s0) +{ + TRACE_DATA *data = CPU_TRACE_DATA (cpu); + int last_input; + + /* Append any results to the end of the inputs */ + last_input = TRACE_INPUT_IDX (data); + save_data (sd, data, trace_fmt_string, strlen (s0) + 1, s0); + + trace_results (sd, cpu, trace_idx, last_input); +} + +void +trace_result_word1_string1 (SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + unsigned_word r0, + char *s0) +{ + TRACE_DATA *data = CPU_TRACE_DATA (cpu); + int last_input; + + /* Append any results to the end of the inputs */ + last_input = TRACE_INPUT_IDX (data); + save_data (sd, data, trace_fmt_word, sizeof (unsigned_word), &r0); + save_data (sd, data, trace_fmt_string, strlen (s0) + 1, s0); + + trace_results (sd, cpu, trace_idx, last_input); +} + +void +trace_vprintf (SIM_DESC sd, sim_cpu *cpu, const char *fmt, va_list ap) +{ + if (cpu != NULL) + { + if (TRACE_FILE (CPU_TRACE_DATA (cpu)) != NULL) + vfprintf (TRACE_FILE (CPU_TRACE_DATA (cpu)), fmt, ap); + else + sim_io_evprintf (sd, fmt, ap); + } + else + { + if (TRACE_FILE (STATE_TRACE_DATA (sd)) != NULL) + vfprintf (TRACE_FILE (STATE_TRACE_DATA (sd)), fmt, ap); + else + sim_io_evprintf (sd, fmt, ap); + } +} + +/* The function trace_one_insn has been replaced by the function pair + trace_prefix() + trace_generic(). It is still used. */ +void +trace_one_insn (SIM_DESC sd, sim_cpu *cpu, address_word pc, + int line_p, const char *filename, int linenum, + const char *phase_wo_colon, const char *fmt, + ...) +{ + va_list ap; + char phase[SIZE_PHASE+2]; + + strncpy (phase, phase_wo_colon, SIZE_PHASE); + strcat (phase, ":"); + + if (!line_p) + { + trace_printf (sd, cpu, "%-*s %s:%-*d 0x%.*lx ", + SIZE_PHASE+1, phase, + filename, + SIZE_LINE_NUMBER, linenum, + SIZE_PC, (long)pc); + va_start (ap, fmt); + trace_vprintf (sd, cpu, fmt, ap); + va_end (ap); + trace_printf (sd, cpu, "\n"); + } + else + { + char buf[256]; + + buf[0] = 0; + if (STATE_TEXT_SECTION (CPU_STATE (cpu)) + && pc >= STATE_TEXT_START (CPU_STATE (cpu)) + && pc < STATE_TEXT_END (CPU_STATE (cpu))) + { + const char *pc_filename = (const char *)0; + const char *pc_function = (const char *)0; + unsigned int pc_linenum = 0; + + if (bfd_find_nearest_line (STATE_PROG_BFD (CPU_STATE (cpu)), + STATE_TEXT_SECTION (CPU_STATE (cpu)), + (struct symbol_cache_entry **) 0, + pc - STATE_TEXT_START (CPU_STATE (cpu)), + &pc_filename, &pc_function, &pc_linenum)) + { + char *p = buf; + if (pc_linenum) + { + sprintf (p, "#%-*d ", SIZE_LINE_NUMBER, pc_linenum); + p += strlen (p); + } + else + { + sprintf (p, "%-*s ", SIZE_LINE_NUMBER+1, "---"); + p += SIZE_LINE_NUMBER+2; + } + + if (pc_function) + { + sprintf (p, "%s ", pc_function); + p += strlen (p); + } + else if (pc_filename) + { + char *q = (char *) strrchr (pc_filename, '/'); + sprintf (p, "%s ", (q) ? q+1 : pc_filename); + p += strlen (p); + } + + if (*p == ' ') + *p = '\0'; + } + } + + trace_printf (sd, cpu, "%-*s 0x%.*x %-*.*s ", + SIZE_PHASE+1, phase, + SIZE_PC, (unsigned) pc, + SIZE_LOCATION, SIZE_LOCATION, buf); + va_start (ap, fmt); + trace_vprintf (sd, cpu, fmt, ap); + va_end (ap); + trace_printf (sd, cpu, "\n"); + } +} + +void +trace_printf VPARAMS ((SIM_DESC sd, sim_cpu *cpu, const char *fmt, ...)) +{ +#if !defined __STDC__ && !defined ALMOST_STDC + SIM_DESC sd; + sim_cpu *cpu; + const char *fmt; +#endif + va_list ap; + + VA_START (ap, fmt); +#if !defined __STDC__ && !defined ALMOST_STDC + sd = va_arg (ap, SIM_DESC); + cpu = va_arg (ap, sim_cpu *); + fmt = va_arg (ap, const char *); +#endif + + trace_vprintf (sd, cpu, fmt, ap); + + va_end (ap); +} + +void +debug_printf VPARAMS ((sim_cpu *cpu, const char *fmt, ...)) +{ +#if !defined __STDC__ && !defined ALMOST_STDC + sim_cpu *cpu; + const char *fmt; +#endif + va_list ap; + + VA_START (ap, fmt); +#if !defined __STDC__ && !defined ALMOST_STDC + cpu = va_arg (ap, sim_cpu *); + fmt = va_arg (ap, const char *); +#endif + + if (CPU_DEBUG_FILE (cpu) == NULL) + (* STATE_CALLBACK (CPU_STATE (cpu))->evprintf_filtered) + (STATE_CALLBACK (CPU_STATE (cpu)), fmt, ap); + else + vfprintf (CPU_DEBUG_FILE (cpu), fmt, ap); + + va_end (ap); +} diff --git a/sim/common/sim-trace.h b/sim/common/sim-trace.h new file mode 100644 index 0000000..14d277e --- /dev/null +++ b/sim/common/sim-trace.h @@ -0,0 +1,551 @@ +/* Simulator tracing/debugging support. + Copyright (C) 1997, 1998 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file is meant to be included by sim-basics.h. */ + +#ifndef SIM_TRACE_H +#define SIM_TRACE_H + +/* Standard traceable entities. */ + +enum { + /* Trace insn execution. */ + TRACE_INSN_IDX = 1, + + /* Trace insn decoding. + ??? This is more of a simulator debugging operation and might best be + moved to --debug-decode. */ + TRACE_DECODE_IDX, + + /* Trace insn extraction. + ??? This is more of a simulator debugging operation and might best be + moved to --debug-extract. */ + TRACE_EXTRACT_IDX, + + /* Trace insn execution but include line numbers. */ + TRACE_LINENUM_IDX, + + /* Trace memory operations. + The difference between this and TRACE_CORE_IDX is (I think) that this + is intended to apply to a higher level. TRACE_CORE_IDX applies to the + low level core operations. */ + TRACE_MEMORY_IDX, + + /* Include model performance data in tracing output. */ + TRACE_MODEL_IDX, + + /* Trace ALU operations. */ + TRACE_ALU_IDX, + + /* Trace memory core operations. */ + TRACE_CORE_IDX, + + /* Trace events. */ + TRACE_EVENTS_IDX, + + /* Trace fpu operations. */ + TRACE_FPU_IDX, + + /* Trace branching. */ + TRACE_BRANCH_IDX, + + /* Add information useful for debugging the simulator to trace output. */ + TRACE_DEBUG_IDX, + + /* Simulator specific trace bits begin here. */ + TRACE_NEXT_IDX, + +}; +/* Maximum number of traceable entities. */ +#ifndef MAX_TRACE_VALUES +#define MAX_TRACE_VALUES 32 +#endif + +/* The -t option only prints useful values. It's easy to type and shouldn't + splat on the screen everything under the sun making nothing easy to + find. */ +#define TRACE_USEFUL_MASK \ +((1 << TRACE_INSN_IDX) \ + | (1 << TRACE_LINENUM_IDX) \ + | (1 << TRACE_MEMORY_IDX) \ + | (1 << TRACE_MODEL_IDX) \ + | (1 << TRACE_EVENTS_IDX)) + +/* Masks so WITH_TRACE can have symbolic values. + The case choice here is on purpose. The lowercase parts are args to + --with-trace. */ +#define TRACE_insn (1 << TRACE_INSN_IDX) +#define TRACE_decode (1 << TRACE_DECODE_IDX) +#define TRACE_extract (1 << TRACE_EXTRACT_IDX) +#define TRACE_linenum (1 << TRACE_LINENUM_IDX) +#define TRACE_memory (1 << TRACE_MEMORY_IDX) +#define TRACE_model (1 << TRACE_MODEL_IDX) +#define TRACE_alu (1 << TRACE_ALU_IDX) +#define TRACE_core (1 << TRACE_CORE_IDX) +#define TRACE_events (1 << TRACE_EVENTS_IDX) +#define TRACE_fpu (1 << TRACE_FPU_IDX) +#define TRACE_branch (1 << TRACE_BRANCH_IDX) +#define TRACE_debug (1 << TRACE_DEBUG_IDX) + +/* Preprocessor macros to simplify tests of WITH_TRACE. */ +#define WITH_TRACE_INSN_P (WITH_TRACE & TRACE_insn) +#define WITH_TRACE_DECODE_P (WITH_TRACE & TRACE_decode) +#define WITH_TRACE_EXTRACT_P (WITH_TRACE & TRACE_extract) +#define WITH_TRACE_LINENUM_P (WITH_TRACE & TRACE_linenum) +#define WITH_TRACE_MEMORY_P (WITH_TRACE & TRACE_memory) +#define WITH_TRACE_MODEL_P (WITH_TRACE & TRACE_model) +#define WITH_TRACE_ALU_P (WITH_TRACE & TRACE_alu) +#define WITH_TRACE_CORE_P (WITH_TRACE & TRACE_core) +#define WITH_TRACE_EVENTS_P (WITH_TRACE & TRACE_events) +#define WITH_TRACE_FPU_P (WITH_TRACE & TRACE_fpu) +#define WITH_TRACE_BRANCH_P (WITH_TRACE & TRACE_branch) +#define WITH_TRACE_DEBUG_P (WITH_TRACE & TRACE_debug) + +/* Tracing install handler. */ +MODULE_INSTALL_FN trace_install; + +/* Struct containing all system and cpu trace data. + + System trace data is stored with the associated module. + System and cpu tracing must share the same space of bitmasks as they + are arguments to --with-trace. One could have --with-trace and + --with-cpu-trace or some such but that's an over-complication at this point + in time. Also, there may be occasions where system and cpu tracing may + wish to share a name. */ + +typedef struct _trace_data { + + /* Global summary of all the current trace options */ + char trace_any_p; + + /* Boolean array of specified tracing flags. */ + /* ??? It's not clear that using an array vs a bit mask is faster. + Consider the case where one wants to test whether any of several bits + are set. */ + char trace_flags[MAX_TRACE_VALUES]; +#define TRACE_FLAGS(t) ((t)->trace_flags) + + /* Tracing output goes to this or stderr if NULL. + We can't store `stderr' here as stderr goes through a callback. */ + FILE *trace_file; +#define TRACE_FILE(t) ((t)->trace_file) + + /* Buffer to store the prefix to be printed before any trace line. */ + char trace_prefix[256]; +#define TRACE_PREFIX(t) ((t)->trace_prefix) + + /* Buffer to save the inputs for the current instruction. Use a + union to force the buffer into correct alignment */ + union { + unsigned8 i8; + unsigned16 i16; + unsigned32 i32; + unsigned64 i64; + } trace_input_data[16]; + unsigned8 trace_input_fmt[16]; + unsigned8 trace_input_size[16]; + int trace_input_idx; +#define TRACE_INPUT_DATA(t) ((t)->trace_input_data) +#define TRACE_INPUT_FMT(t) ((t)->trace_input_fmt) +#define TRACE_INPUT_SIZE(t) ((t)->trace_input_size) +#define TRACE_INPUT_IDX(t) ((t)->trace_input_idx) + + /* Category of trace being performed */ + int trace_idx; +#define TRACE_IDX(t) ((t)->trace_idx) + + /* Trace range. + ??? Not all cpu's support this. */ + ADDR_RANGE range; +#define TRACE_RANGE(t) (& (t)->range) +} TRACE_DATA; + +/* System tracing support. */ + +#define STATE_TRACE_FLAGS(sd) TRACE_FLAGS (STATE_TRACE_DATA (sd)) + +/* Return non-zero if tracing of IDX is enabled for non-cpu specific + components. The "S" in "STRACE" refers to "System". */ +#define STRACE_P(sd,idx) \ +((WITH_TRACE & (1 << (idx))) != 0 \ + && STATE_TRACE_FLAGS (sd)[idx] != 0) + +/* Non-zero if --trace-<xxxx> was specified for SD. */ +#define STRACE_DEBUG_P(sd) STRACE_P (sd, TRACE_DEBUG_IDX) + +/* CPU tracing support. */ + +#define CPU_TRACE_FLAGS(cpu) TRACE_FLAGS (CPU_TRACE_DATA (cpu)) + +/* Return non-zero if tracing of IDX is enabled for CPU. */ +#define TRACE_P(cpu,idx) \ +((WITH_TRACE & (1 << (idx))) != 0 \ + && CPU_TRACE_FLAGS (cpu)[idx] != 0) + +/* Non-zero if --trace-<xxxx> was specified for CPU. */ +#define TRACE_ANY_P(cpu) ((WITH_TRACE) && (CPU_TRACE_DATA (cpu)->trace_any_p)) +#define TRACE_INSN_P(cpu) TRACE_P (cpu, TRACE_INSN_IDX) +#define TRACE_DECODE_P(cpu) TRACE_P (cpu, TRACE_DECODE_IDX) +#define TRACE_EXTRACT_P(cpu) TRACE_P (cpu, TRACE_EXTRACT_IDX) +#define TRACE_LINENUM_P(cpu) TRACE_P (cpu, TRACE_LINENUM_IDX) +#define TRACE_MEMORY_P(cpu) TRACE_P (cpu, TRACE_MEMORY_IDX) +#define TRACE_MODEL_P(cpu) TRACE_P (cpu, TRACE_MODEL_IDX) +#define TRACE_ALU_P(cpu) TRACE_P (cpu, TRACE_ALU_IDX) +#define TRACE_CORE_P(cpu) TRACE_P (cpu, TRACE_CORE_IDX) +#define TRACE_EVENTS_P(cpu) TRACE_P (cpu, TRACE_EVENTS_IDX) +#define TRACE_FPU_P(cpu) TRACE_P (cpu, TRACE_FPU_IDX) +#define TRACE_BRANCH_P(cpu) TRACE_P (cpu, TRACE_BRANCH_IDX) +#define TRACE_DEBUG_P(cpu) TRACE_P (cpu, TRACE_DEBUG_IDX) + +/* Traceing functions. + + */ + +/* Prime the trace buffers ready for any trace output. + Must be called prior to any other trace operation */ +extern void trace_prefix PARAMS ((SIM_DESC sd, + sim_cpu *cpu, + sim_cia cia, + address_word pc, + int print_linenum_p, + const char *file_name, + int line_nr, + const char *fmt, + ...)) + __attribute__((format (printf, 8, 9))); + +/* Generic trace print, assumes trace_prefix() has been called */ + +extern void trace_generic PARAMS ((SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + const char *fmt, + ...)) + __attribute__((format (printf, 4, 5))); + +/* Trace a varying number of word sized inputs/outputs. trace_result* + must be called to close the trace operation. */ + +extern void trace_input0 PARAMS ((SIM_DESC sd, + sim_cpu *cpu, + int trace_idx)); + +extern void trace_input_word1 PARAMS ((SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + unsigned_word d0)); + +extern void trace_input_word2 PARAMS ((SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + unsigned_word d0, + unsigned_word d1)); + +extern void trace_input_word3 PARAMS ((SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + unsigned_word d0, + unsigned_word d1, + unsigned_word d2)); + +extern void trace_input_word4 PARAMS ((SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + unsigned_word d0, + unsigned_word d1, + unsigned_word d2, + unsigned_word d3)); + +extern void trace_input_addr1 PARAMS ((SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + address_word d0)); + +extern void trace_input_bool1 PARAMS ((SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + int d0)); + +extern void trace_input_fp1 PARAMS ((SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + fp_word f0)); + +extern void trace_input_fp2 PARAMS ((SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + fp_word f0, + fp_word f1)); + +extern void trace_input_fp3 PARAMS ((SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + fp_word f0, + fp_word f1, + fp_word f2)); + +extern void trace_input_fpu1 PARAMS ((SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + struct _sim_fpu *f0)); + +extern void trace_input_fpu2 PARAMS ((SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + struct _sim_fpu *f0, + struct _sim_fpu *f1)); + +extern void trace_input_fpu3 PARAMS ((SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + struct _sim_fpu *f0, + struct _sim_fpu *f1, + struct _sim_fpu *f2)); + +/* Other trace_input{_<fmt><nr-inputs>} functions can go here */ + +extern void trace_result0 PARAMS ((SIM_DESC sd, + sim_cpu *cpu, + int trace_idx)); + +extern void trace_result_word1 PARAMS ((SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + unsigned_word r0)); + +extern void trace_result_word2 PARAMS ((SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + unsigned_word r0, + unsigned_word r1)); + +extern void trace_result_word4 PARAMS ((SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + unsigned_word r0, + unsigned_word r1, + unsigned_word r2, + unsigned_word r3)); + +extern void trace_result_bool1 PARAMS ((SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + int r0)); + +extern void trace_result_addr1 PARAMS ((SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + address_word r0)); + +extern void trace_result_fp1 PARAMS ((SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + fp_word f0)); + +extern void trace_result_fp2 PARAMS ((SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + fp_word f0, + fp_word f1)); + +extern void trace_result_fpu1 PARAMS ((SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + struct _sim_fpu *f0)); + +extern void trace_result_string1 PARAMS ((SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + char *str0)); + +extern void trace_result_word1_string1 PARAMS ((SIM_DESC sd, + sim_cpu *cpu, + int trace_idx, + unsigned_word r0, + char *s0)); + +/* Other trace_result{_<type><nr-results>} */ + + +/* Macro's for tracing ALU instructions */ + +#define TRACE_ALU_INPUT0() \ +do { \ + if (TRACE_ALU_P (CPU)) \ + trace_input0 (SD, CPU, TRACE_ALU_IDX); \ +} while (0) + +#define TRACE_ALU_INPUT1(V0) \ +do { \ + if (TRACE_ALU_P (CPU)) \ + trace_input_word1 (SD, CPU, TRACE_ALU_IDX, (V0)); \ +} while (0) + +#define TRACE_ALU_INPUT2(V0,V1) \ +do { \ + if (TRACE_ALU_P (CPU)) \ + trace_input_word2 (SD, CPU, TRACE_ALU_IDX, (V0), (V1)); \ +} while (0) + +#define TRACE_ALU_INPUT3(V0,V1,V2) \ +do { \ + if (TRACE_ALU_P (CPU)) \ + trace_input_word3 (SD, CPU, TRACE_ALU_IDX, (V0), (V1), (V2)); \ +} while (0) + +#define TRACE_ALU_INPUT4(V0,V1,V2,V3) \ +do { \ + if (TRACE_ALU_P (CPU)) \ + trace_input_word4 (SD, CPU, TRACE_ALU_IDX, (V0), (V1), (V2), (V3)); \ +} while (0) + +#define TRACE_ALU_RESULT(R0) TRACE_ALU_RESULT1(R0) + +#define TRACE_ALU_RESULT0() \ +do { \ + if (TRACE_ALU_P (CPU)) \ + trace_result0 (SD, CPU, TRACE_ALU_IDX); \ +} while (0) + +#define TRACE_ALU_RESULT1(R0) \ +do { \ + if (TRACE_ALU_P (CPU)) \ + trace_result_word1 (SD, CPU, TRACE_ALU_IDX, (R0)); \ +} while (0) + +#define TRACE_ALU_RESULT2(R0,R1) \ +do { \ + if (TRACE_ALU_P (CPU)) \ + trace_result_word2 (SD, CPU, TRACE_ALU_IDX, (R0), (R1)); \ +} while (0) + +#define TRACE_ALU_RESULT4(R0,R1,R2,R3) \ +do { \ + if (TRACE_ALU_P (CPU)) \ + trace_result_word4 (SD, CPU, TRACE_ALU_IDX, (R0), (R1), (R2), (R3)); \ +} while (0) + + +/* Macro's for tracing FPU instructions */ + +#define TRACE_FP_INPUT0() \ +do { \ + if (TRACE_FPU_P (CPU)) \ + trace_input0 (SD, CPU, TRACE_FPU_IDX); \ +} while (0) + +#define TRACE_FP_INPUT1(V0) \ +do { \ + if (TRACE_FPU_P (CPU)) \ + trace_input_fp1 (SD, CPU, TRACE_FPU_IDX, (V0)); \ +} while (0) + +#define TRACE_FP_INPUT2(V0,V1) \ +do { \ + if (TRACE_FPU_P (CPU)) \ + trace_input_fp2 (SD, CPU, TRACE_FPU_IDX, (V0), (V1)); \ +} while (0) + +#define TRACE_FP_INPUT3(V0,V1,V2) \ +do { \ + if (TRACE_FPU_P (CPU)) \ + trace_input_fp3 (SD, CPU, TRACE_FPU_IDX, (V0), (V1), (V2)); \ +} while (0) + +#define TRACE_FP_INPUT_WORD1(V0) \ +do { \ + if (TRACE_FPU_P (CPU)) \ + trace_input_word1 (SD, CPU, TRACE_FPU_IDX, (V0)); \ +} while (0) + +#define TRACE_FP_RESULT(R0) \ +do { \ + if (TRACE_FPU_P (CPU)) \ + trace_result_fp1 (SD, CPU, TRACE_FPU_IDX, (R0)); \ +} while (0) + +#define TRACE_FP_RESULT2(R0,R1) \ +do { \ + if (TRACE_FPU_P (CPU)) \ + trace_result_fp2 (SD, CPU, TRACE_FPU_IDX, (R0), (R1)); \ +} while (0) + +#define TRACE_FP_RESULT_BOOL(R0) \ +do { \ + if (TRACE_FPU_P (CPU)) \ + trace_result_bool1 (SD, CPU, TRACE_FPU_IDX, (R0)); \ +} while (0) + +#define TRACE_FP_RESULT_WORD(R0) \ +do { \ + if (TRACE_FPU_P (CPU)) \ + trace_result_word1 (SD, CPU, TRACE_FPU_IDX, (R0)); \ +} while (0) + + +/* Macros for tracing branches */ + +#define TRACE_BRANCH_INPUT(COND) \ +do { \ + if (TRACE_BRANCH_P (CPU)) \ + trace_input_bool1 (SD, CPU, TRACE_BRANCH_IDX, (COND)); \ +} while (0) + +#define TRACE_BRANCH_RESULT(DEST) \ +do { \ + if (TRACE_BRANCH_P (CPU)) \ + trace_result_addr1 (SD, CPU, TRACE_BRANCH_IDX, (DEST)); \ +} while (0) + + +/* The function trace_one_insn has been replaced by the function pair + trace_prefix() + trace_generic() */ +extern void trace_one_insn PARAMS ((SIM_DESC sd, + sim_cpu * cpu, + address_word cia, + int print_linenum_p, + const char *file_name, + int line_nr, + const char *unit, + const char *fmt, + ...)) + __attribute__((format (printf, 8, 9))); + +extern void trace_printf PARAMS ((SIM_DESC, sim_cpu *, const char *, ...)) + __attribute__((format (printf, 3, 4))); + +extern void trace_vprintf PARAMS ((SIM_DESC, sim_cpu *, const char *, va_list)); + +/* Debug support. + This is included here because there isn't enough of it to justify + a sim-debug.h. */ + +/* Return non-zero if debugging of IDX for CPU is enabled. */ +#define DEBUG_P(cpu, idx) \ +((WITH_DEBUG & (1 << (idx))) != 0 \ + && CPU_DEBUG_FLAGS (cpu)[idx] != 0) + +/* Non-zero if "--debug-insn" specified. */ +#define DEBUG_INSN_P(cpu) DEBUG_P (cpu, DEBUG_INSN_IDX) + +extern void debug_printf PARAMS ((sim_cpu *, const char *, ...)) + __attribute__((format (printf, 2, 3))); + +#endif /* SIM_TRACE_H */ diff --git a/sim/common/sim-types.h b/sim/common/sim-types.h new file mode 100644 index 0000000..babc598 --- /dev/null +++ b/sim/common/sim-types.h @@ -0,0 +1,201 @@ +/* This file is part of psim (model of the PowerPC(tm) architecture) + + Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License + as published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + -- + + PowerPC is a trademark of International Business Machines Corporation. */ + + +#ifndef SIM_TYPES_H +/* #define SIM_TYPES_H */ + +/* INTEGER QUANTITIES: + + TYPES: + + signed* signed type of the given size + unsigned* The corresponding insigned type + + SIZES + + *NN Size based on the number of bits + *_NN Size according to the number of bytes + *_word Size based on the target architecture's word + word size (32/64 bits) + *_cell Size based on the target architecture's + IEEE 1275 cell size (almost always 32 bits) + +*/ + + +#if !defined (SIM_TYPES_H) && defined (__GNUC__) +#define SIM_TYPES_H + +/* bit based */ + +#define UNSIGNED32(X) ((unsigned32) X##UL) +#define UNSIGNED64(X) ((unsigned64) X##ULL) + +#define SIGNED32(X) ((signed32) X##L) +#define SIGNED64(X) ((signed64) X##LL) + +typedef signed int signed8 __attribute__ ((__mode__ (__QI__))); +typedef signed int signed16 __attribute__ ((__mode__ (__HI__))); +typedef signed int signed32 __attribute__ ((__mode__ (__SI__))); +typedef signed int signed64 __attribute__ ((__mode__ (__DI__))); + +typedef unsigned int unsigned8 __attribute__ ((__mode__ (__QI__))); +typedef unsigned int unsigned16 __attribute__ ((__mode__ (__HI__))); +typedef unsigned int unsigned32 __attribute__ ((__mode__ (__SI__))); +typedef unsigned int unsigned64 __attribute__ ((__mode__ (__DI__))); + +typedef struct { unsigned64 a[2]; } unsigned128; +typedef struct { signed64 a[2]; } signed128; + +#endif + + +#if !defined (SIM_TYPES_H) && defined (_MSC_VER) +#define SIM_TYPES_H + +/* bit based */ + +#define UNSIGNED32(X) (X##ui32) +#define UNSIGNED64(X) (X##ui64) + +#define SIGNED32(X) (X##i32) +#define SIGNED64(X) (X##i64) + +typedef signed char signed8; +typedef signed short signed16; +typedef signed int signed32; +typedef signed __int64 signed64; + +typedef unsigned int unsigned8; +typedef unsigned int unsigned16; +typedef unsigned int unsigned32; +typedef unsigned __int64 unsigned64; + +typedef struct { unsigned64 a[2]; } unsigned128; +typedef struct { signed64 a[2]; } signed128; + +#endif /* _MSC_VER */ + + +#if !defined (SIM_TYPES_H) +#define SIM_TYPES_H + +/* bit based */ + +#define UNSIGNED32(X) (X##UL) +#define UNSIGNED64(X) (X##ULL) + +#define SIGNED32(X) (X##L) +#define SIGNED64(X) (X##LL) + +typedef signed char signed8; +typedef signed short signed16; +#if defined (__ALPHA__) +typedef signed int unsigned32; +typedef signed long unsigned64; +#else +typedef signed long unsigned32; +typedef signed long long unsigned64; +#endif + +typedef unsigned char unsigned8; +typedef unsigned short unsigned16; +#if defined (__ALPHA__) +typedef unsigned int unsigned32; +typedef unsigned long unsigned64; +#else +typedef unsigned long unsigned32; +typedef unsigned long long unsigned64; +#endif + +typedef struct { unsigned64 a[2]; } unsigned128; +typedef struct { signed64 a[2]; } signed128; + +#endif + + +/* byte based */ + +typedef signed8 signed_1; +typedef signed16 signed_2; +typedef signed32 signed_4; +typedef signed64 signed_8; +typedef signed128 signed_16; + +typedef unsigned8 unsigned_1; +typedef unsigned16 unsigned_2; +typedef unsigned32 unsigned_4; +typedef unsigned64 unsigned_8; +typedef unsigned128 unsigned_16; + + +/* for general work, the following are defined */ +/* unsigned: >= 32 bits */ +/* signed: >= 32 bits */ +/* long: >= 32 bits, sign undefined */ +/* int: small indicator */ + +/* target architecture based */ +#if (WITH_TARGET_WORD_BITSIZE == 64) +typedef unsigned64 unsigned_word; +typedef signed64 signed_word; +#endif +#if (WITH_TARGET_WORD_BITSIZE == 32) +typedef unsigned32 unsigned_word; +typedef signed32 signed_word; +#endif + + +/* Other instructions */ +#if (WITH_TARGET_ADDRESS_BITSIZE == 64) +typedef unsigned64 unsigned_address; +typedef signed64 signed_address; +#endif +#if (WITH_TARGET_ADDRESS_BITSIZE == 32) +typedef unsigned32 unsigned_address; +typedef signed32 signed_address; +#endif +typedef unsigned_address address_word; + + +/* IEEE 1275 cell size */ +#if (WITH_TARGET_CELL_BITSIZE == 64) +typedef unsigned64 unsigned_cell; +typedef signed64 signed_cell; +#endif +#if (WITH_TARGET_CELL_BITSIZE == 32) +typedef unsigned32 unsigned_cell; +typedef signed32 signed_cell; +#endif +typedef signed_cell cell_word; /* cells are normally signed */ + + +/* Floating point registers */ +#if (WITH_TARGET_FLOATING_POINT_BITSIZE == 64) +typedef unsigned64 fp_word; +#endif +#if (WITH_TARGET_FLOATING_POINT_BITSIZE == 32) +typedef unsigned32 fp_word; +#endif + +#endif diff --git a/sim/common/sim-utils.c b/sim/common/sim-utils.c new file mode 100644 index 0000000..3adbae5 --- /dev/null +++ b/sim/common/sim-utils.c @@ -0,0 +1,411 @@ +/* Miscellaneous simulator utilities. + Copyright (C) 1997, 1998 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "sim-main.h" +#include "sim-assert.h" + +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif + +#ifdef HAVE_TIME_H +#include <time.h> +#endif + +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> /* needed by sys/resource.h */ +#endif + +#ifdef HAVE_SYS_RESOURCE_H +#include <sys/resource.h> +#endif + +#ifdef HAVE_STRING_H +#include <string.h> +#else +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#endif + +#include "libiberty.h" +#include "bfd.h" +#include "sim-utils.h" + +/* Global pointer to all state data. + Set by sim_resume. */ +struct sim_state *current_state; + +/* Allocate zero filled memory with xmalloc - xmalloc aborts of the + allocation fails. */ + +void * +zalloc (unsigned long size) +{ + void *memory = (void *) xmalloc (size); + memset (memory, 0, size); + return memory; +} + +void +zfree (void *data) +{ + free (data); +} + +/* Allocate a sim_state struct. */ + +SIM_DESC +sim_state_alloc (SIM_OPEN_KIND kind, + host_callback *callback) +{ + SIM_DESC sd = ZALLOC (struct sim_state); + + STATE_MAGIC (sd) = SIM_MAGIC_NUMBER; + STATE_CALLBACK (sd) = callback; + STATE_OPEN_KIND (sd) = kind; + +#if 0 + { + int cpu_nr; + + /* Initialize the back link from the cpu struct to the state struct. */ + /* ??? I can envision a design where the state struct contains an array + of pointers to cpu structs, rather than an array of structs themselves. + Implementing this is trickier as one may not know what to allocate until + one has parsed the args. Parsing the args twice wouldn't be unreasonable, + IMHO. If the state struct ever does contain an array of pointers then we + can't do this here. + ??? See also sim_post_argv_init*/ + for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; cpu_nr++) + { + CPU_STATE (STATE_CPU (sd, cpu_nr)) = sd; + CPU_INDEX (STATE_CPU (sd, cpu_nr)) = cpu_nr; + } + } +#endif + +#ifdef SIM_STATE_INIT + SIM_STATE_INIT (sd); +#endif + + return sd; +} + +/* Free a sim_state struct. */ + +void +sim_state_free (SIM_DESC sd) +{ + ASSERT (sd->base.magic == SIM_MAGIC_NUMBER); + +#ifdef SIM_STATE_FREE + SIM_STATE_FREE (sd); +#endif + + zfree (sd); +} + +/* Return a pointer to the cpu data for CPU_NAME, or NULL if not found. */ + +sim_cpu * +sim_cpu_lookup (SIM_DESC sd, const char *cpu_name) +{ + int i; + + for (i = 0; i < MAX_NR_PROCESSORS; ++i) + if (strcmp (cpu_name, CPU_NAME (STATE_CPU (sd, i))) == 0) + return STATE_CPU (sd, i); + return NULL; +} + +/* Return the prefix to use for a CPU specific message (typically an + error message). */ + +const char * +sim_cpu_msg_prefix (sim_cpu *cpu) +{ +#if MAX_NR_PROCESSORS == 1 + return ""; +#else + static char *prefix; + + if (prefix == NULL) + { + int maxlen = 0; + for (i = 0; i < MAX_NR_PROCESSORS; ++i) + { + int len = strlen (CPU_NAME (STATE_CPU (sd, i))); + if (len > maxlen) + maxlen = len; + } + prefix = (char *) xmalloc (maxlen + 5); + } + sprintf (prefix, "%s: ", CPU_NAME (cpu)); + return prefix; +#endif +} + +/* Cover fn to sim_io_eprintf. */ + +void +sim_io_eprintf_cpu (sim_cpu *cpu, const char *fmt, ...) +{ + SIM_DESC sd = CPU_STATE (cpu); + va_list ap; + + va_start (ap, fmt); + sim_io_eprintf (sd, sim_cpu_msg_prefix (cpu)); + sim_io_evprintf (sd, fmt, ap); + va_end (ap); +} + +/* Turn VALUE into a string with commas. */ + +char * +sim_add_commas (char *buf, int sizeof_buf, unsigned long value) +{ + int comma = 3; + char *endbuf = buf + sizeof_buf - 1; + + *--endbuf = '\0'; + do { + if (comma-- == 0) + { + *--endbuf = ','; + comma = 2; + } + + *--endbuf = (value % 10) + '0'; + } while ((value /= 10) != 0); + + return endbuf; +} + +/* Analyze PROG_NAME/PROG_BFD and set these fields in the state struct: + STATE_ARCHITECTURE, if not set already and can be determined from the bfd + STATE_PROG_BFD + STATE_START_ADDR + STATE_TEXT_SECTION + STATE_TEXT_START + STATE_TEXT_END + + PROG_NAME is the file name of the executable or NULL. + PROG_BFD is its bfd or NULL. + + If both PROG_NAME and PROG_BFD are NULL, this function returns immediately. + If PROG_BFD is not NULL, PROG_NAME is ignored. + + Implicit inputs: STATE_MY_NAME(sd), STATE_TARGET(sd), + STATE_ARCHITECTURE(sd). + + A new bfd is created so the app isn't required to keep its copy of the + bfd open. */ + +SIM_RC +sim_analyze_program (sd, prog_name, prog_bfd) + SIM_DESC sd; + char *prog_name; + bfd *prog_bfd; +{ + asection *s; + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + + if (prog_bfd != NULL) + { + if (prog_bfd == STATE_PROG_BFD (sd)) + /* already analyzed */ + return SIM_RC_OK; + else + /* duplicate needed, save the name of the file to be re-opened */ + prog_name = bfd_get_filename (prog_bfd); + } + + /* do we need to duplicate anything? */ + if (prog_name == NULL) + return SIM_RC_OK; + + /* open a new copy of the prog_bfd */ + prog_bfd = bfd_openr (prog_name, STATE_TARGET (sd)); + if (prog_bfd == NULL) + { + sim_io_eprintf (sd, "%s: can't open \"%s\": %s\n", + STATE_MY_NAME (sd), + prog_name, + bfd_errmsg (bfd_get_error ())); + return SIM_RC_FAIL; + } + if (!bfd_check_format (prog_bfd, bfd_object)) + { + sim_io_eprintf (sd, "%s: \"%s\" is not an object file: %s\n", + STATE_MY_NAME (sd), + prog_name, + bfd_errmsg (bfd_get_error ())); + bfd_close (prog_bfd); + return SIM_RC_FAIL; + } + if (STATE_ARCHITECTURE (sd) != NULL) + bfd_set_arch_info (prog_bfd, STATE_ARCHITECTURE (sd)); + else + { + if (bfd_get_arch (prog_bfd) != bfd_arch_unknown + && bfd_get_arch (prog_bfd) != bfd_arch_obscure) + { + STATE_ARCHITECTURE (sd) = bfd_get_arch_info (prog_bfd); + } + } + + /* update the sim structure */ + if (STATE_PROG_BFD (sd) != NULL) + bfd_close (STATE_PROG_BFD (sd)); + STATE_PROG_BFD (sd) = prog_bfd; + STATE_START_ADDR (sd) = bfd_get_start_address (prog_bfd); + + for (s = prog_bfd->sections; s; s = s->next) + if (strcmp (bfd_get_section_name (prog_bfd, s), ".text") == 0) + { + STATE_TEXT_SECTION (sd) = s; + STATE_TEXT_START (sd) = bfd_get_section_vma (prog_bfd, s); + STATE_TEXT_END (sd) = STATE_TEXT_START (sd) + bfd_section_size (prog_bfd, s); + break; + } + + return SIM_RC_OK; +} + +/* Simulator timing support. */ + +/* Called before sim_elapsed_time_since to get a reference point. */ + +SIM_ELAPSED_TIME +sim_elapsed_time_get () +{ +#ifdef HAVE_GETRUSAGE + struct rusage mytime; + if (getrusage (RUSAGE_SELF, &mytime) == 0) + return 1 + (SIM_ELAPSED_TIME) (((double) mytime.ru_utime.tv_sec * 1000) + (((double) mytime.ru_utime.tv_usec + 500) / 1000)); + return 1; +#else +#ifdef HAVE_TIME + return 1 + (SIM_ELAPSED_TIME) time ((time_t) 0); +#else + return 1; +#endif +#endif +} + +/* Return the elapsed time in milliseconds since START. + The actual time may be cpu usage (prefered) or wall clock. */ + +unsigned long +sim_elapsed_time_since (start) + SIM_ELAPSED_TIME start; +{ +#ifdef HAVE_GETRUSAGE + return sim_elapsed_time_get () - start; +#else +#ifdef HAVE_TIME + return (sim_elapsed_time_get () - start) * 1000; +#else + return 0; +#endif +#endif +} + + + +/* do_command but with printf style formatting of the arguments */ +void +sim_do_commandf (SIM_DESC sd, + const char *fmt, + ...) +{ + va_list ap; + char *buf; + va_start (ap, fmt); + vasprintf (&buf, fmt, ap); + sim_do_command (sd, buf); + va_end (ap); + free (buf); +} + + +/* sim-basics.h defines a number of enumerations, convert each of them + to a string representation */ +const char * +map_to_str (unsigned map) +{ + switch (map) + { + case read_map: return "read"; + case write_map: return "write"; + case exec_map: return "exec"; + case io_map: return "io"; + default: + { + static char str[10]; + sprintf (str, "(%ld)", (long) map); + return str; + } + } +} + +const char * +access_to_str (unsigned access) +{ + switch (access) + { + case access_invalid: return "invalid"; + case access_read: return "read"; + case access_write: return "write"; + case access_exec: return "exec"; + case access_io: return "io"; + case access_read_write: return "read_write"; + case access_read_exec: return "read_exec"; + case access_write_exec: return "write_exec"; + case access_read_write_exec: return "read_write_exec"; + case access_read_io: return "read_io"; + case access_write_io: return "write_io"; + case access_read_write_io: return "read_write_io"; + case access_exec_io: return "exec_io"; + case access_read_exec_io: return "read_exec_io"; + case access_write_exec_io: return "write_exec_io"; + case access_read_write_exec_io: return "read_write_exec_io"; + default: + { + static char str[10]; + sprintf (str, "(%ld)", (long) access); + return str; + } + } +} + +const char * +transfer_to_str (unsigned transfer) +{ + switch (transfer) + { + case read_transfer: return "read"; + case write_transfer: return "write"; + default: return "(error)"; + } +} + + diff --git a/sim/common/sim-utils.h b/sim/common/sim-utils.h new file mode 100644 index 0000000..8e80e6a --- /dev/null +++ b/sim/common/sim-utils.h @@ -0,0 +1,90 @@ +/* Miscellaneous simulator utilities. + Copyright (C) 1997 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef SIM_UTILS_H +#define SIM_UTILS_H + +/* Memory management with an allocator that clears memory before use. */ + +void *zalloc (unsigned long size); + +#define ZALLOC(TYPE) (TYPE*)zalloc(sizeof (TYPE)) +#define NZALLOC(TYPE,N) (TYPE*)zalloc(sizeof (TYPE) * (N)) + +void zfree(void*); + +/* Turn VALUE into a string with commas. */ +char *sim_add_commas (char *, int, unsigned long); + +/* Utilities for elapsed time reporting. */ + +/* Opaque type, known only inside sim_elapsed_time_foo fns. Externally + it is known to never have the value zero. */ +typedef unsigned long SIM_ELAPSED_TIME; + + +/* Get reference point for future call to sim_time_elapsed. */ +SIM_ELAPSED_TIME sim_elapsed_time_get (void); + +/* Elapsed time in milliseconds since START. */ +unsigned long sim_elapsed_time_since (SIM_ELAPSED_TIME start); + +/* Utilities for manipulating the load image. */ + +SIM_RC sim_analyze_program (SIM_DESC sd, char *prog_name, + struct _bfd *prog_bfd); + +/* Load program PROG into the simulator using the function DO_LOAD. + If PROG_BFD is non-NULL, the file has already been opened. + If VERBOSE_P is non-zero statistics are printed of each loaded section + and the transfer rate (for consistency with gdb). + If LMA_P is non-zero the program sections are loaded at the LMA + rather than the VMA + If this fails an error message is printed and NULL is returned. + If it succeeds the bfd is returned. + NOTE: For historical reasons, older hardware simulators incorrectly + write the program sections at LMA interpreted as a virtual address. + This is still accommodated for backward compatibility reasons. */ + +typedef int sim_write_fn PARAMS ((SIM_DESC sd, SIM_ADDR mem, + unsigned char *buf, int length)); +struct _bfd *sim_load_file (SIM_DESC sd, const char *myname, + host_callback *callback, char *prog, + struct _bfd *prog_bfd, int verbose_p, + int lma_p, sim_write_fn do_load); + +/* Internal version of sim_do_command, include formatting */ +void sim_do_commandf (SIM_DESC sd, const char *fmt, ...); + + +/* These are defined in callback.c as cover functions to the vprintf + callbacks. */ + +void sim_cb_printf (host_callback *, const char *, ...); +void sim_cb_eprintf (host_callback *, const char *, ...); + + +/* sim-basics.h defines a number of enumerations, convert each of them + to a string representation */ +const char *map_to_str (unsigned map); +const char *access_to_str (unsigned access); +const char *transfer_to_str (unsigned transfer); + +#endif diff --git a/sim/common/sim-watch.c b/sim/common/sim-watch.c new file mode 100644 index 0000000..75c9ad1 --- /dev/null +++ b/sim/common/sim-watch.c @@ -0,0 +1,458 @@ +/* Generic simulator watchpoint support. + Copyright (C) 1997 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "sim-main.h" +#include "sim-options.h" + +#include "sim-assert.h" + +#include <ctype.h> + +#ifdef HAVE_STRING_H +#include <string.h> +#else +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#endif + +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif + +enum { + OPTION_WATCH_DELETE = OPTION_START, + + OPTION_WATCH_INFO, + OPTION_WATCH_CLOCK, + OPTION_WATCH_CYCLES, + OPTION_WATCH_PC, + + OPTION_WATCH_OP, +}; + + +/* Break an option number into its op/int-nr */ +static watchpoint_type +option_to_type (SIM_DESC sd, + int option) +{ + sim_watchpoints *watch = STATE_WATCHPOINTS (sd); + watchpoint_type type = ((option - OPTION_WATCH_OP) + / (watch->nr_interrupts + 1)); + SIM_ASSERT (type >= 0 && type < nr_watchpoint_types); + return type; +} + +static int +option_to_interrupt_nr (SIM_DESC sd, + int option) +{ + sim_watchpoints *watch = STATE_WATCHPOINTS (sd); + int interrupt_nr = ((option - OPTION_WATCH_OP) + % (watch->nr_interrupts + 1)); + return interrupt_nr; +} + +static int +type_to_option (SIM_DESC sd, + watchpoint_type type, + int interrupt_nr) +{ + sim_watchpoints *watch = STATE_WATCHPOINTS (sd); + return ((type * (watch->nr_interrupts + 1)) + + interrupt_nr + + OPTION_WATCH_OP); +} + + +/* Delete one or more watchpoints. Fail if no watchpoints were found */ + +static SIM_RC +do_watchpoint_delete (SIM_DESC sd, + int ident, + watchpoint_type type) +{ + sim_watchpoints *watch = STATE_WATCHPOINTS (sd); + sim_watch_point **entry = &watch->points; + SIM_RC status = SIM_RC_FAIL; + while ((*entry) != NULL) + { + if ((*entry)->ident == ident + || (*entry)->type == type) + { + sim_watch_point *dead = (*entry); + (*entry) = (*entry)->next; + sim_events_deschedule (sd, dead->event); + zfree (dead); + status = SIM_RC_OK; + } + else + entry = &(*entry)->next; + } + return status; +} + +static char * +watchpoint_type_to_str (SIM_DESC sd, + watchpoint_type type) +{ + switch (type) + { + case pc_watchpoint: + return "pc"; + case clock_watchpoint: + return "clock"; + case cycles_watchpoint: + return "cycles"; + case invalid_watchpoint: + case nr_watchpoint_types: + return "(invalid-type)"; + } + return NULL; +} + +static char * +interrupt_nr_to_str (SIM_DESC sd, + int interrupt_nr) +{ + sim_watchpoints *watch = STATE_WATCHPOINTS (sd); + if (interrupt_nr < 0) + return "(invalid-interrupt)"; + else if (interrupt_nr >= watch->nr_interrupts) + return "breakpoint"; + else + return watch->interrupt_names[interrupt_nr]; +} + + +static void +do_watchpoint_info (SIM_DESC sd) +{ + sim_watchpoints *watch = STATE_WATCHPOINTS (sd); + sim_watch_point *point; + sim_io_printf (sd, "Watchpoints:\n"); + for (point = watch->points; point != NULL; point = point->next) + { + sim_io_printf (sd, "%3d: watch %s %s ", + point->ident, + watchpoint_type_to_str (sd, point->type), + interrupt_nr_to_str (sd, point->interrupt_nr)); + if (point->is_periodic) + sim_io_printf (sd, "+"); + if (!point->is_within) + sim_io_printf (sd, "!"); + sim_io_printf (sd, "0x%lx", point->arg0); + if (point->arg1 != point->arg0) + sim_io_printf (sd, ",0x%lx", point->arg1); + sim_io_printf (sd, "\n"); + } +} + + + +static sim_event_handler handle_watchpoint; + +static SIM_RC +schedule_watchpoint (SIM_DESC sd, + sim_watch_point *point) +{ + sim_watchpoints *watch = STATE_WATCHPOINTS (sd); + switch (point->type) + { + case pc_watchpoint: + point->event = sim_events_watch_sim (sd, + watch->pc, + watch->sizeof_pc, + 0/* host-endian */, + point->is_within, + point->arg0, point->arg1, + /* PC in arg0..arg1 */ + handle_watchpoint, + point); + return SIM_RC_OK; + case clock_watchpoint: + point->event = sim_events_watch_clock (sd, + point->arg0, /* ms time */ + handle_watchpoint, + point); + return SIM_RC_OK; + case cycles_watchpoint: + point->event = sim_events_schedule (sd, + point->arg0, /* time */ + handle_watchpoint, + point); + return SIM_RC_OK; + default: + sim_engine_abort (sd, NULL, NULL_CIA, + "handle_watchpoint - internal error - bad switch"); + return SIM_RC_FAIL; + } + return SIM_RC_OK; +} + + +static void +handle_watchpoint (SIM_DESC sd, void *data) +{ + sim_watchpoints *watch = STATE_WATCHPOINTS (sd); + sim_watch_point *point = (sim_watch_point *) data; + int interrupt_nr = point->interrupt_nr; + + if (point->is_periodic) + /* reschedule this event before processing it */ + schedule_watchpoint (sd, point); + else + do_watchpoint_delete (sd, point->ident, invalid_watchpoint); + + if (point->interrupt_nr == watch->nr_interrupts) + sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_stopped, SIM_SIGINT); + else + watch->interrupt_handler (sd, &watch->interrupt_names[interrupt_nr]); +} + + +static SIM_RC +do_watchpoint_create (SIM_DESC sd, + watchpoint_type type, + int opt, + char *arg) +{ + sim_watchpoints *watch = STATE_WATCHPOINTS (sd); + sim_watch_point **point; + + /* create the watchpoint */ + point = &watch->points; + while ((*point) != NULL) + point = &(*point)->next; + (*point) = ZALLOC (sim_watch_point); + + /* fill in the details */ + (*point)->ident = ++(watch->last_point_nr); + (*point)->type = option_to_type (sd, opt); + (*point)->interrupt_nr = option_to_interrupt_nr (sd, opt); + /* prefixes to arg - +== periodic, !==not or outside */ + (*point)->is_within = 1; + while (1) + { + if (arg[0] == '+') + (*point)->is_periodic = 1; + else if (arg[0] == '!') + (*point)->is_within = 0; + else + break; + arg++; + } + + (*point)->arg0 = strtoul (arg, &arg, 0); + if (arg[0] == ',') + (*point)->arg0 = strtoul (arg, NULL, 0); + else + (*point)->arg1 = (*point)->arg0; + + /* schedule it */ + schedule_watchpoint (sd, (*point)); + + return SIM_RC_OK; +} + + +static SIM_RC +watchpoint_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt, + char *arg, int is_command) +{ + if (opt >= OPTION_WATCH_OP) + return do_watchpoint_create (sd, clock_watchpoint, opt, arg); + else + switch (opt) + { + + case OPTION_WATCH_DELETE: + if (isdigit ((int) arg[0])) + { + int ident = strtol (arg, NULL, 0); + if (do_watchpoint_delete (sd, ident, invalid_watchpoint) + != SIM_RC_OK) + { + sim_io_eprintf (sd, "Watchpoint %d not found\n", ident); + return SIM_RC_FAIL; + } + return SIM_RC_OK; + } + else if (strcasecmp (arg, "all") == 0) + { + watchpoint_type type; + for (type = invalid_watchpoint + 1; + type < nr_watchpoint_types; + type++) + { + do_watchpoint_delete (sd, 0, type); + } + return SIM_RC_OK; + } + else if (strcasecmp (arg, "pc") == 0) + { + if (do_watchpoint_delete (sd, 0, pc_watchpoint) + != SIM_RC_OK) + { + sim_io_eprintf (sd, "No PC watchpoints found\n"); + return SIM_RC_FAIL; + } + return SIM_RC_OK; + } + else if (strcasecmp (arg, "clock") == 0) + { + if (do_watchpoint_delete (sd, 0, clock_watchpoint) != SIM_RC_OK) + { + sim_io_eprintf (sd, "No CLOCK watchpoints found\n"); + return SIM_RC_FAIL; + } + return SIM_RC_OK; + } + else if (strcasecmp (arg, "cycles") == 0) + { + if (do_watchpoint_delete (sd, 0, cycles_watchpoint) != SIM_RC_OK) + { + sim_io_eprintf (sd, "No CYCLES watchpoints found\n"); + return SIM_RC_FAIL; + } + return SIM_RC_OK; + } + sim_io_eprintf (sd, "Unknown watchpoint type `%s'\n", arg); + return SIM_RC_FAIL; + + case OPTION_WATCH_INFO: + { + do_watchpoint_info (sd); + return SIM_RC_OK; + } + + default: + sim_io_eprintf (sd, "Unknown watch option %d\n", opt); + return SIM_RC_FAIL; + + } + +} + + +static SIM_RC +sim_watchpoint_init (SIM_DESC sd) +{ + sim_watchpoints *watch = STATE_WATCHPOINTS (sd); + sim_watch_point *point; + /* NOTE: Do not need to de-schedule any previous watchpoints as + sim-events has already done this */ + /* schedule any watchpoints enabled by command line options */ + for (point = watch->points; point != NULL; point = point->next) + { + schedule_watchpoint (sd, point); + } + return SIM_RC_OK; +} + + +static const OPTION watchpoint_options[] = +{ + { {"watch-delete", required_argument, NULL, OPTION_WATCH_DELETE }, + '\0', "IDENT|all|pc|cycles|clock", "Delete a watchpoint", + watchpoint_option_handler }, + + { {"watch-info", no_argument, NULL, OPTION_WATCH_INFO }, + '\0', NULL, "List scheduled watchpoints", + watchpoint_option_handler }, + + { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL } +}; + +static char *default_interrupt_names[] = { "int", 0, }; + + + +SIM_RC +sim_watchpoint_install (SIM_DESC sd) +{ + sim_watchpoints *watch = STATE_WATCHPOINTS (sd); + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + /* the basic command set */ + sim_module_add_init_fn (sd, sim_watchpoint_init); + sim_add_option_table (sd, NULL, watchpoint_options); + /* fill in some details */ + if (watch->interrupt_names == NULL) + watch->interrupt_names = default_interrupt_names; + watch->nr_interrupts = 0; + while (watch->interrupt_names[watch->nr_interrupts] != NULL) + watch->nr_interrupts++; + /* generate more advansed commands */ + { + OPTION *int_options = NZALLOC (OPTION, 1 + (watch->nr_interrupts + 1) * nr_watchpoint_types); + int interrupt_nr; + for (interrupt_nr = 0; interrupt_nr <= watch->nr_interrupts; interrupt_nr++) + { + watchpoint_type type; + for (type = 0; type < nr_watchpoint_types; type++) + { + char *name; + int nr = interrupt_nr * nr_watchpoint_types + type; + OPTION *option = &int_options[nr]; + asprintf (&name, "watch-%s-%s", + watchpoint_type_to_str (sd, type), + interrupt_nr_to_str (sd, interrupt_nr)); + option->opt.name = name; + option->opt.has_arg = required_argument; + option->opt.val = type_to_option (sd, type, interrupt_nr); + option->doc = ""; + option->doc_name = ""; + option->handler = watchpoint_option_handler; + } + } + /* adjust first few entries so that they contain real + documentation, the first entry includes a list of actions. */ + { + char *prefix = + "Watch the simulator, take ACTION in COUNT cycles (`+' for every COUNT cycles), ACTION is"; + char *doc; + int len = strlen (prefix) + 1; + for (interrupt_nr = 0; interrupt_nr <= watch->nr_interrupts; interrupt_nr++) + len += strlen (interrupt_nr_to_str (sd, interrupt_nr)) + 1; + doc = NZALLOC (char, len); + strcpy (doc, prefix); + for (interrupt_nr = 0; interrupt_nr <= watch->nr_interrupts; interrupt_nr++) + { + strcat (doc, " "); + strcat (doc, interrupt_nr_to_str (sd, interrupt_nr)); + } + int_options[0].doc_name = "watch-cycles-ACTION"; + int_options[0].arg = "[+]COUNT"; + int_options[0].doc = doc; + } + int_options[1].doc_name = "watch-pc-ACTION"; + int_options[1].arg = "[!]ADDRESS"; + int_options[1].doc = + "Watch the PC, take ACTION when matches ADDRESS (in range ADDRESS,ADDRESS), `!' negates test"; + int_options[2].doc_name = "watch-clock-ACTION"; + int_options[2].arg = "[+]MILLISECONDS"; + int_options[2].doc = + "Watch the clock, take ACTION after MILLISECONDS (`+' for every MILLISECONDS)"; + + sim_add_option_table (sd, NULL, int_options); + } + return SIM_RC_OK; +} diff --git a/sim/common/sim-watch.h b/sim/common/sim-watch.h new file mode 100644 index 0000000..ad920d3 --- /dev/null +++ b/sim/common/sim-watch.h @@ -0,0 +1,78 @@ +/* Simulator watchpoint support. + Copyright (C) 1997 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB, the GNU debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +#ifndef SIM_WATCH_H +#define SIM_WATCH_H + +typedef enum { + invalid_watchpoint = -1, + pc_watchpoint, + clock_watchpoint, + cycles_watchpoint, + nr_watchpoint_types, +} watchpoint_type; + +typedef struct _sim_watch_point sim_watch_point; +struct _sim_watch_point { + int ident; + watchpoint_type type; + int interrupt_nr; /* == nr_interrupts -> breakpoint */ + int is_periodic; + int is_within; + unsigned long arg0; + unsigned long arg1; + sim_event *event; + sim_watch_point *next; +}; + + +typedef struct _sim_watchpoints { + + /* Pointer into the host's data structures specifying the + address/size of the program-counter */ + /* FIXME: In the future this shall be generalized so that any of the + N processors M registers can be watched */ + void *pc; + int sizeof_pc; + + /* Pointer to the handler for interrupt watchpoints */ + /* FIXME: can this be done better? */ + /* NOTE: For the DATA arg, the handler is passed a (char**) pointer + that is an offset into the INTERRUPT_NAMES vector. Use + arithmetic to determine the interrupt-nr. */ + sim_event_handler *interrupt_handler; + + /* Pointer to a null terminated list of interrupt names */ + /* FIXME: can this be done better? Look at the PPC's interrupt + mechanism and table for a rough idea of where it will go next */ + int nr_interrupts; + char **interrupt_names; + + /* active watchpoints */ + int last_point_nr; + sim_watch_point *points; + +} sim_watchpoints; + +/* Watch install handler. */ +MODULE_INSTALL_FN sim_watchpoint_install; + +#endif /* SIM_WATCH_H */ diff --git a/sim/common/syscall.c b/sim/common/syscall.c new file mode 100644 index 0000000..e0a3b88 --- /dev/null +++ b/sim/common/syscall.c @@ -0,0 +1,482 @@ +/* Remote target system call support. + Copyright 1997, 1998 Free Software Foundation, Inc. + Contributed by Cygnus Solutions. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This interface isn't intended to be specific to any particular kind + of remote (hardware, simulator, whatever). As such, support for it + (e.g. sim/common/callback.c) should *not* live in the simulator source + tree, nor should it live in the gdb source tree. K&R C must be + supported. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "ansidecl.h" +#include "libiberty.h" +#ifdef ANSI_PROTOTYPES +#include <stdarg.h> +#else +#include <varargs.h> +#endif +#include <stdio.h> +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <errno.h> +#include <fcntl.h> +#include <time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "callback.h" +#include "targ-vals.h" + +#ifndef ENOSYS +#define ENOSYS EINVAL +#endif +#ifndef ENAMETOOLONG +#define ENAMETOOLONG EINVAL +#endif + +/* Maximum length of a path name. */ +#ifndef MAX_PATH_LEN +#define MAX_PATH_LEN 1024 +#endif + +/* When doing file read/writes, do this many bytes at a time. */ +#define FILE_XFR_SIZE 4096 + +/* FIXME: for now, need to consider target word size. */ +#define TWORD long +#define TADDR unsigned long + +/* Utility of cb_syscall to fetch a path name or other string from the target. + The result is 0 for success or a host errno value. */ + +static int +get_string (cb, sc, buf, buflen, addr) + host_callback *cb; + CB_SYSCALL *sc; + char *buf; + int buflen; + TADDR addr; +{ + char *p, *pend; + + for (p = buf, pend = buf + buflen; p < pend; ++p, ++addr) + { + /* No, it isn't expected that this would cause one transaction with + the remote target for each byte. The target could send the + path name along with the syscall request, and cache the file + name somewhere (or otherwise tweak this as desired). */ + unsigned int count = (*sc->read_mem) (cb, sc, addr, p, 1); + + if (count != 1) + return EINVAL; + if (*p == 0) + break; + } + if (p == pend) + return ENAMETOOLONG; + return 0; +} + +/* Utility of cb_syscall to fetch a path name. + The buffer is malloc'd and the address is stored in BUFP. + The result is that of get_string. + If an error occurs, no buffer is left malloc'd. */ + +static int +get_path (cb, sc, addr, bufp) + host_callback *cb; + CB_SYSCALL *sc; + TADDR addr; + char **bufp; +{ + char *buf = xmalloc (MAX_PATH_LEN); + int result; + + result = get_string (cb, sc, buf, MAX_PATH_LEN, addr); + if (result == 0) + *bufp = buf; + else + free (buf); + return result; +} + +/* Perform a system call on behalf of the target. */ + +CB_RC +cb_syscall (cb, sc) + host_callback *cb; + CB_SYSCALL *sc; +{ + TWORD result = 0, errcode = 0; + + if (sc->magic != CB_SYSCALL_MAGIC) + abort (); + + switch (cb_target_to_host_syscall (cb, sc->func)) + { +#if 0 /* FIXME: wip */ + case CB_SYS_argvlen : + { + /* Compute how much space is required to store the argv,envp + strings so that the program can allocate the space and then + call SYS_argv to fetch the values. */ + int addr_size = cb->addr_size; + int argc,envc,arglen,envlen; + const char **argv = cb->init_argv; + const char **envp = cb->init_envp; + + argc = arglen = 0; + if (argv) + { + for ( ; argv[argc]; ++argc) + arglen += strlen (argv[argc]) + 1; + } + envc = envlen = 0; + if (envp) + { + for ( ; envp[envc]; ++envc) + envlen += strlen (envp[envc]) + 1; + } + result = arglen + envlen; + break; + } + + case CB_SYS_argv : + { + /* Pointer to target's buffer. */ + TADDR tbuf = sc->arg1; + /* Buffer size. */ + int bufsize = sc->arg2; + /* Q is the target address of where all the strings go. */ + TADDR q; + int word_size = cb->word_size; + int i,argc,envc,len; + const char **argv = cb->init_argv; + const char **envp = cb->init_envp; + + argc = 0; + if (argv) + { + for ( ; argv[argc]; ++argc) + { + int len = strlen (argv[argc]); + int written = (*sc->write_mem) (cb, sc, tbuf, argv[argc], len + 1); + if (written != len) + { + result = -1; + errcode = EINVAL; + goto FinishSyscall; + } + tbuf = len + 1; + } + } + if ((*sc->write_mem) (cb, sc, tbuf, "", 1) != 1) + { + result = -1; + errcode = EINVAL; + goto FinishSyscall; + } + tbuf++; + envc = 0; + if (envp) + { + for ( ; envp[envc]; ++envc) + { + int len = strlen (envp[envc]); + int written = (*sc->write_mem) (cb, sc, tbuf, envp[envc], len + 1); + if (written != len) + { + result = -1; + errcode = EINVAL; + goto FinishSyscall; + } + tbuf = len + 1; + } + } + if ((*sc->write_mem) (cb, sc, tbuf, "", 1) != 1) + { + result = -1; + errcode = EINVAL; + goto FinishSyscall; + } + result = argc; + sc->result2 = envc; + break; + } +#endif /* wip */ + + case CB_SYS_exit : + /* Caller must catch and handle. */ + break; + + case CB_SYS_open : + { + char *path; + + errcode = get_path (cb, sc, sc->arg1, &path); + if (errcode != 0) + { + result = -1; + goto FinishSyscall; + } + result = (*cb->open) (cb, path, sc->arg2 /*, sc->arg3*/); + free (path); + if (result < 0) + goto ErrorFinish; + } + break; + + case CB_SYS_close : + result = (*cb->close) (cb, sc->arg1); + if (result < 0) + goto ErrorFinish; + break; + + case CB_SYS_read : + { + /* ??? Perfect handling of error conditions may require only one + call to cb->read. One can't assume all the data is + contiguously stored in host memory so that would require + malloc'ing/free'ing the space. Maybe later. */ + char buf[FILE_XFR_SIZE]; + int fd = sc->arg1; + TADDR addr = sc->arg2; + size_t count = sc->arg3; + size_t bytes_read = 0; + int bytes_written; + + while (count > 0) + { + if (fd == 0) + result = (int) (*cb->read_stdin) (cb, buf, + (count < FILE_XFR_SIZE + ? count : FILE_XFR_SIZE)); + else + result = (int) (*cb->read) (cb, fd, buf, + (count < FILE_XFR_SIZE + ? count : FILE_XFR_SIZE)); + if (result == -1) + goto ErrorFinish; + if (result == 0) /* EOF */ + break; + bytes_written = (*sc->write_mem) (cb, sc, addr, buf, result); + if (bytes_written != result) + { + result = -1; + errcode = EINVAL; + goto FinishSyscall; + } + bytes_read += result; + count -= result; + addr += result; + /* If this is a short read, don't go back for more */ + if (result != FILE_XFR_SIZE) + break; + } + result = bytes_read; + } + break; + + case CB_SYS_write : + { + /* ??? Perfect handling of error conditions may require only one + call to cb->write. One can't assume all the data is + contiguously stored in host memory so that would require + malloc'ing/free'ing the space. Maybe later. */ + char buf[FILE_XFR_SIZE]; + int fd = sc->arg1; + TADDR addr = sc->arg2; + size_t count = sc->arg3; + int bytes_read; + size_t bytes_written = 0; + + while (count > 0) + { + int bytes_to_read = count < FILE_XFR_SIZE ? count : FILE_XFR_SIZE; + bytes_read = (*sc->read_mem) (cb, sc, addr, buf, bytes_to_read); + if (bytes_read != bytes_to_read) + { + result = -1; + errcode = EINVAL; + goto FinishSyscall; + } + if (fd == 1) + { + result = (int) (*cb->write_stdout) (cb, buf, bytes_read); + (*cb->flush_stdout) (cb); + } + else if (fd == 2) + { + result = (int) (*cb->write_stderr) (cb, buf, bytes_read); + (*cb->flush_stderr) (cb); + } + else + result = (int) (*cb->write) (cb, fd, buf, bytes_read); + if (result == -1) + goto ErrorFinish; + bytes_written += result; + count -= result; + addr += result; + } + result = bytes_written; + } + break; + + case CB_SYS_lseek : + { + int fd = sc->arg1; + unsigned long offset = sc->arg2; + int whence = sc->arg3; + + result = (*cb->lseek) (cb, fd, offset, whence); + if (result < 0) + goto ErrorFinish; + } + break; + + case CB_SYS_unlink : + { + char *path; + + errcode = get_path (cb, sc, sc->arg1, &path); + if (errcode != 0) + { + result = -1; + goto FinishSyscall; + } + result = (*cb->unlink) (cb, path); + free (path); + if (result < 0) + goto ErrorFinish; + } + break; + + case CB_SYS_stat : + { + char *path,*buf; + int buflen; + struct stat statbuf; + TADDR addr = sc->arg2; + + errcode = get_path (cb, sc, sc->arg1, &path); + if (errcode != 0) + { + result = -1; + goto FinishSyscall; + } + result = (*cb->stat) (cb, path, &statbuf); + free (path); + if (result < 0) + goto ErrorFinish; + buflen = cb_host_to_target_stat (cb, NULL, NULL); + buf = xmalloc (buflen); + if (cb_host_to_target_stat (cb, &statbuf, buf) != buflen) + { + /* The translation failed. This is due to an internal + host program error, not the target's fault. */ + free (buf); + errcode = ENOSYS; + result = -1; + goto FinishSyscall; + } + if ((*sc->write_mem) (cb, sc, addr, buf, buflen) != buflen) + { + free (buf); + errcode = EINVAL; + result = -1; + goto FinishSyscall; + } + free (buf); + } + break; + + case CB_SYS_fstat : + { + char *buf; + int buflen; + struct stat statbuf; + TADDR addr = sc->arg2; + + result = (*cb->fstat) (cb, sc->arg1, &statbuf); + if (result < 0) + goto ErrorFinish; + buflen = cb_host_to_target_stat (cb, NULL, NULL); + buf = xmalloc (buflen); + if (cb_host_to_target_stat (cb, &statbuf, buf) != buflen) + { + /* The translation failed. This is due to an internal + host program error, not the target's fault. */ + free (buf); + errcode = ENOSYS; + result = -1; + goto FinishSyscall; + } + if ((*sc->write_mem) (cb, sc, addr, buf, buflen) != buflen) + { + free (buf); + errcode = EINVAL; + result = -1; + goto FinishSyscall; + } + free (buf); + } + break; + + case CB_SYS_time : + { + /* FIXME: May wish to change CB_SYS_time to something else. + We might also want gettimeofday or times, but if system calls + can be built on others, we can keep the number we have to support + here down. */ + time_t t = (*cb->time) (cb, (time_t *) 0); + result = t; + /* It is up to target code to process the argument to time(). */ + } + break; + + case CB_SYS_chdir : + case CB_SYS_chmod : + case CB_SYS_utime : + /* fall through for now */ + + default : + result = -1; + errcode = ENOSYS; + break; + } + + FinishSyscall: + sc->result = result; + if (errcode == 0) + sc->errcode = 0; + else + sc->errcode = cb_host_to_target_errno (cb, errcode); + return CB_RC_OK; + + ErrorFinish: + sc->result = result; + sc->errcode = (*cb->get_errno) (cb); + return CB_RC_OK; +} diff --git a/sim/common/tconfig.in b/sim/common/tconfig.in new file mode 100644 index 0000000..fd8b5be --- /dev/null +++ b/sim/common/tconfig.in @@ -0,0 +1,19 @@ +/* Default target configuration file. + To override this, create file `tconfig.in' in the simulator's + source directory. */ + +/* Define this if the simulator supports profiling. + See the mips simulator for an example. + This enables the `-p foo' and `-s bar' options. + The target is required to provide sim_set_profile{,_size}. */ +/* #define SIM_HAVE_PROFILE */ + +/* Define this if the simulator uses an instruction cache. + See the h8/300 simulator for an example. + This enables the `-c size' option to set the size of the cache. + The target is required to provide sim_set_simcache_size. */ +/* #define SIM_HAVE_SIMCACHE */ + +/* Define this if the target cpu is bi-endian + and the simulator supports it. */ +/* #define SIM_HAVE_BIENDIAN */ |