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) };
}