<html><head><title>The ARM instruction set</title></head>
<body background="images/tile">
<h3><center>The ARM instruction set</center></h3>
<p>
The first class of instructions I am going to talk about only has one instruction. This is the SWI instruction, and stands for SoftWare Interrupt. It is through this mechanism that all operating system routines are implemented.
<p>
<h4>SWI (Software Interrupt)</h4>
<p>
A SWI call is what it claims to be, an interrupt initiated in software. There are a number of interrupts that can occur other than the SWI, for example, the RESET signal. The operating system has a table of instructions to execute if a particular interrupt occurs. Normally these instructions will be a branch to the routine that deals with them. The memory address of the table starts at 0 and ends at &1C, and is fixed by the processor, but the routines to deal with the interrupt can reside anywhere in memory (the user could write his own interrupt handlers if he really wanted to).
<p>
A SWI call causes an interrupt to occur. The processor switches into Supervisor mode. Supervisor mode allows read/write access to all of the computer's memory. User mode (the standard mode) doesn't allow this, and some areas of the memory are partitioned off so as to prevent rogue programs writing to certain sections of memory. Once in supervisor mode, the program counter is stored. It then branches to memory location 8 (the SWI entry in the interrupt table) to deal with the interrupt. This location contains a branch instruction which sends the processor off to the actual SWI handling routine.
<p>
The question now is how does the SWI handler know what routine the program wanted to call? To answer this question, I need to explain how ARM instructions are coded.
<p>
<h4>Instruction Coding</h4>
<p>
All machine code instructions on the ARM occupy a 4 byte word. All the information about how the instruction should operate, what registers it uses etc. must be stored in these 4 bytes. The instruction is split into a number of different fields, and the number, and their meaning depends on the instruction class. The user doesn't normally need to worry about this (that is what an assembler is for after all!), but it is instructive to know something about it.
<p>
In the case of the SWI call, the top 4 bits are a code which say which conditions have to be met before the instruction is executed (this is common to all instructions). See Table 1 for details of the different conditions. The next 4 bits hold a code (1111) saying that this instruction is a SWI. The remain 24 bits are ignored by the ARM, but are used to specify what operating system routine is being called. As a result, there are 2^24 different codes which can be used to specify what routine is required.
<p>
<h4>SWI decoding</h4>
<p>
The SWI number is divided up into a number of different parts. SWI numbers are grouped together in blocks of 64 consecutive numbers. These are called chunks, and each chunk has an identification number (there are 1024 of these), which are generally attributed to different parts of RiscOs. For example, the Wimp Manager has SWI numbers &400C0-&400FF. (The bits that count indicate that this is the 3rd chunk)
<p>
The other important feature of the SWI numbers is the 'X' bit. This is set by prefixing the SWI name with an X. This indicates that if an error occurs, the routine should return to the calling code with the overflow flag (V) set so that the calling code can deal with it itself. So, a SWI call would change from
<p>
<code>SWI "OS_WriteC" to SWI"XOS_WriteC"</code>
<p>
More details of the SWI number format can be found in Table 2.
<p>
All SWI numbers have an associated name, which can be found in the module that the SWI comes from. The Basic Assembler automatically converts SWI names into their corresponding number, so the use of SWI names instead of numbers is recommended as it helps to improve clarity. The operating system routines "OS_SWINumberFromString" and "OS_SWINumberToString" convert between number and name and vice-versa.
<p>
<h4>Using SWIs</h4>
<p>
Information for a particular SWI is passed using registers. The number that are used depends on the the routine, but they start from r0 upwards. Knowing that only r0-r3 (say) are going to be used in the various SWIs you are using means that you can leave these registers free, and keep important information in the other registers. All SWIs will preserve the contents of any registers they are not using to pass information back in.
<p>
The range of SWI calls available is wide ranging. For example, converting a number into a string and printing it can be performed using only two SWI calls. If r0 contains the number to be printed, r1 a pointer to a resultant string, and r2 the size of the buffer, the following code will print the number.
<p><code>
SWI "OS_ConvertCardinal4"<br>
SWI "OS_Write0"</code>
<p>
The OS_ConvertCardinal4 returns the address of the string to print in r0 which is the same register that OS_Write0 requires the address to be in.
<p>
Changing the OS_ConvertCardinal4 to OS_SWINumberToString, and adding a MOV R0,R1 between the two instructions in the above example would print out the name of a particular SWI number.
<p>
<h4>Bits and pieces</h4>
<p>
Data can be stored within the machine code program using the directives EQUS, EQUB and so on (see Table 3 for full details). These work by instructing the assembler to store the data at that point in memory. The number of bytes taken depends on the directive. This can present a problem though. Due to the way the ARM works, all instructions must be word aligned, that is to say that because ARM instructions are 4 bytes long, the instructions must be consecutively arranged, and hence have to be at an address divisible by 4. The reason for this is because the program counter assumes that the bottom 2 bits of an address are 00 (and by implication that all instruction addresses are multiples of 4), and uses these 2 bits in the program counter for another purpose. Should you find that by entering data the next address isn't word aligned, the directive ALIGN will instruct the assembler to use the next word aligned memory location to continue assembling from.
<p>
The SWI instruction is an extremely powerful way of interacting with the operating system. The time overhead in finding which SWI should be executed is generally not high enough to cause too many problems. Next time I will look at data processing operations as these comprise the bulk of instructions the ARM recognises.
<p>
<h4>Table 1 : Execution conditions</h4>
<pre>
EQ (EQual)               If Z is set
NE (Not Equal)           If Z is clear
CS (Carry Set)           If C is set
CC (Carry Clear)         If C is clear
MI (MInus)               If N is set
PL (PLus)                If N is clear
VS (oVerflow Set)        If V is set
VC (oVerflow Clear)      If V is clear
HI (HIgher)              If C set and Z is clear
LS (Lower or Same)       If C clear and Z is set
GE (Greater or Equal)    If N clear and V clear
                         or if N set and V set
LT (Less Than)           If N set and V clear
                         or if N clear and V set
GT (Greater Than)        As for GE but Z must be clear
LE (Less than or Equal)  As for LT but Z must be set
AL (ALways)              Always; Regardless of state of flags
NV (NeVer)               Never; Regardless of state of flags
</pre>
<b>Flags</b>
<pre>
Z : Zero Flag            Set when 2 compared values are equal
                         or set if destination result is zero
N : Negative flag        N reflects the state of bit 31 of a result
C : Carry flag           Set if a result is larger than the available bits
                         or during shift operations
V : Overflow flag        Set if there is a carry from bit 30 to 31 and
                         there is no carry set or if there is no carry
                         from bit 30 to 31 but there is a carry set
</pre>
Instruction conditions are tacked on the end of a normal instruction.
So, executing a SWI only if the Z flag is not set is written as 
<p>
<code>SWINE "OS_WriteC"</code>
<p>
<h4>Table 2 : SWI number format</h4>
<pre>
bits 20 - 23    Operating system identification

                RISC OS = 0000
                RISC iX = 1000

bits 18 - 19    Determines which part of system implements the SWI

                00  = Operating System
                01  = Operating System extension modules
                10  = Third party resident applications
                11  = User Applications

bits 17         The 'X' bits. Determines action on errors

bits 6 - 16     SWI Chunk Identification number

bits 0 - 5      Identify individual SWIs in a chunk.
</pre>
So operating system extension SWIs start at &40000, third parties
at &80000, and users at &C0000.
<p>
<h4>Table 3 : Assembler Directives</h4>
<pre>
EQUB    Stores 1 byte
EQUW    Stores 2 bytes
EQUD    Stores 4 bytes (32 bit word)
EQUS    Store variable length string

ALIGN   Re-aligns program counter to a word boundary
</pre>
</body>
</html>