Struct lc3_ensemble::sim::Simulator

source ·
pub struct Simulator {
    pub mem: Mem,
    pub reg_file: RegFile,
    pub pc: u16,
    pub frame_stack: FrameStack,
    pub instructions_run: u64,
    pub flags: SimFlags,
    pub breakpoints: BreakpointList,
    /* private fields */
}
Expand description

Executes assembled code.

Fields§

§mem: Mem

The simulator’s memory.

Note that this is held in the heap, as it is too large for the stack.

§reg_file: RegFile

The simulator’s register file.

§pc: u16

The program counter.

§frame_stack: FrameStack

The frame stack.

§instructions_run: u64

The number of instructions successfully run since this Simulator was initialized.

This can be set to 0 to reset the counter.

§flags: SimFlags

Configuration settings for the simulator.

These are preserved between resets.

See SimFlags for more details on what configuration settings are available.

§breakpoints: BreakpointList

Breakpoints for the simulator.

Implementations§

source§

impl Simulator

source

pub fn new(flags: SimFlags) -> Self

Creates a new simulator with the provided initializers and with the OS loaded, but without a loaded object file.

source

pub fn load_os(&mut self)

Loads and initializes the operating system.

Note that this is done automatically with Simulator::new.

This will initialize kernel space and create trap handlers, however it will not load working IO. This can cause IO traps such as GETC and PUTC to hang. The only trap that is assured to function without IO is HALT.

To initialize the IO, use Simulator::open_io.

source

pub fn reset(&mut self)

Resets the simulator.

This resets the state of the Simulator back to before any execution calls, while preserving configuration and debug state.

Note that this function preserves:

  • Flags
  • Breakpoints
  • External interrupts
  • MCR reference (i.e., anything with access to the Simulator’s MCR can still control it)
  • IO (however, note that it does not reset IO state, which must be manually reset)

This also does not reload object files. Any object file data has to be reloaded into the Simulator.

source

pub fn open_io<IO: Into<SimIO>>(&mut self, io: IO)

Sets and initializes the IO handler.

source

pub fn close_io(&mut self)

Closes the IO handler, waiting for it to close.

source

pub fn load_obj_file(&mut self, obj: &ObjectFile)

Loads an object file into this simulator.

source

pub fn psr(&self) -> &PSR

Gets a reference to the PSR.

source

pub fn mcr(&self) -> &Arc<AtomicBool>

Gets a reference to the MCR.

source

pub fn set_pc( &mut self, addr_word: Word, st_check_mem: bool ) -> Result<(), SimErr>

Sets the PC to the given address, raising any errors that occur.

The st_check_mem parameter indicates whether the data at the PC should be verified in strict mode. This should be enabled when it is absolutely known that the PC will read from the provided address on the next cycle.

This should be true when this function is used for instructions like BR and JSR and should be false when this function is used to increment PC during fetch.

source

pub fn offset_pc( &mut self, offset: i16, st_check_mem: bool ) -> Result<(), SimErr>

Adds an offset to the PC.

See Simulator::set_pc for details about st_check_mem.

source

pub fn prefetch_pc(&self) -> u16

Gets the value of the prefetch PC.

This function returns the value of PC before it is incremented druing fetch, which is also the location of the currently executing instruction in memory.

This is useful for pointing to a given memory location in error handling, as this computation always points to the memory location of the instruction.

source

pub fn hit_breakpoint(&self) -> bool

Indicates whether the last execution of the simulator hit a breakpoint.

source

pub fn hit_halt(&self) -> bool

Indicates whether the last execution of the simulator resulted in a HALT successfully occurring.

This is defined as:

  • HALT being executed while virtual HALTs are enabled
  • MCR being set to x0000 during the execution of the program.
source

pub fn default_mem_ctx(&self) -> MemAccessCtx

Computes the default memory access context, which are the default flags to use (see Mem::read and Mem::write).

source

pub fn call_subroutine(&mut self, addr: u16) -> Result<(), SimErr>

Calls a subroutine.

This does all the steps for calling a subroutine, namely:

  • Setting the PC to the subroutine’s start address
  • Setting R7 to the original PC (return address)
  • Adding information to the frame stack
source

pub fn add_external_interrupt( &mut self, interrupt: impl Fn(&Self) -> Result<(), InterruptErr> + Send + Sync + 'static )

Registers an “external interrupt” to the simulator which is run every step.

An “external interrupt” is a function that can pause execution of the Simulator, which is not necessarily handled by the Simulator’s OS.

When an InterruptErr is raised by an external interrupt, the simulation will raise SimErr::Interrupt, which can be used to handle the resulting InterruptErr.

One example where this is used is in Python bindings. In that case, we want to be able to halt the Simulator on a KeyboardInterrupt. However, by default, Python cannot signal to the Rust library that a KeyboardInterrupt has occurred. Thus, we can add a signal handler as an external interrupt to allow the KeyboardInterrupt to be handled properly.

source

pub fn clear_external_interrupts(&mut self)

Clears any external interrupts.

source

pub fn run_while( &mut self, tripwire: impl FnMut(&mut Simulator) -> bool ) -> Result<(), SimErr>

Runs until the tripwire condition returns false (or any of the typical breaks occur).

The typical break conditions are:

  • HALT is executed
  • the MCR is set to false
  • A breakpoint matches
source

pub fn run(&mut self) -> Result<(), SimErr>

Execute the program.

source

pub fn run_with_limit(&mut self, max_steps: u64) -> Result<(), SimErr>

Execute the program with a limit on how many steps to execute.

source

pub fn step_in(&mut self) -> Result<(), SimErr>

Simulate one step, executing one instruction.

source

pub fn step_over(&mut self) -> Result<(), SimErr>

Simulate one step, executing one instruction and running through entire subroutines as a single step.

source

pub fn step_out(&mut self) -> Result<(), SimErr>

Run through the simulator’s execution until the subroutine is exited.

Trait Implementations§

source§

impl Debug for Simulator

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Default for Simulator

source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

source§

fn vzip(self) -> V