The ARMulator
=============


Introduction
------------

The ARMulator is a family of programs which emulate the instruction sets of 
various ARM processors, and their supporting architectures. The programs are 
written in C, and interface directly to user-supplied models written in C or 
C++. An ARMulator suitably equipped to support timing accuracy can be 
integrated into any hardware modelling system which accepts models written in 
C. 

The ARMulator has many uses:

 *  it provides an environment for the development of ARM-targeted software on 
    a range of non ARM-based host systems;

 *  it allows accurate, if somewhat slow compared to real hardware, 
    benchmarking of ARM-targeted software;

 *  it supports the simulation of prototype ARM based systems, ahead of the 
    availability of real hardware, so that software and hardware development 
    can proceed in parallel;

 *  it provides a generic ARM processor core model for incorporation into 
    hardware simulation environments (via the foreign language interfaces to 
    those environments).


Emulation Options
-----------------

There are three levels of accuracy that can be supported:

 *  Instruction-accurate

 *  Cycle-accurate

 *  Timing-accurate

The first of these simply models the instruction set, without regard to the 
precise timing characteristics of the processor. As a result, it is 
considerably faster than the other variants, and is best suited to software 
development and benchmarking.

The second models accurately the signal transitions that would occur on each 
clock cycle around the periphery of the processor core, and is therefore slower 
than the instruction-accurate option.

The final level incorporates a timing veneer around the cycle-accurate model, 
which causes signal transitions to occur at the correct times within a clock 
cycle. At this level, the performance of the emulator becomes heavily dependent 
on the logic simulator into which the model is being integrated.

The rest of this document describes instruction-accurate emulation. Cycle- and 
timing-accurate emulation is discussed in the document <ARMulators for Hardware 
Modelling>, which is available from your supplier upon request.


The ARMulator Environment
-------------------------

An ARMulator consists of four parts:

 1. the model of the ARM  processor, together with various utility functions to 
    support system modelling, and incorporating the Remote Debug Interface;

 2. a memory interface which transfers data  between the ARM model and the 
    memory model or memory management unit model;

 3. a co-processor interface to optional ARM co-processor models;

 4. an operating system interface to provide an execution environment.

Part 1 incorporates the Remote Debug Interface (RDI), which is used to connect 
the ARMulator to the ARM Symbolic Debugger, <armsd>, or to the ARM  Windowing 
Debugger, <armwd>, to provide a hardware-independent, low-level, ARM software 
development environment. The ARMulator communicates with <armsd> and <armwd> 
via the RDI (see "<ARM Remote Debug Interface>" of the 
Technical Specifications for details). This interface is used to control the 
ARMulator.

Example models of memory, a co-processor, and a simple operating system, are 
supplied in source form with the ARMulator distribution.

The file <armdefs.h> defines functions, data structures and useful macros to 
support modelling.


Memory Models
-------------

For instruction-based and program-based emulation, a memory model must be 
constructed to allow the ARMulator to load instructions and to access data. A 
model can be built at two levels, the first designed to allow rapid prototyping 
and the second designed for maximum emulation performance.

An example of each type of model is supplied in source form with the ARMulator. 

The <ARMul_State> structure contains four pointers (type char* in C) that can 
be used by the memory interface to refer to the memory model:

    MemDataPtr;

    MemInPtr;

    MemOutPtr;

    MemSparePtr.

<MemDataPtr> is intended to be used as a pointer to the memory system's private 
data structures, for example to a <Translation Lookaside Buffer>.

<MemInPtr> and <MemOutPtr> are intended to be used to refer to memory attached 
to ARM6's DataInBus and DataOutBus respectively.

<MemSparePtr> is free for any extra data that may require referencing.

If the multiple instantiation property of the ARMulator is to be preserved, 
then it is essential that memory models declare no static data of their own, 
but chain dynamically allocated (<malloc'd>) state-containing structures off 
<MemDataPtr>.

A fifth field in <ARMul_State> structure, <MemSize>, is used by the C run time 
system to find the top of RAM memory. If this value is set then the C user 
stack will descend from this address, otherwise the runtime system will use a 
default value.


High Speed Memory Interface
...........................

To maximise the performance of a memory model (thus maximising the number of 
instructions emulated per second), the following high speed memory interface 
should be used. This interface can distinguish between different sorts of 
memory access using different access functions. Eighteen functions have to be 
implemented (in C):

    unsigned ARMul_MemoryInit(ARMul_State *state, ARMword memory_size)
    unsigned ARMul_MemoryExit(ARMul_State *state)
    ARMword ARMul_LoadInstrS(ARMul_State *state, ARMword address)
    ARMword ARMul_LoadInstrN(ARMul_State *state, ARMword address)
    ARMword ARMul_LoadWordS(ARMul_State *state, ARMword address)
    ARMword ARMul_LoadWordN(ARMul_State *state, ARMword address)
    ARMword ARMul_LoadByte(ARMul_State *state, ARMword address)
    void ARMul_StoreWordS(ARMul_State *state, ARMword address, ARMword data)
    void ARMul_StoreWordN(ARMul_State *state, ARMword address, ARMword data)
    void ARMul_StoreByte(ARMul_State *state, ARMword address, ARMword data)
    ARMword ARMul_SwapWord(ARMul_State *state, ARMword address, ARMword data)
    ARMword ARMul_SwapByte(ARMul_State *state, ARMword address, ARMword data)
    void ARMul_Icycles(ARMul_State *state, unsigned number, ARMword address)
    ARMword ARMul_ReadWord(ARMul_State *state, ARMword address)
    ARMword ARMul_ReadByte(ARMul_State *state, ARMword address)
    void ARMul_WriteWord(ARMul_State *state, ARMword address, ARMword data)
    void ARMul_WriteByte(ARMul_State *state, ARMword address, ARMword data)

The above functions are described individually in the following paragraphs.

    unsigned ARMul_MemoryInit(ARMul_State *state, unsigned long memorysize)

This routine is called once, before any other routines are called, to allow the 
memory manager to initialise itself. If initialisation fails, the routine 
should return FALSE, otherwise return TRUE. The <memorysize> argument specifies 
the minimum amount of memory required by the ARMulator; if the size cannot be 
supplied, initialisation should fail. For systems implementing a fixed size 
memory, this argument should be used to set the value of <MemSize> in 
<ARMul_State>. The memory model can use this opportunity to attach to other 
parts of the ARMulator - an MMU model would probably want to attach to 
coprocessor 15 and the ModeChange upcall, for example.

    unsigned ARMul_MemoryExit(ARMul_State *state, unsigned long memorysize)

This routine is called once to allow the memory manager to perform finalisation 
code, such as deallocating memory. If finalisation fails, the routine should 
return FALSE; otherwise return TRUE.

    ARMword ARMul_LoadInstrS(ARMul_State *state, ARMword address).

This function should return the instruction addressed by <address>. The address 
was produced by the address incrementer, and sequentially follows that of the 
preceding memory access. 

    ARMword ARMul_LoadInstrN(ARMul_State *state, ARMword address)

This function should return the instruction addressed by <address>. The address 
does not sequentially follow that of the preceding memory access. 

    ARMword ARMul_LoadWordS(ARMul_State *state, ARMword address)

This function should return the word addressed by <address>. The address was 
produced by the address incrementer and sequentially follows that of the 
preceding memory access. 

    ARMword ARMul_LoadWordN(ARMul_State *state, ARMword address)

This function should return the word addressed by <address>. The address does 
not sequentially follow that of the preceding memory access. 

    ARMword ARMul_LoadByte(ARMul_State *state, ARMword address)

This function should return the byte addressed by <address>. The byte should be 
returned in the least significant eight bits of the returned value.

    void ARMul_StoreWordS(ARMul_State *state, ARMword address, ARMword data) 

This routine stores the word <data> to memory at address <address>. The address 
was produced by the address incrementer and sequentially follows that of the 
preceding word stored.

    void ARMul_StoreWordN(ARMul_State *state, ARMword address, ARMword data)

This routine stores the word <data> to memory at address <address>. The address 
does not sequentially follow that of the preceding word stored. 

    void ARMul_StoreByte(ARMul_State *state, ARMword address, ARMword data)

This routine should store the byte in the least significant eight bits of <data> 
to memory, at address <address>.

    ARMword ARMul_SwapWord(ARMul_State *state, ARMword address, ARMword data)

This function should load the word addressed by <address>, store the word <data> 
at <address>, and return the loaded value. 

    ARMword ARMul_SwapByte(ARMul_State *state, ARMword address, ARMword data)

This function should load the byte addressed by <address>, store the byte from 
the least significant eight bits of <data> at <address>, and return the loaded 
value. 

    void ARMul_Icycles(ARMul_State *state, unsigned number, ARMword address)

This routine is used to inform the memory system that the processor is about to 
execute <number> internal (I) cycles. The address of the next memory access 
will be <address>.

    void ARMul_Ccycles(ARMul_State *state, unsigned number, ARMword address)

This routine is used to inform the memory system that the processor is about to 
execute <number> co-processor cycles. 

    ARMword ARMul_ReadWord(ARMul_State *state, ARMword address)
    ARMword ARMul_ReadByte(ARMul_State *state, ARMword address)
    void ARMul_WriteWord(ARMul_State *state, ARMword address, ARMword data)
    void ARMul_WriteByte(ARMul_State *state, ARMword address, ARMword data)

These four functions must be <pure> and transfer data to or from the memory 
model without updating any other internal state. These functions are used by 
implementations of the Remote Debug Interface (see "<ARM Remote Debug Interface>
" of the Technical Specifications for details) to inspect 
and alter the modelled memory. As a general guideline, these calls should 
reflect the same memory mapping as that seen by the processor in its current 
state, but should not enforce protection attributes, and should not have any 
side effects such as causing cache line-fetches.

Finally, the memory system is at liberty to attach a handler to the ModeChange 
upcall. This is a function pointer that is part of every ARMul_State, and is 
called every time the processor mode is changed. This allows access permissions 
to be switched, and so on. The handler should take a copy of the old pointer 
value, and pass the call on to that function when it has finished (the default 
value of the pointer is a do-nothing function). The function is called as:

    void ARMul_ModeChangeUpcall(ARMul_State *state, ARMword old, ARMword new)

immediately after the register banks have been switched (if appropriate).


Rapid Prototype Memory Model
............................

Three routines must be written (in C) to provide a prototype memory model for 
the ARMulator:

    ARMul_MemoryInit;
    ARMul_MemoryExit;
    ARMul_MemAccess.

Supplied in source form with the ARMulator are veneer routines which then 
implement the eighteen routines described in the previous section.

Each routine takes a pointer to an <ARMul_State> as its first parameter. 

    unsigned ARMul_MemoryInit(ARMul_State *state, ARMword memory_size)

This routine is called once, before any other routines are called, to allow the 
memory manager to initialise itself. If initialisation fails, the routine 
should return FALSE, otherwise return TRUE. The <memorysize> argument specifies 
the minimum amount of memory required by the ARMulator; if the size cannot be 
supplied, initialisation should fail. For systems implementing a fixed size 
memory, this argument should be used to set the value of <MemSize> in 
<ARMul_State>.

    unsigned ARMul_MemoryExit(ARMul_State *state, unsigned long memorysize)

This routine is called once to allow the memory manager to perform finalisation 
code, such as deallocating memory. If finalisation fails, the routine should 
return FALSE; otherwise return TRUE.

    ARMword ARMul_MemAccess(
          ARMul_State *state,
          ARMword address,
          ARMword dataOut,
          ARMword bw,
          ARMword rw,
          ARMword seq,
          ARMword mreq,
          ARMword opc,
          ARMword lock,
          ARMword trans,
          ARMword account)

This routine must perform a memory access by modelling the ARM memory interface 
pins. The parameters following the ubiquitous state parameter have the 
following meanings:

    <address>   encodes ARM's address bus and always has a valid value.

    <dataOut>   encodes ARM's dataOut bus and only has a valid value during 
                memory write requests.

    <bw>        encodes ARM's Not Byte/Word pin, and has the value LOW for byte 
                requests and HIGH for word requests. Its value is only valid 
                when the value of <mreq> (see below) is LOW (i.e. during data 
                transfers).

    <rw>        represents ARM's Not Read/Write pin, and has a value of LOW for 
                read requests and HIGH for write requests. Its value is only 
                valid when the value of <mreq> (see below) is LOW (i.e. during 
                data transfers). Byte read requests should return the entire 
                word from the memory. The ARMulator will extract the required 
                byte, just as ARM itself would. Byte Write operations receive 
                the byte to be written replicated four times in dataOut; the 
                memory model must extract the correct byte. 

    <seq>       represents ARM's Sequential Pin, and has a value of HIGH when 
                the address specified is sequential with the previous access. 
                Its value is always valid.

    <mreq>      represents ARM's Not Memory Request Pin, and has a value of LOW 
                when the access should actually load or store data. Its value 
                is always valid.

    <opc>       represents ARM's Not OpCode Pin, and has a value of LOW if the 
                access is an instruction fetch. Its value is only valid when 
                the value of <mreq> (see above) is LOW (i.e. during data 
                transfers).

    <lock>      represents ARM's Lock Pin, and has a value of HIGH if the 
                memory system should deny other devices access to the memory. 
                The signal is only valid when <mreq> (see above) is LOW (i.e. 
                during data transfers).

    <trans>     represents ARM's Not Trans Pin, and has a value of LOW if the 
                processor is in a User mode. Its value is always valid.

    <account>   is used to inform the memory system that it should account for 
                the number of cycles used in this memory access by updating the 
                fields <NumScycles>, <NumNcycles>, <NumIcycles> and <NumCcycles> 
                in the <ARMul_State> structure pointed to by <state>.

When <rw> is LOW, <ARMul_MemAccess> should return the contents of the memory 
location addressed by <address>; otherwise it should return 0. Aborts in the 
memory system are modelled using two macros defined in <armdefs.h>.

If an Abort occurs during an instruction prefetch (<opc> equals LOW) the macro 
<ARMul_PREFETCHABORT> should be called, passing the address of the abort (from 
the <address> argument to <ARMul_MemAccess>) as a parameter.

If a Data Abort occurs, the macro <ARMul_DataAbort> should be called, again 
using <address> as its parameter.

In both cases the value <ARMul_ABORTWORD> should be returned. 


Co-processor Modelling
----------------------

The ARMulator models a co-processor via a software interface that uses the 
ARMulator to handle most of the difficult handshaking and timing constraints. 
Each co-processor modelling function must be installed in the <ARMul_CoProInit> 
function defined in <armcopro.c> using the function <ARMul_CoProAttach>.

    void ARMul_CoProAttach(ARMul_State *state, ARMword number,
                         ARMul_CPInits *init, ARMul_CPExits *exit,
                         ARMul_LDCs *ldc, ARMul_STCs *stc,
                         ARMul_MRCs *mrc, ARMul_MCRs *mcr,
                         ARMul_CDPs *cdp,
                         ARMul_CPReads *read, ARMul_CPWrites *write,
                         ARMword *regwords)

This routine installs up to nine routines for co-processor number <number>. The 
remaining arguments are pointers to functions. If any arguments are NULL the 
handler is not changed.

    extern void ARMul_CoProDetach(ARMul_State *state, ARMword number);

This function sets the default handlers for a co-processor, (no initialisation, 
finalisation, read or write functions, and dummy operation functions which 
cause ARM undefined instructions).

The functions passed to <ARMul_CoProAttach> are as follows:

    unsigned ARMul_CPInits(ARMul_State *state)

This routine is called once, before any other routines are called, allowing the 
co-processor to initialise. If initialisation is not possible, the routine 
should return the value FALSE; otherwise return the value TRUE. 

    unsigned ARMul_CPExits(ARMul_State *state)

This routine is called last, allowing the co-processor to finalise. If 
finalisation is not possible, the routine should return the value FALSE, 
otherwise return the value TRUE. 

The next five functions accept a parameter <type> that can have five values:

    FIRST       indicates this is the first time the co-processor has been 
                called with this instruction.

    TRANSFER    indicates that this is the load cycle of an LDC instruction 
                (the data is being loaded from memory).

    DATA        indicates that the co-processor is being called with valid data 
                (LDC and MCR), or is expected to return valid data (STC and 
                MRC).

    INTERRUPT   is used to warn the co-processor that the ARMulator is about to 
                service an interrupt, so the co-processor should discard the 
                current instruction. Usually, the instruction will be retried 
                later, in which case the type parameter will be reset to FIRST.

    BUSY        is used as the reply to a previous call that returned BUSY (see 
                below)

For each of these functions, a second parameter, <instr> is the co-processor 
instruction itself.

These functions must return one of four values:

    BUSY        to indicate that the co-processor is busy and the ARMulator 
                should   busy-wait, recalling the routine repeatedly;

    CANT        to indicate that the co-processor cannot execute this 
                particular instruction;

    INC         to indicate the ARMulator should produce the next address for 
                an LDC or STC instruction, and call the co-processor function 
                again;

    DONE        to indicate successful completion of the instruction.

Descriptions of the five functions follow:

    unsigned ARMul_CDPs(ARMul_State *state, unsigned type, ARMword instr)

This function is called when the ARMulator encounters a CDP instruction 
destined for this co-processor. Unless it returns the value BUSY, it will only 
be called once with <type> set to FIRST.

    unsigned ARMul_MRCs(ARMul_State *state,
                      unsigned type, ARMword instr, ARMword *value)

This function is called when the ARMulator encounters an MRC instruction 
destined for this co-processor. The <value> argument is a pointer to (the model 
of) an ARM register where the result of the transfer should be stored (if it 
was successfully emulated). This location should be considered <write> only. 
Unless the function returns the value BUSY, it will only be called once with 
<type> set to FIRST.

    unsigned ARMul_MCRs(ARMul_State *state,
                      unsigned type, ARMword instr, ARMword value)

This function is called when the ARMulator encounters an MCR instruction 
destined for this co-processor. The <value> argument is the value of the ARM 
register to transfer (if it was successfully emulated). Unless the function 
returns the value BUSY, it will only be called once with <type> set to FIRST. 

    unsigned ARMul_LDCs(ARMul_State *state,
                      unsigned type, ARMword instr, ARMword value)

This routine is called when the ARMulator encounters an LDC instruction 
destined for this co-processor. The <value> argument is the data loaded from 
memory. This function will be called first with <type> set to FIRST. Assuming 
the function does not return BUSY, the function will then be called with <type> 
set to TRANSFER, and finally with <type> set to DATA, at which point the <value> 
argument will be valid. The function may request further data to be transferred 
by returning the value INC, in which case subsequent calls will have <type> set 
to DATA and the <value> argument will be valid. 

    unsigned ARMul_STCs(ARMul_State *state,
                      unsigned type, ARMword instr, ARMword *value)

This routine is called when the ARMulator encounters an STC instruction 
destined for this co-processor. The <value> argument should be set to the value 
to be stored to memory at the address calculated by the ARMulator. This 
location should be considered write-only. This function will be called first 
with <type> set to FIRST. Assuming the function does not return BUSY, the 
function will then be called with <type> set to DATA, at which point the 
function should store the data to be written to memory in <value>. The function 
may request further data to be transferred by returning the value INC. 
Subsequent calls will have <type> set to DATA and <value> should be set to the 
value to write to memory. 

Finally, two functions allow a debugger to read and write co-processor 
registers via the Remote Debug Interface, (see "<ARM Remote Debug Interface>" 
starting on page72 of the Technical Specifications for details):

    unsigned ARMul_CPReads(ARMul_State *state,
                      unsigned reg, ARMword *value)
    unsigned ARMul_CPWrites(ARMul_State *state,
                      unsigned reg, ARMword *value)

<ARMul_CPReads> reads the co-processor register numbered <reg>, and transfers 
its value to the location addressed by <value>.

<ARMul_CPWrites> sets the value of the co-processor register numbered <reg> to 
the value addressed by <value>.

    ARMword *regwords

The <regwords> argument describes to ARMulator the shape of your co-processor's 
registers. It consists of a single word giving the number of registers followed 
by a vector of the minimum number of words required to contain the register. 
For an example, see the definition of the minimal MMU system given in <armos.c>
.

The state structure contains the field:

    char *CPData[16]

that a co-processor may use to point to private data. Each co-processor should 
use the element of the array corresponding to its co-processor number. 


Modelling an Operating System or Low Level Monitor
--------------------------------------------------

Rapid prototyping of low-level operating system code is supported via four 
functions:

    unsigned ARMul_OSInit(ARMul_State *state)
    unsigned ARMul_OSHandleSWI(ARMul_State *state, unsigned number)
    ARMword ARMul_OSLastErrorP(ARMul_State *state)
    unsigned ARMul_OSException(ARMul_State *state, ARMword vector, ARMword pc)

in the file <armos.c>. The <ARMul_State> structure contains a pointer called 
<OSptr> which can be used to point to a structure holding the operating system 
model's state.

    unsigned ARMul_OSInit(ARMul_State *state)

<ARMul_OSInit> is used to inform the OS model that it should initialise itself. 
The function may return FALSE, indicating that initialisation was impossible. 
The memory system is guaranteed to be operating at this time, and thus the 
memory interface routines described in the earlier section <Memory Models> may 
be used to install default trap handlers, etc.

    unsigned ARMul_OSHandleSWI(ARMul_State *state, unsigned SWInum)

<ARMul_OSHandleSWI> is passed the SWI number (in <SWInum>) of each SWI 
instruction executed by the ARMulator, as it is executed, allowing support code 
to simulate operating system operations. You can extend this code to model as 
much of your operating system as you choose. This OS model can, of course, 
communicate with the emulated application, by reading and writing the emulated 
ARM state using the routines described in "<Accessing ARMulator's State>" 
starting on page44.  The function may refuse to handle a SWI by returning 
FALSE, in which case the SWI exception vector is taken by the ARMulator. If the 
function returns TRUE, execution continues normally following the SWI 
instruction.

    ARMword ARMul_OSLastErrorP(ARMul_State *state)

This function should return the last software error reported to the debuggee 
via a default Error Vector handler. If no handler is installed the routine 
should return zero.         

    unsigned ARMul_OSException(ARMul_State *state, ARMword vector, ARMword pc)

<ARMul_OSException> is called whenever a hardware exception occurs. The CPU 
state is frozen immediately after the exception has occurred, but before the 
CPU has switched processor state, or taken the appropriate exception vector. 
The argument <vector> contains the address of the vector about to be executed: 
0 for Reset; 4 for Undefined Instruction; 0x1c for Fast Interrupt (FIQ) etc. 
The argument <pc> contains the value of the program counter (including the 
effect of pipelining) at the time the exception occurred.

The function may choose to ignore the exception by returning TRUE, and 
execution will continue from the instruction following the aborted instruction. 
A return value of TRUE will cause the exception to occur normally (i.e. a 
possible mode change and execution to continue from the appropriate exception 
vector).


Accessing ARMulator's State
---------------------------

The ARMulator provides several functions which allow full access to its 
internal state. These functions may only be called at the beginning of a new 
instruction (i.e. from inside any initialisation or finalisation function; or 
<ARMul_OSHandleSWI>, <ARMul_LoadInstrS>, <ARMul_LoadInstrN>; or a routine 
called by the ARMulator's event handler, see "<Event Handling>" starting on 
page46); at any other time the ARMulator's state is undefined.

    ARMword ARMul_GetReg(ARMul_State *state, unsigned mode, unsigned reg)
    void ARMul_SetReg(ARMul_State *state, unsigned mode, unsigned reg)

These functions allow the value of a register from a given mode to be read and 
written. Register 15 should not be accessed with these functions. Mode numbers 
are defined in <armdefs.h> as follows:

    USER26MODE        USER32MODE
    FIQ26MODE         FIQ32MODE
    IRQ26MODE         IRQ32MODE
    SVC26MODE         SVC32MODE
                      ABORT32MODE
                      UNDEF32MODE

    ARMword ARMul_GetPC(ARMul_State *state)
    void ARMul_SetPC(ARMul_State *state, ARMword value)
    ARMword ARMul_GetR15(ARMul_State *state)
    void ARMul_SetR15(ARMul_State *state, ARMword value)

These functions allow access to Register 15. The PC variants strip/preserve the 
condition code, and mode bits from register 15 if the processor was in a 26 bit 
mode. 

    ARMword ARMul_GetCPSR(ARMul_State *state)
    void ARMul_SetCPSR(ARMul_State *state, ARMword value)

These functions allow the CPSR to be read and written. The format of the CPSR 
is the same as that of ARM6, regardless of processor mode.

    ARMword ARMul_GetSPSR(ARMul_State *state, ARMword mode)
    void ARMul_SetSPSR(ARMul_State *state, ARMword mode, ARMword value)

These functions allow the SPSR of a specified mode to be read and written. The 
format of a SPSR is the same as that of ARM6, regardless of processor mode.


ARMulator Signals
-----------------

Some of ARM's I/O signals can be read and written by accessing the fields of 
the <ARMul_State> structure at any time. The following fields are guaranteed to 
contain valid values at all times:

    ARMword instr
    ARMword pc
    unsigned NresetSig
    unsigned NfiqSig
    unsigned NirqSig
    unsigned abortSig
    unsigned NtransSig
    unsigned bigendSig
    unsigned prog32Sig
    unsigned data32Sig
    unsigned lateabtSig

The <instr> field contains the address of the instruction that is currently 
being executed, the <pc> field contains the address of that instruction. The 
meaning of the other fields are described in the <ARM6 Datasheet>, and should 
be set to the value HIGH or LOW. The signals <Nreset>, <Nfiq> and <Nirq> are 
only checked if the value of <Exception> in the state structure is set to TRUE.


Processor selection
-------------------

The function

    void ARMul_SelectProcessor(ARMul_State *state, int processor)

can be used to change the processor being emulated. The full range of possible 
processors is listed in <armdefs.h>. This will, as a side-effect, alter the 
values of various I/O signals.

There is currently no way to specify processor requirements over the RDI, so 
armsd will, by default, only provide ARM6 emulation.

Note that cycle counts returned by ARM7M multiplies are subject to change.


Event Handling
--------------

The ARMulator has two routines to assist with scheduling asynchronous events:

 *  the function <ARMul_Time>;

 *  the function <ARMul_ScheduleEvent>.

The function

    unsigned long ARMul_Time(ARMul_State *state)

returns the number of clock ticks executed since system reset, modulo 2^32.

The function

    void ARMul_ScheduleEvent(ARMul_State *state,
          unsigned howlong, unsigned (*func)(ARMul_State *state))

allows a function (passed in the argument <func>) to be called <howlong> clock 
ticks into the future, therefore allowing code like multicycle FPU instructions 
to produce results some time into the future. The function is called with a 
pointer to the emulation state pertaining at the time of the call. The value of 
<howlong> must not exceed 1000.


The ARM Debug Monitor
---------------------

The files <armos.h>, <armfpe.h> and <armos.c> define a low level interface 
between the ARMulator and the host's operating system, used for debugging 
applications running under the ARMulator and to support the semi-hosted ANSI C 
library via the host's C library. The same interface is used between the ARM 
debug monitor (for platform independent ARM evaluation and development cards) 
and the ARM symbolic debugger, <armsd>. This gives a common low-level 
programming, C library and debugging environment across:

 *  the ARMulator under <armsd>; 

 *  the ARM Platform Independent Evaluation (PIE) card for the ARM60 driven by 
    <armsd>;

For further details, please refer to "<ARM Debug Monitor>" 
of the Technical Specifications.

