1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//! Control of the base simulator
use crate::{
simics_exception,
sys::{
pc_step_t, SIM_break_cycle, SIM_break_message, SIM_break_simulation, SIM_break_step,
SIM_continue, SIM_quit, SIM_shutdown, SIM_simics_is_running,
},
ConfObject, Result,
};
use raw_cstr::raw_cstr;
/// Alias for `pc_step_t`
pub type PcStep = pc_step_t;
#[simics_exception]
/// Continue the simulation.
///
/// Run the simulation. In typical usage with steps being 0, the simulation will run
/// forward until it is stopped, either by a breakpoint, internal event, or through the
/// user interface.
///
/// With a non-zero steps, Simics will make sure that at least one processor runs steps
/// steps and then stop the simulation. As with steps being 0, the function can also
/// return early if other break criteria are met.
///
/// In order to properly control when simulation stops in time, it is advisable to use
/// step or cycle breakpoints on one or more objects.
///
/// The function returns non-zero if the simulation was started, and 0 otherwise.
///
/// This typically needs to be run in global scope using:
///
/// ```rust,ignore
/// use simics::api::{continue_simulation, run_alone};
///
/// run_alone(|| { continue_simulation(); });
/// ```
///
/// # Arguments
///
/// * `steps` - Zero to run until stopped, or a number of steps to cintinue for
///
/// # Context
///
/// Global Context
pub fn continue_simulation(steps: i64) -> PcStep {
unsafe { SIM_continue(steps) }
}
#[simics_exception]
/// Check whether SIMICS is currently running
///
/// Returns true if the simulation is running, e.g. if it has been started using
/// continue_simulation, or false otherwise. It also returns true when the simulation is
/// reversing.
///
/// # Context
///
/// Cell Context
pub fn simics_is_running() -> bool {
unsafe { SIM_simics_is_running() }
}
#[simics_exception]
/// Stop the simulation with a message
///
/// Ask Simics to stop the simulation as soon as possible, displaying the supplied
/// message.
///
/// Simics will normally stop before the next instruction is executed. If this function
/// is called when an instruction has started executing, and the instruction can be
/// aborted, it will rewind to before the instruction. This might leave the simulation
/// in a state where some repeatable part of the instruction is already executed.
///
/// # Context
///
/// Cell Context
pub fn break_simulation<S>(msg: S) -> Result<()>
where
S: AsRef<str>,
{
unsafe { SIM_break_simulation(raw_cstr(msg.as_ref())?) };
Ok(())
}
#[simics_exception]
/// Set the message whhen SIMICs next breaks execution
///
/// Display the reason why Simics will stop simulation. This is similar to
/// break_simulation, with the difference that it doesn't actually break the
/// simulation. It can be used by code that wants to display a break message and stop
/// the simulation by some other means.
///
/// # Context
///
/// Cell Context
pub fn break_message<S>(msg: S) -> Result<()>
where
S: AsRef<str>,
{
unsafe { SIM_break_message(raw_cstr(msg)?) };
Ok(())
}
#[simics_exception]
/// Shutdown simics gracefully without exiting the process.
///
/// Perform the same clean up as quit, but do not exit the process. After having
/// called this function, no Simics API function can be called.
///
/// # Context
///
/// Cell Context
pub fn shutdown() {
unsafe { SIM_shutdown() };
}
#[simics_exception]
/// Quit simics and exit with a code
///
/// Quit Simics in an orderly fashion. The Simics process will return the value
/// exit_code. See the Core_Clean_At_Exit and Core_At_Exit haps for ways to run user
/// code when Simics exits. Callbacks for the Core_Clean_At_Exit hap will only run if
/// quit is called from Global Context, while Core_At_Exit is always called.
///
/// # Context
///
/// Cell Context
pub fn quit(exit_code: i32) {
unsafe {
SIM_quit(exit_code);
}
}
#[simics_exception]
/// Insert a breakpoint event at cycles clock cycles from now, causing simulation to
/// stop when reached by obj.
///
/// # Arguments
///
/// * `obj` - The object whose cycles will be monitored to break on
/// * `cycles` - The number of cycles until the break occurs
///
/// # Context
///
/// _Cell Context_
pub fn break_cycle(obj: *mut ConfObject, cycles: i64) {
unsafe { SIM_break_cycle(obj, cycles) };
}
#[simics_exception]
/// Sets a step breakpoint on a processor.
///
/// # Arguments
///
/// * `obj` - The object whose steps will be monitored to break on
/// * `steps` - The number of instructions until the break occurs
///
/// # Exceptions
///
/// * [`SimException::SimExc_InterfaceNotFound`] - Thrown if the obj object doesn't implement the step
/// interface.
///
/// # Context
///
/// _Cell Context_
pub fn break_step(obj: *mut ConfObject, steps: i64) {
unsafe { SIM_break_step(obj, steps) };
}