/* * Copyright 2010 Tilera Corporation. All Rights Reserved. * * 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, version 2. * * 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, GOOD TITLE or * NON INFRINGEMENT. See the GNU General Public License for * more details. */ /** * @file * * Provides an API for controlling the simulator at runtime. */ /** * @addtogroup arch_sim * @{ * * An API for controlling the simulator at runtime. * * The simulator's behavior can be modified while it is running. * For example, human-readable trace output can be enabled and disabled * around code of interest. * * There are two ways to modify simulator behavior: * programmatically, by calling various sim_* functions, and * interactively, by entering commands like "sim set functional true" * at the tile-monitor prompt. Typing "sim help" at that prompt provides * a list of interactive commands. * * All interactive commands can also be executed programmatically by * passing a string to the sim_command function. */ #ifndef __ARCH_SIM_H__ #define __ARCH_SIM_H__ #include #include #ifndef __ASSEMBLER__ #include /** * Return true if the current program is running under a simulator, * rather than on real hardware. If running on hardware, other "sim_xxx()" * calls have no useful effect. */ static inline int sim_is_simulator(void) { return __insn_mfspr(SPR_SIM_CONTROL) != 0; } /** * Checkpoint the simulator state to a checkpoint file. * * The checkpoint file name is either the default or the name specified * on the command line with "--checkpoint-file". */ static __inline void sim_checkpoint(void) { __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_CHECKPOINT); } /** * Report whether or not various kinds of simulator tracing are enabled. * * @return The bitwise OR of these values: * * SIM_TRACE_CYCLES (--trace-cycles), * SIM_TRACE_ROUTER (--trace-router), * SIM_TRACE_REGISTER_WRITES (--trace-register-writes), * SIM_TRACE_DISASM (--trace-disasm), * SIM_TRACE_STALL_INFO (--trace-stall-info) * SIM_TRACE_MEMORY_CONTROLLER (--trace-memory-controller) * SIM_TRACE_L2_CACHE (--trace-l2) * SIM_TRACE_LINES (--trace-lines) */ static __inline unsigned int sim_get_tracing(void) { return __insn_mfspr(SPR_SIM_CONTROL) & SIM_TRACE_FLAG_MASK; } /** * Turn on or off different kinds of simulator tracing. * * @param mask Either one of these special values: * * SIM_TRACE_NONE (turns off tracing), * SIM_TRACE_ALL (turns on all possible tracing). * * or the bitwise OR of these values: * * SIM_TRACE_CYCLES (--trace-cycles), * SIM_TRACE_ROUTER (--trace-router), * SIM_TRACE_REGISTER_WRITES (--trace-register-writes), * SIM_TRACE_DISASM (--trace-disasm), * SIM_TRACE_STALL_INFO (--trace-stall-info) * SIM_TRACE_MEMORY_CONTROLLER (--trace-memory-controller) * SIM_TRACE_L2_CACHE (--trace-l2) * SIM_TRACE_LINES (--trace-lines) */ static __inline void sim_set_tracing(unsigned int mask) { __insn_mtspr(SPR_SIM_CONTROL, SIM_TRACE_SPR_ARG(mask)); } /** * Request dumping of different kinds of simulator state. * * @param mask Either this special value: * * SIM_DUMP_ALL (dump all known state) * * or the bitwise OR of these values: * * SIM_DUMP_REGS (the register file), * SIM_DUMP_SPRS (the SPRs), * SIM_DUMP_ITLB (the iTLB), * SIM_DUMP_DTLB (the dTLB), * SIM_DUMP_L1I (the L1 I-cache), * SIM_DUMP_L1D (the L1 D-cache), * SIM_DUMP_L2 (the L2 cache), * SIM_DUMP_SNREGS (the switch register file), * SIM_DUMP_SNITLB (the switch iTLB), * SIM_DUMP_SNL1I (the switch L1 I-cache), * SIM_DUMP_BACKTRACE (the current backtrace) */ static __inline void sim_dump(unsigned int mask) { __insn_mtspr(SPR_SIM_CONTROL, SIM_DUMP_SPR_ARG(mask)); } /** * Print a string to the simulator stdout. * * @param str The string to be written. */ static __inline void sim_print(const char* str) { for ( ; *str != '\0'; str++) { __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PUTC | (*str << _SIM_CONTROL_OPERATOR_BITS)); } __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PUTC | (SIM_PUTC_FLUSH_BINARY << _SIM_CONTROL_OPERATOR_BITS)); } /** * Print a string to the simulator stdout. * * @param str The string to be written (a newline is automatically added). */ static __inline void sim_print_string(const char* str) { for ( ; *str != '\0'; str++) { __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PUTC | (*str << _SIM_CONTROL_OPERATOR_BITS)); } __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PUTC | (SIM_PUTC_FLUSH_STRING << _SIM_CONTROL_OPERATOR_BITS)); } /** * Execute a simulator command string. * * Type 'sim help' at the tile-monitor prompt to learn what commands * are available. Note the use of the tile-monitor "sim" command to * pass commands to the simulator. * * The argument to sim_command() does not include the leading "sim" * prefix used at the tile-monitor prompt; for example, you might call * sim_command("trace disasm"). */ static __inline void sim_command(const char* str) { int c; do { c = *str++; __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_COMMAND | (c << _SIM_CONTROL_OPERATOR_BITS)); } while (c); } #ifndef __DOXYGEN__ /** * The underlying implementation of "_sim_syscall()". * * We use extra "and" instructions to ensure that all the values * we are passing to the simulator are actually valid in the registers * (i.e. returned from memory) prior to the SIM_CONTROL spr. */ static __inline long _sim_syscall0(int val) { long result; __asm__ __volatile__ ("mtspr SIM_CONTROL, r0" : "=R00" (result) : "R00" (val)); return result; } static __inline long _sim_syscall1(int val, long arg1) { long result; __asm__ __volatile__ ("{ and zero, r1, r1; mtspr SIM_CONTROL, r0 }" : "=R00" (result) : "R00" (val), "R01" (arg1)); return result; } static __inline long _sim_syscall2(int val, long arg1, long arg2) { long result; __asm__ __volatile__ ("{ and zero, r1, r2; mtspr SIM_CONTROL, r0 }" : "=R00" (result) : "R00" (val), "R01" (arg1), "R02" (arg2)); return result; } /* Note that _sim_syscall3() and higher are technically at risk of receiving an interrupt right before the mtspr bundle, in which case the register values for arguments 3 and up may still be in flight to the core from a stack frame reload. */ static __inline long _sim_syscall3(int val, long arg1, long arg2, long arg3) { long result; __asm__ __volatile__ ("{ and zero, r3, r3 };" "{ and zero, r1, r2; mtspr SIM_CONTROL, r0 }" : "=R00" (result) : "R00" (val), "R01" (arg1), "R02" (arg2), "R03" (arg3)); return result; } static __inline long _sim_syscall4(int val, long arg1, long arg2, long arg3, long arg4) { long result; __asm__ __volatile__ ("{ and zero, r3, r4 };" "{ and zero, r1, r2; mtspr SIM_CONTROL, r0 }" : "=R00" (result) : "R00" (val), "R01" (arg1), "R02" (arg2), "R03" (arg3), "R04" (arg4)); return result; } static __inline long _sim_syscall5(int val, long arg1, long arg2, long arg3, long arg4, long arg5) { long result; __asm__ __volatile__ ("{ and zero, r3, r4; and zero, r5, r5 };" "{ and zero, r1, r2; mtspr SIM_CONTROL, r0 }" : "=R00" (result) : "R00" (val), "R01" (arg1), "R02" (arg2), "R03" (arg3), "R04" (arg4), "R05" (arg5)); return result; } /** * Make a special syscall to the simulator itself, if running under * simulation. This is used as the implementation of other functions * and should not be used outside this file. * * @param syscall_num The simulator syscall number. * @param nr The number of additional arguments provided. * * @return Varies by syscall. */ #define _sim_syscall(syscall_num, nr, args...) \ _sim_syscall##nr( \ ((syscall_num) << _SIM_CONTROL_OPERATOR_BITS) | SIM_CONTROL_SYSCALL, \ ##args) /* Values for the "access_mask" parameters below. */ #define SIM_WATCHPOINT_READ 1 #define SIM_WATCHPOINT_WRITE 2 #define SIM_WATCHPOINT_EXECUTE 4 static __inline int sim_add_watchpoint(unsigned int process_id, unsigned long address, unsigned long size, unsigned int access_mask, unsigned long user_data) { return _sim_syscall(SIM_SYSCALL_ADD_WATCHPOINT, 5, process_id, address, size, access_mask, user_data); } static __inline int sim_remove_watchpoint(unsigned int process_id, unsigned long address, unsigned long size, unsigned int access_mask, unsigned long user_data) { return _sim_syscall(SIM_SYSCALL_REMOVE_WATCHPOINT, 5, process_id, address, size, access_mask, user_data); } /** * Return value from sim_query_watchpoint. */ struct SimQueryWatchpointStatus { /** * 0 if a watchpoint fired, 1 if no watchpoint fired, or -1 for * error (meaning a bad process_id). */ int syscall_status; /** * The address of the watchpoint that fired (this is the address * passed to sim_add_watchpoint, not an address within that range * that actually triggered the watchpoint). */ unsigned long address; /** The arbitrary user_data installed by sim_add_watchpoint. */ unsigned long user_data; }; static __inline struct SimQueryWatchpointStatus sim_query_watchpoint(unsigned int process_id) { struct SimQueryWatchpointStatus status; long val = SIM_CONTROL_SYSCALL | (SIM_SYSCALL_QUERY_WATCHPOINT << _SIM_CONTROL_OPERATOR_BITS); __asm__ __volatile__ ("{ and zero, r1, r1; mtspr SIM_CONTROL, r0 }" : "=R00" (status.syscall_status), "=R01" (status.address), "=R02" (status.user_data) : "R00" (val), "R01" (process_id)); return status; } /* On the simulator, confirm lines have been evicted everywhere. */ static __inline void sim_validate_lines_evicted(unsigned long long pa, unsigned long length) { #ifdef __LP64__ _sim_syscall(SIM_SYSCALL_VALIDATE_LINES_EVICTED, 2, pa, length); #else _sim_syscall(SIM_SYSCALL_VALIDATE_LINES_EVICTED, 4, 0 /* dummy */, (long)(pa), (long)(pa >> 32), length); #endif } /* Return the current CPU speed in cycles per second. */ static __inline long sim_query_cpu_speed(void) { return _sim_syscall(SIM_SYSCALL_QUERY_CPU_SPEED, 0); } #endif /* !__DOXYGEN__ */ /** * Modify the shaping parameters of a shim. * * @param shim The shim to modify. One of: * SIM_CONTROL_SHAPING_GBE_0 * SIM_CONTROL_SHAPING_GBE_1 * SIM_CONTROL_SHAPING_GBE_2 * SIM_CONTROL_SHAPING_GBE_3 * SIM_CONTROL_SHAPING_XGBE_0 * SIM_CONTROL_SHAPING_XGBE_1 * * @param type The type of shaping. This should be the same type of * shaping that is already in place on the shim. One of: * SIM_CONTROL_SHAPING_MULTIPLIER * SIM_CONTROL_SHAPING_PPS * SIM_CONTROL_SHAPING_BPS * * @param units The magnitude of the rate. One of: * SIM_CONTROL_SHAPING_UNITS_SINGLE * SIM_CONTROL_SHAPING_UNITS_KILO * SIM_CONTROL_SHAPING_UNITS_MEGA * SIM_CONTROL_SHAPING_UNITS_GIGA * * @param rate The rate to which to change it. This must fit in * SIM_CONTROL_SHAPING_RATE_BITS bits or a warning is issued and * the shaping is not changed. * * @return 0 if no problems were detected in the arguments to sim_set_shaping * or 1 if problems were detected (for example, rate does not fit in 17 bits). */ static __inline int sim_set_shaping(unsigned shim, unsigned type, unsigned units, unsigned rate) { if ((rate & ~((1 << SIM_CONTROL_SHAPING_RATE_BITS) - 1)) != 0) return 1; __insn_mtspr(SPR_SIM_CONTROL, SIM_SHAPING_SPR_ARG(shim, type, units, rate)); return 0; } #ifdef __tilegx__ /** Enable a set of mPIPE links. Pass a -1 link_mask to enable all links. */ static __inline void sim_enable_mpipe_links(unsigned mpipe, unsigned long link_mask) { __insn_mtspr(SPR_SIM_CONTROL, (SIM_CONTROL_ENABLE_MPIPE_LINK_MAGIC_BYTE | (mpipe << 8) | (1 << 16) | ((uint_reg_t)link_mask << 32))); } /** Disable a set of mPIPE links. Pass a -1 link_mask to disable all links. */ static __inline void sim_disable_mpipe_links(unsigned mpipe, unsigned long link_mask) { __insn_mtspr(SPR_SIM_CONTROL, (SIM_CONTROL_ENABLE_MPIPE_LINK_MAGIC_BYTE | (mpipe << 8) | (0 << 16) | ((uint_reg_t)link_mask << 32))); } #endif /* __tilegx__ */ /* * An API for changing "functional" mode. */ #ifndef __DOXYGEN__ #define sim_enable_functional() \ __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_ENABLE_FUNCTIONAL) #define sim_disable_functional() \ __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_DISABLE_FUNCTIONAL) #endif /* __DOXYGEN__ */ /* * Profiler support. */ /** * Turn profiling on for the current task. * * Note that this has no effect if run in an environment without * profiling support (thus, the proper flags to the simulator must * be supplied). */ static __inline void sim_profiler_enable(void) { __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PROFILER_ENABLE); } /** Turn profiling off for the current task. */ static __inline void sim_profiler_disable(void) { __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PROFILER_DISABLE); } /** * Turn profiling on or off for the current task. * * @param enabled If true, turns on profiling. If false, turns it off. * * Note that this has no effect if run in an environment without * profiling support (thus, the proper flags to the simulator must * be supplied). */ static __inline void sim_profiler_set_enabled(int enabled) { int val = enabled ? SIM_CONTROL_PROFILER_ENABLE : SIM_CONTROL_PROFILER_DISABLE; __insn_mtspr(SPR_SIM_CONTROL, val); } /** * Return true if and only if profiling is currently enabled * for the current task. * * This returns false even if sim_profiler_enable() was called * if the current execution environment does not support profiling. */ static __inline int sim_profiler_is_enabled(void) { return ((__insn_mfspr(SPR_SIM_CONTROL) & SIM_PROFILER_ENABLED_MASK) != 0); } /** * Reset profiling counters to zero for the current task. * * Resetting can be done while profiling is enabled. It does not affect * the chip-wide profiling counters. */ static __inline void sim_profiler_clear(void) { __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PROFILER_CLEAR); } /** * Enable specified chip-level profiling counters. * * Does not affect the per-task profiling counters. * * @param mask Either this special value: * * SIM_CHIP_ALL (enables all chip-level components). * * or the bitwise OR of these values: * * SIM_CHIP_MEMCTL (enable all memory controllers) * SIM_CHIP_XAUI (enable all XAUI controllers) * SIM_CHIP_MPIPE (enable all MPIPE controllers) */ static __inline void sim_profiler_chip_enable(unsigned int mask) { __insn_mtspr(SPR_SIM_CONTROL, SIM_PROFILER_CHIP_ENABLE_SPR_ARG(mask)); } /** * Disable specified chip-level profiling counters. * * Does not affect the per-task profiling counters. * * @param mask Either this special value: * * SIM_CHIP_ALL (disables all chip-level components). * * or the bitwise OR of these values: * * SIM_CHIP_MEMCTL (disable all memory controllers) * SIM_CHIP_XAUI (disable all XAUI controllers) * SIM_CHIP_MPIPE (disable all MPIPE controllers) */ static __inline void sim_profiler_chip_disable(unsigned int mask) { __insn_mtspr(SPR_SIM_CONTROL, SIM_PROFILER_CHIP_DISABLE_SPR_ARG(mask)); } /** * Reset specified chip-level profiling counters to zero. * * Does not affect the per-task profiling counters. * * @param mask Either this special value: * * SIM_CHIP_ALL (clears all chip-level components). * * or the bitwise OR of these values: * * SIM_CHIP_MEMCTL (clear all memory controllers) * SIM_CHIP_XAUI (clear all XAUI controllers) * SIM_CHIP_MPIPE (clear all MPIPE controllers) */ static __inline void sim_profiler_chip_clear(unsigned int mask) { __insn_mtspr(SPR_SIM_CONTROL, SIM_PROFILER_CHIP_CLEAR_SPR_ARG(mask)); } /* * Event support. */ #ifndef __DOXYGEN__ static __inline void sim_event_begin(unsigned int x) { #if defined(__tile__) && !defined(__NO_EVENT_SPR__) __insn_mtspr(SPR_EVENT_BEGIN, x); #endif } static __inline void sim_event_end(unsigned int x) { #if defined(__tile__) && !defined(__NO_EVENT_SPR__) __insn_mtspr(SPR_EVENT_END, x); #endif } #endif /* !__DOXYGEN__ */ #endif /* !__ASSEMBLER__ */ #endif /* !__ARCH_SIM_H__ */ /** @} */