9 Processor API 9.2 Simics API Functions
API Reference Manual  /  9 Processor API  / 

9.1 Interfaces

This section lists the interfaces that can be implemented by the processor model to enable certain Simics features. They are not required, but implementing them will allow user defined processor models to support the same generic feature set as Simics standard processor models. If you intend to plug your model into an existing Simics-provided platform, then many of these interfaces are actually required for such a platform to function.

Processor Info Interface

The processor_info_v2 interface is implemented by processors models. The interface has processor generic functions that are architecture independent.

The disassemble function returns the disassemble string for an instruction at address with opcode according to instruction_data. The instruction_data is an attr_value_t value of data type with the bytes of the opcode. The bytes are in the same order as they are stored in memory. For VLIW architectures, sub_operation is used to select which sub-operation to disassemble. The sub-operations start at zero, and a request for the entire unit including all sub-operations is encoded with sub-operation -1. A request for a sub-operation that is not present (for example when sub-operation is neither 0 nor -1 for non-VLIW architectures) results in the integer part of the return tuple being set to zero. If successful, the function should return a tuple with the size of the instruction in bytes and the disassembly string. The disassembly string should be allocated with MM_MALLOC or similar and is to be freed by the caller. If more bytes are needed, then the function should indicate that by returning a negative number in the tuple where the absolute value of the number is the required number of bytes. The string should be NULL if more bytes are needed. The implementor of processor_info_v2 is allowed to request one additional byte at a time until enough bytes are passed to determine what the instruction is. Illegal instructions should still result in a valid returned tuple, where the integer part will be used by the disassemble command to skip that many bytes before disassembling the next instruction. The address can be used to display absolute destinations of program counter relative branches.

The set_program_counter function sets the program counter in the processor. The get_program_counter function returns the current program counter.

The logical_to_physical function translates a logical address to a physical address of the type defined by access_type. The function returns a physical_block_t struct with valid bit and the address. The address is valid when the valid bit is not 0. The logical_to_physical function also returns block_start and block_end. The start and end of a block has the same logical to physical transformation as the translated address. The range is inclusive, so block_end should be the address of the last byte of the block. This information can be used to figure out how often the logical_to_physical function needs to be called. An implementation would typically return the page start and end here, but it is free to return any power of 2 sized block as long as it includes the translated address.

The current operating mode of the processor is returned with get_processor_mode.

The processor can be enabled or disabled with the enable_processor or disable_processor functions. The functions should return 0 if the processor changed from enabled to disabled or from disabled to enabled, and 1 if the processor did not change state. The current state is returned by the get_enabled function. Enabled or disabled here refers to the state that the user of the model has put the processor into. In particular, it is independent of the power mode of the processor. A processor that has powered down does not count as disabled in this sense, nor does the enable_processor wake up a processor that is in a power-saving sleep state.

The endianness of the processor is returned by the get_endian function.

The physical memory object is returned by the get_physical_memory function. The object returned by get_physical_memory is used to set breakpoints by the global break command, and to read and write physical memory through set, get, load-binary, load-file, and the default implementation of disassemble. The object returned implements the memory_space and breakpoint interfaces. The memory_space interface for the returned object is only be used in inquiry mode corresponding to actions by the simulator itself rather than by the simulated software. An implementation may return NULL from this method, which will lead to the command listed above not being supported when such a processor is selected.

The get_logical_address_width function returns the number of logical/virtual address bits and the get_physical_address_width function returns the number of physical address bits.

The processor architecture is returned by calling the architecture function. The architecture should be one of arm, mips32, mips64, ppc32, ppc64, sparc-v8, sparc-v9, x86, x86-64, or something else if none of the listed is a good match.

All functions in the interface are optional. Each function can be set to NULL if it is not supported.

SIM_INTERFACE(processor_info_v2) {
        tuple_int_string_t (*disassemble)(conf_object_t *obj,
                                          generic_address_t address,
                                          attr_value_t instruction_data,
                                          int sub_operation);
        void (*set_program_counter)(conf_object_t *obj,
                                    logical_address_t pc);
        logical_address_t (*get_program_counter)(conf_object_t *obj);
        physical_block_t (*logical_to_physical)(conf_object_t *obj,
                                                logical_address_t address,
                                                access_t access_type);
        processor_mode_t (*get_processor_mode)(conf_object_t *obj);
        int (*enable_processor)(conf_object_t *obj);
        int (*disable_processor)(conf_object_t *obj);
        int (*get_enabled)(conf_object_t *obj);

        cpu_endian_t (*get_endian)(conf_object_t *obj);
        conf_object_t *(*get_physical_memory)(conf_object_t *obj);

        int (*get_logical_address_width)(conf_object_t *obj);
        int (*get_physical_address_width)(conf_object_t *obj);

        const char *(*architecture)(conf_object_t *obj);
};

#define PROCESSOR_INFO_V2_INTERFACE "processor_info_v2"

Note that the original version of this interface (processor_info) must also be implemented. The only difference between the two interfaces is that the original version lacks the get_processor_mode function.

Processor CLI Interface

Some commands and features in the CLI use the processor_cli interface. Those commands will have limited functionality if the interface is not fully implemented.

The first argument to each function is the object to act on. This object should implement both the processor_info interface and the processor_cli interface.

The get_disassembly function is used for the disassemble command as well as to disassemble the next instruction to be executed, when control is returned to the CLI prompt. For most architectures, get_disassembly can be set to NULL, in which case the command will use other interfaces to provide a generic disassembly. The get_disassembly function should return a tuple with the length of the instruction in bytes and the disassembly string. The addr_prefix parameter selects the address type of the address parameter, whether it is a physical address ("p"), a linear address ("l") or a virtual address ("v"), just as returned from get_address_prefix. The address parameter is the program counter for the instruction to disassemble. If print_cpu is non-zero, then the name of the processor should be included first in the disassembly line. If mnemonic is not NULL, then it should be output instead of the instruction disassemble. The mnemonic is used to print exception or interrupt information as returned by the get_pending_exception_string function.

get_pregs returns the string to output in the CLI for the print-processor-registers command. The all parameter is a boolean corresponding to the -all switch to the print-processor-registers command.

The diff_regs function is used by the stepi command when the -r flag is used. The diff_regs function returns a list of register names, where each register in that list will be read through the int_register interface before and after an instruction.

When returning to the CLI prompt, information about the next instruction or step to execute is printed. Normally, that is the disassemble of the instruction at the current program counter. The get_pending_exception_string function is called before the disassembly to find out if the next step will not be an instruction, but rather a taken exception or interrupt. The function should inspect the given cpu (an object implementing processor_info and processor_cli) and return NULL if the next step will be the execution of the instruction at the current program counter. If the next step will instead be the handling of an exception or interrupt, then a string saying that should be returned.

The get_address_prefix function returns a string with the default address prefix for memory related commands. Simics defines the generic prefixes "v" for virtual addresses, "l" for linear addresses, and "p" for physical addresses. The default if get_address_prefix is NULL is "v" for virtual addresses.

translate_to_physical translates an address to a physical address. If translate_to_physical is NULL, then the only allowed address prefixes are "v" (virtual) and "p" (physical), and the logical_to_physical function in the processor_info interface will be used to translate virtual addresses.

SIM_INTERFACE(processor_cli) {
	tuple_int_string_t (*get_disassembly)(conf_object_t *obj,
                                              const char *addr_prefix,
                                              generic_address_t address,
                                              bool print_cpu,
                                              const char *mnemonic);
	char *(*get_pregs)(conf_object_t *cpu,
                           bool all);
	attr_value_t (*get_diff_regs)(conf_object_t *obj);
	char *(*get_pending_exception_string)(conf_object_t *obj);
	char *(*get_address_prefix)(conf_object_t *obj);
	physical_block_t (*translate_to_physical)(conf_object_t *obj,
                                                  const char *prefix,
                                                  generic_address_t address);
};

#define PROCESSOR_CLI_INTERFACE "processor_cli"

Processor GUI Interface

The processor_gui interface is implemented by processors that support displays in the Simics native GUI. It is only registered to indicate support for the displays, and does not contain any actual functionality.

SIM_INTERFACE(processor_gui) {
        void (*dummy)(conf_object_t *obj);
};

#define PROCESSOR_GUI_INTERFACE "processor_gui"

Step Interface

The step interface is typically implemented by processors, but can be implemented by other objects as well. Its purpose is to handle step events using a queue.

The current number of steps for the queue is returned when calling get_step_count.

The post_step function will schedule an event that will occur after steps (which must be nonnegative) counted from local current step at queue. An event previously posted can be removed by calling cancel_step. The cancel_step function takes a function pred as argument which is called when a matching event is found. The event is only removed if pred returns 1. The find_next_step takes the same arguments as cancel_step but only returns the number of cycles before the event will occur. The evclass is the event class, obj is the object posting the event, and user_data is pointer to data used as a parameter when calling the callback function defined in the evclass. If no matching event was found, find_next_step returns −1.

The events method returns a list of all pending events in expiration order. Each element is a four-element list containing the event object, the event class name, the expiration time counted in steps as an integer and the event description as given by the event class describe method, or nil for events whose event class do not define that method.

The advance function will increment the number of steps for the queue, decrementing the number of steps to the first event to the value defined by steps. The number of steps remaining to the next event is returned. It is an error to advance beyond the next pending event, so the return value is never negative.

The implementor of the step interface can use any checkpoint representation. The name field in the event class data structure is unique, and the attribute setter function for checkpoint restore can use VT_get_event_class to get the event class structure corresponding to an event class name.

SIM_INTERFACE(step) {
        pc_step_t (*get_step_count)(conf_object_t *NOTNULL queue);
        void (*post_step)(
                conf_object_t *NOTNULL queue,
                event_class_t *NOTNULL evclass,
                conf_object_t *NOTNULL obj,
                pc_step_t steps,
                lang_void *user_data);
        void (*cancel_step)(
                conf_object_t *NOTNULL queue,
                event_class_t *NOTNULL evclass,
                conf_object_t *NOTNULL obj,
                int (*pred)(lang_void *data, lang_void *match_data),
                lang_void *match_data);
        pc_step_t (*find_next_step)(
                conf_object_t *NOTNULL queue,
                event_class_t *NOTNULL evclass,
                conf_object_t *NOTNULL obj,
                int (*pred)(lang_void *data, lang_void *match_data),
                lang_void *match_data);

        attr_value_t (*events)(conf_object_t *NOTNULL obj);

        pc_step_t (*advance)(conf_object_t *queue, pc_step_t steps);
};

#define STEP_INTERFACE "step"

Step-Cycle-Ratio Interface

The step_cycle_ratio interface is implemented by processors that support a changeable ratio between steps and cycles. The set-step-rate command uses this interface to set the ratio between steps and cycles.

The set_ratio sets the ratio between steps and cycles. Note that the introduction of stall cycles can skew the ratio. The get_ratio simply returns the current ratio.

The cycles and step arguments must be in the range [1..128] and cycles must be a power of two. Implementers of this interface may choose to ignore other values of cycles and step and may log an error.

typedef struct {
        uint32 steps;
        uint32 cycles;
} step_cycle_ratio_t;

SIM_INTERFACE(step_cycle_ratio) {
        step_cycle_ratio_t (*get_ratio)(conf_object_t *obj);
        void (*set_ratio)(conf_object_t *obj, uint32 steps, uint32 cycles);
};

#define STEP_CYCLE_RATIO_INTERFACE "step_cycle_ratio"

Stall Interface

The stall interface can be implemented by objects that also implement the cycle and step interfaces. The stall interface controls the addition of extra cycles between steps.

The get_stall_cycles function returns the remaining number of stall cycles. The object will advance that number of cycles before starting with the next step.

The set_stall_cycles function is used to change the number of stall cycles before the next step. It is legal to first call this function with a large value for cycles and then at a later point reduce the cycle count is resume execution earlier than indicated by the first call.

The get_total_stall_cycles returns the total accumulated number of stall cycles.

SIM_INTERFACE(stall) {
        cycles_t (*get_stall_cycles)(conf_object_t *obj);
        void (*set_stall_cycles)(conf_object_t *obj, cycles_t cycles);
        cycles_t (*get_total_stall_cycles)(conf_object_t *obj);
};
#define STALL_INTERFACE "stall"

Register Interface

The int_register interface is used for access to registers in a processor. It can be used to access any kind of integer register, not only the "normal" registers. This includes all kinds of control registers, hidden registers and anything else that might be useful to access as a register. The only limitation is that the register value should be representable as a 64-bit unsigned integer.

This interface can be implemented by other classes than processors, but it is likely to be found mostly in processors.

Registers are identified by a number, and there are two functions to translate from register names to register numbers and back. The translation need not be one-to-one, which means that one register can have several names. A register name can, however, only translate to a single register number.

Often, registers are grouped in register banks, where registers in the bank are numbered from 0 up. Registers in a bank should have consecutive numbers (unless their numbering is very sparse). This allows a user to deduce register numbers by calling get_number for the first register only. The first register numbers should be used for the general-purpose integer registers, if possible (so that integer register rN has number N).

Using this interface to read or write registers does not cause any side effects, such as triggering interrupts or signalling haps.

get_number translates a register name to its number. Returns -1 if the register does not exist.

get_name translates a register number to its canonical name.

read reads a register value.

write writes a new register value.

all_registers returns a list of all register numbers that can be used for this object.

register_info returns information about a single register. The information return depends on the info parameter.

Sim_RegInfo_Catchable
Return 1 if Core_Control_Register_Write and Core_Control_Register_Read are triggered when this register is written or read.
Return 0 otherwise.

typedef enum {
        Sim_RegInfo_Catchable
} ireg_info_t;

SIM_INTERFACE(int_register) {
        int (*get_number)(conf_object_t *NOTNULL obj,
                          const char *NOTNULL name);
        const char *(*get_name)(conf_object_t *NOTNULL obj, int reg);
        uint64 (*read)(conf_object_t *NOTNULL obj, int reg);
        void (*write)(conf_object_t *NOTNULL obj, int reg, uint64 val);
        attr_value_t (*all_registers)(conf_object_t *NOTNULL obj);
        int (*register_info)(conf_object_t *NOTNULL obj, int reg,
                             ireg_info_t info);
};

#define INT_REGISTER_INTERFACE "int_register"

Decoder Interface

SIM_INTERFACE(decoder) {
        void (*register_decoder)(conf_object_t *obj, 
                                 decoder_t *NOTNULL decoder);
        void (*unregister_decoder)(conf_object_t *obj, 
                                   decoder_t *NOTNULL decoder);
};

The decoder interface is implemented by processors that allows connecting user decoders. This allows a user to implement the semantics of instructions that are not available in the standard Simics model or change the semantics of instructions implemented by Simics. This interface replaces SIM_register_arch_decoder and SIM_unregister_arch_decoder functions.

The register_decoder function adds a decoder and unregister_decoder removes a decoder.

The decoder is installed/removed for every object of the same class as the obj argument which must be the same object from which the interface was fetched.

When Simics decodes an instruction, it will first see if any instruction decoders are registered for the current CPU class. For any decoders it finds, Simics will let it try to decode the instruction. The decoders are called in order, starting with the last registered decoder, and if one decoder accepts the instruction, the rest of the decoders will not be called.

The decoder is specified by the decoder_t data structure that the user supplies:

typedef struct {
        void *user_data;
        int (*NOTNULL decode)(uint8 *code,
                              int valid_bytes,
                              conf_object_t *cpu,
                              instruction_info_t *ii,
                              void *user_data);
        tuple_int_string_t (*NOTNULL disassemble)(uint8 *code,
                                                  int valid_bytes,
                                                  conf_object_t *cpu,
                                                  void *user_data);
        int (*NOTNULL flush)(instruction_info_t *ii,
                             void *user_data);
} decoder_t;

The decode function is called to decode an instruction pointed to by code. The first byte corresponds to the lowest address of the instruction in the simulated memory. valid_bytes tells how many bytes can be read. The CPU is given in the cpu parameter. When the decoder has successfully decoded an instruction, it should set the ii_ServiceRoutine, the ii_Arg, and the ii_Type members of the ii structure (see below), and returns the number of bytes used in the decoding. If it does not apply to the given instruction, it should return zero. If the decoder needs more data than valid_bytes it should return a negative number corresponding to the total number of bytes it will need to continue the decoding. The underlying architecture limits the number of bytes that can be requested, e.g. no more than 4 bytes can be requested on most RISC architectures. Simics will call the decoder again when more bytes are available. This process is repeated until the decoder accepts or rejects the instruction. A decoder should never request more data than it needs. For example, if an instructions can be rejected by looking at the first byte, the decoder should never ask for more bytes.

The instruction_info_t is defined as follows:

typedef struct instruction_info {
        service_routine_t  ii_ServiceRoutine;
        uint64             ii_Arg;
        unsigned int       ii_Type;
        lang_void         *ii_UserData;
        logical_address_t  ii_LogicalAddress;
        physical_address_t ii_PhysicalAddress;
} instruction_info_t;

ii_ServiceRoutine is a pointer to a function that will be called by Simics every time the instruction is executed. It has the following prototype:

typedef exception_type_t (*service_routine_t)(conf_object_t *cpu, 
                                              uint64 arg,
                                              lang_void *user_data);

The service routine function should return an exception when it is finished to signal its status. If no exception occurs Sim_PE_No_Exception should be returned.

See exception_type_t in src/include/simics/base/memory.h for the different exceptions available.

A special return value, Sim_PE_Default_Semantics, can be returned; this signals Simics to run the default semantics for the instruction. This is useful if the semantics of an instruction should be changed but the user routine does not want to handle it all the time.

Note that in a shared memory multiprocessor, the CPU used in decoding may differ from the CPU that executes the instruction, since the decoded instructions may be cached.

ii_Arg is the argument arg that will be passed on to the service routine function. Op code bit-fields for the instruction such as register numbers or intermediate values can be stored here. The ii_UserData field can also be used to pass information to the service routine if more data is needed.

ii_Type is either UD_IT_SEQUENTIAL or UD_IT_CONTROL_FLOW. A sequential type means that the instruction does not perform any branches and the update of the program counter(s) is handled by Simics. In a control flow instruction on the other hand it is up to the user to set the program counter(s).

ii_LogicalAddress and ii_PhysicalAddress holds the logical and physical addresses of the instruction to be decoded.

The disassemble function is called to disassemble an instruction. It uses the same code, valid_bytes, and cpu parameters as the decode function. If the disassembly is valid, then the string part of the returned tuple_int_string_t struct should be a MALLOCed string with the disassembly and the integer part should be its length in bytes. The caller is responsible for freeing the disassembly string. The string member should be NULL and the integer part should be zero if the disassembly is not valid. If the disassemble function needs more data than valid_bytes it should return a negative number in the integer part in the same way as the decode function, and set the string part to NULL.

The flush function is called to free any memory allocated when decoding an instruction and any user data associated with the instruction. It should return zero if it does not recognize the instruction, and non-zero if it has accepted it. Usually, the way to recognize if a decoded instruction is the right one to flush is to compare ii->ii_ServiceRoutine with the function that was set in the decode function. Note that the cpu parameter is the processor that caused the flush. It is more or less an arbitrary processor and should be ignored.

In addition to the function pointers, the decoder_t structure contains a user_data pointer that is passed to all the functions. This can be used for passing any data to the decoder functions.

Exception Interface

The exception interface is used together with the Core_Exception hap to enable inspection abilities for triggered exceptions.

The exception interface is used to translate exception numbers, as received by the Core_Exception hap, to names, and vice versa.

The get_number function returns the number associated with an exception name, or -1 if the no exception with the given name exist. The get_name returns the name associated with an exception number. The get_source function is only used on X86 targets and returns the source for an exception, as an exception number can be raised from different sources. The all_exceptions function returns a list of all exceptions numbers.

The exception numbers are architecturally defined, while their names are defined by the model.

SIM_INTERFACE(exception) {
        int (*get_number)(conf_object_t *NOTNULL obj,
                          const char *NOTNULL name);
        const char *(*get_name)(conf_object_t *NOTNULL obj, int exc);
        int (*get_source)(conf_object_t *NOTNULL obj, int exc);
        attr_value_t (*all_exceptions)(conf_object_t *NOTNULL obj);
};

#define EXCEPTION_INTERFACE "exception"

Context Handler Interface

Note: This interface is not supported, and may change in the future.
Get and set current context. The set_current_context function returns zero if the passed object is not of the context class, otherwise one is returned.

SIM_INTERFACE(context_handler) {
        conf_object_t *(*get_current_context)(conf_object_t *obj);
        int (*set_current_context)(conf_object_t *obj, conf_object_t *ctx);
};

#define CONTEXT_HANDLER_INTERFACE "context_handler"

Exec Trace Interface

The exec_trace interface is implemented by processor models that support tracing. A trace listener registers itself with the register_tracer call. The tracer callback will be called by the processor model when each instruction is just about to be executed, passing the tracer_data as passed to the register_tracer function in addition to information about the instruction that is executed. Invoke unregister_tracer with the same two pointers to deregister the listener.

typedef void (*instruction_trace_callback_t)(lang_void *tracer_data,
                                             conf_object_t *cpu,
                                             linear_address_t la,
                                             logical_address_t va,
                                             physical_address_t pa,
                                             byte_string_t opcode);

The pa parameter to the callback will always be valid, but some CPU architectures may not support la or va. The la argument is typically only valid for x86 CPUs. Lastly, the opcode of the instruction is passed in opcode. The opcode is passed without endian conversion, meaning that byte X in opcode corresponds to the byte at pa + X.

SIM_INTERFACE(exec_trace) {
        void (*register_tracer)(conf_object_t *NOTNULL cpu_obj,
                                instruction_trace_callback_t tracer,
                                lang_void *tracer_data);
        void (*unregister_tracer)(conf_object_t *NOTNULL cpu_obj,
                                  instruction_trace_callback_t tracer,
                                  lang_void *tracer_data);
};

#define EXEC_TRACE_INTERFACE "exec_trace"

Opcode Info Interface

The opcode_info interface is implemented by processors that need to communicate information about the encoding of instructions to the GUI.

The get_opcode_length function returns information about instruction encoding in the current operating mode of the processor. The min_alignment field indicates the smallest allowed alignment of instructions, typically 4 for regular RISC architectures. The max_length field specifies the maximum instruction length in bytes. The avg_length is an approximation of the average instruction size.

typedef struct {
        int min_alignment;
        int max_length;
        int avg_length;
} opcode_length_info_t;

SIM_INTERFACE(opcode_info) {
        opcode_length_info_t (*get_opcode_length_info)(conf_object_t *obj);
};

#define OPCODE_INFO_INTERFACE "opcode_info"

Virtual Data Breakpoint Interface

Add and remove virtual-address (and, on x86, linear-address) read and write breakpoints. On every read access that intersects a read breakpoint's interval, the registered callback function is called with the object that initiated the read, and the address and size of the read. (The interval includes both endpoints; first must be less than or equal to last.) Write breakpoints work exactly the same, except that the callback is given the actual value being written, not just its size.

The callback is called before the read or write has taken place, but may not intervene. If one or more breakpoint callbacks stop the simulation, the current instruction is completed before the stop takes effect. If more than one breakpoint is triggered by the same read or write, the implementation may call their callbacks in any order.

On x86, the Virtual_Breakpoint_Flag_Linear flag causes the breakpoint to use linear rather than virtual addresses. (Adding a breakpoint with unsupported flags is illegal.)

Note: This interface is preliminary and may change without prior notice.
typedef enum {
        Virtual_Breakpoint_Flag_Linear = 1
} virtual_breakpoint_flags_t;

SIM_INTERFACE(virtual_data_breakpoint) {
        virtual_data_bp_handle_t *NOTNULL (*add_read)(
                conf_object_t *NOTNULL obj,
                generic_address_t first, generic_address_t last,
                void (*NOTNULL callback)(
                        cbdata_call_t data, conf_object_t *NOTNULL initiator,
                        generic_address_t address, unsigned size),
                cbdata_register_t data, uint32 flags);
        virtual_data_bp_handle_t *NOTNULL (*add_write)(
                conf_object_t *NOTNULL obj,
                generic_address_t first, generic_address_t last,
                void (*NOTNULL callback)(
                        cbdata_call_t data, conf_object_t *NOTNULL initiator,
                        generic_address_t address, bytes_t value),
                cbdata_register_t data, uint32 flags);
        void (*remove)(conf_object_t *NOTNULL obj,
                       virtual_data_bp_handle_t *NOTNULL bp_handle);
};
#define VIRTUAL_DATA_BREAKPOINT_INTERFACE "virtual_data_breakpoint"

Virtual Instruction Breakpoint Interface

Add and remove virtual-address (and, on x86, linear-address) instruction breakpoints. Every time the processor executes an instruction that intersects the breakpoint's interval, the callback function is called with the processor, and the address and size of the instruction. (The interval includes both endpoints; first must be less than or equal to last.)

The callback is called before the instruction is executed. If one or more breakpoint callbacks stop the simulation, the stop takes effect before the instruction is run. (This means that once the simulation starts again, the same breakpoints will trigger immediately again. The callback can use VT_step_stamp to detect re-triggering.) If more than one breakpoint is triggered by the same instruction, the implementation may call their callbacks in any order.

If the filter function is non-null and returns false, the callback is not called. The filter function is supplied with the instruction opcode (the raw bytes of the instruction) and a processor (which may not be the same processor that the breakpoint is set on, but is guaranteed to be of the same class). The filter may base its decision only on the opcode bytes and the string obtained by asking the processor to disassemble the instruction; this allows the implementation to cache the result and omit future calls to the filter function where the opcode and disassembly string would be the same.

On x86, the Virtual_Breakpoint_Flag_Linear flag causes the breakpoint to use linear rather than virtual addresses. Calling with unsupported flags is illegal.

Note: This interface is preliminary and may change without prior notice.
typedef enum {
        Virtual_Breakpoint_Flag_Linear = 1
} virtual_breakpoint_flags_t;

SIM_INTERFACE(virtual_instruction_breakpoint) {
        virtual_instr_bp_handle_t *NOTNULL (*add)(
                conf_object_t *NOTNULL obj,
                generic_address_t first, generic_address_t last,
                bool (*filter)(cbdata_call_t filter_data,
                               conf_object_t *NOTNULL cpu, bytes_t opcode),
                cbdata_register_t filter_data,
                void (*NOTNULL callback)(
                        cbdata_call_t callback_data, conf_object_t *NOTNULL cpu,
                        generic_address_t address, unsigned size),
                cbdata_register_t callback_data, uint32 flags);
        void (*remove)(conf_object_t *NOTNULL obj,
                       virtual_instr_bp_handle_t *NOTNULL bp_handle);
};
#define VIRTUAL_INSTRUCTION_BREAKPOINT_INTERFACE \
        "virtual_instruction_breakpoint"

Describe Registers Interface

This interface is used by the Simics debugger to get certain information from a processor.

The first_child function returns the first description in the sequence of child descriptions of parent or NULL if parent has no children. Groups can have both registers and groups as children, registers can only have fields as children and fields cannot have any children. If parent is NULL, return the first description in the sequence of top-level descriptions.

Use next_description to deallocate the previous description and return the next description in the sequence or NULL if there are no more descriptions in the current sequence.

The free_description function is used to free the description without returning the next one in the sequence.

The first_named_value function returns the first named value in the sequence of named values for parent or NULL if there are no named values for parent. Only fields and registers can have named values.

Use next_named_value to deallocate the previous named value and return the next named value or NULL if there are no more named values in this sequence.

Use free_named_value to free the named value without returning the next one in the sequence.

The get and set functions are used to get and set the value of the register. To set the value pass in a bytes_t for the value. The value passed in must be long enough to contain the full value of the register. If the bytes_t is too long it will be truncated. To get the value pass in a buffer_t which is long enough to contain the register's value. The value is encoded in little endian byte order.

typedef enum {
        Description_Type_Group,

        Description_Type_Int_Reg,
        Description_Type_Float_Reg,
        Description_Type_Fields_Reg,

        Description_Type_Int_Field,
        Description_Type_Float_Field,
} description_type_t;

typedef enum {
        Reg_Role_None, /* No special role for the register. */
        Reg_Role_Program_Counter /* The register is the program counter. */
} reg_role_t;

typedef enum {
        Reg_Bitorder_Little_Endian,
        Reg_Bitorder_Big_Endian
} reg_bitorder_t;

typedef struct {
        const char *name;
        const char *description;
        const bytes_t value; /* Little endian byte order */
} named_value_t;

typedef struct {
        /* Common fields */
        description_type_t type;
        const char *name;
        const char *description;

        /* Register and field fields */
        int16 dwarf_id;            /* id used by dwarf for this register
                                      or -1 if no such id is defined. This
                                      is ABI specific, but the CPU will
                                      give the ids for the most common ABI
                                      for that architecture. */
        reg_bitorder_t bitorder;   /* Bitorder convention used in the
                                      documentation for this register or
                                      field. */
        reg_role_t role;           /* Role of this register in the ABI/HW. */
        bool memory_mapped;        /* True if the register is memory mapped. */
        uint64 offset;             /* Offset into the bank for memory mapped
                                      registers. */
        bool catchable;            /* True if Core_Control_Register_Write and
                                      Core_Control_Register_Read are triggered
                                      when this register is written or read. */
        int msb, lsb;              /* Most and least significant bit of the
                                      register or field. Always given in le
                                      bitorder. For groups msb == -1 and
                                      lsb == 0. */
        int regsize;               /* Number of bits in the register, or the
                                      register this field is a part of. */
        int reg_id;                /* For registers and fields the id to pass
                                      to the get and set methods to access the
                                      register's value. Fields have the same
                                      reg_id as the register they are a part
                                      of. Not valid for groups.*/
} description_t;

SIM_INTERFACE(describe_registers) {
        const description_t *(*first_child)(
                conf_object_t *NOTNULL obj, const description_t *parent);
        const description_t *(*next_description)(
                conf_object_t *NOTNULL obj, const description_t *prev);
        void (*free_description)(conf_object_t *NOTNULL obj,
                                 const description_t *desc);
        const named_value_t *(*first_named_value)(
                conf_object_t *NOTNULL obj, const description_t *parent);
        const named_value_t *(*next_named_value)(
                conf_object_t *NOTNULL obj, const named_value_t *prev);
        void (*free_named_value)(conf_object_t *NOTNULL obj,
                                 const named_value_t *nv);
        void (*get)(conf_object_t *NOTNULL obj, int reg_id, buffer_t dest);
        void (*set)(conf_object_t *NOTNULL obj, int reg_id, bytes_t value);
};

#define DESCRIBE_REGISTERS_INTERFACE "describe_registers"

9 Processor API 9.2 Simics API Functions