THE
UNIVERSITY OF TEESSIDE
SCHOOL OF COMPUTING AND
MATHEMATICS
MIDDLESBROUGH
TS1 3BA
ARM SIMULATOR
BSc Informatics
April 2000
T.Magnussen
Supervisor : Professor A.Clements
Second reader : A.Siday
ABSTRACT
This
project has produced a software simulation of a ARM processor. A user may run
ARM assembly programs and view the results in a graphical interface.
The analysis phase of the project involved detailed studies of different ARM architectures and ARM assembly language. Most of the decisions about hardware components to include in the simulation and assembly instructions to support were made during this stage. This phase also involved identifying the requirements of the simulator.
The next stage was design, in which the GUI was sketched and sequence and class diagrams were made to model the system structure. Use case diagrams were employed to fulfil the GUI design.
The implementation phase involved turning the diagrams into code, following the design as closely as possible.
Testing was done for each separate implemented part, and a final test was done at the end of the implementation. Shortage of time made the testing somewhat less extensive than desired.
When all was over and done with, all documentation was refined and put together in a final report together with a conclusion.
The system is fully implemented and all the major goals were reached. Some recommendations for enhancements have been summarised.
I would like to thank Professor Alan Clements for his support, technical input and guidance through the project period. Thanks to Jan Andersen for lending me the hardware books that helped me through some difficult times.
Endre Moen and Morten Gustavsen provided unavailable help in testing the system.
ABSTRACT…................................................................................................................. i
ACKNOWLEDGMENTS................................................................................................. ii
CONTENTS……............................................................................................................ iii
CHAPTER 1 – INTRODUCTION................................................................................... 1
CHAPTER 2 – METHODOLOGY................................................................................... 2
2.1 Analysis methodologies........................................................................................ 2
2.2 Design methodologies.......................................................................................... 3
2.3 Implementation methodologies.............................................................................. 3
2.4 Testing methodologies.......................................................................................... 4
CHAPTER 3 – ARM HARDWARE ANALYSIS............................................................. 5
3.1 ARM architectures.............................................................................................. 5
3.2 Registers and register roles.................................................................................. 5
3.3 Condition code flags............................................................................................. 8
3.4 Control bits.......................................................................................................... 8
3.5 Memory formats.................................................................................................. 8
3.6 Simulator constraints............................................................................................ 8
CHAPTER 4 – ARM ASSEMBLY LANGUAGE ANALYSIS........................................ 10
4.1 The ARM Instruction Set................................................................................... 10
4.2 The selected instruction set................................................................................. 10
4.3 Conditional execution......................................................................................... 11
4.4 The ‘S’ bit......................................................................................................... 12
4.5 Shifts operations................................................................................................ 12
4.6 Register based shift counts................................................................................. 17
4.7 Immediate operand substitution........................................................................... 17
4.8 Negative operands............................................................................................. 17
4.9 Conclusion......................................................................................................... 18
CHAPTER 5 – REQUIREMENT ANALYSIS................................................................ 19
5.1 An example scenario.......................................................................................... 19
5.2 Specification of requirements.............................................................................. 19
CHAPTER 6 – GRAPHICAL USER INTERFACE DESIGN.......................................... 21
6.1 GUI Design issues............................................................................................. 21
6.2 Designing the user interface............................................................................... 22
CHAPTER 7 – SYSTEM DESIGN................................................................................. 25
7.1 Designing the instruction objects......................................................................... 25
7.2 Designing a ’compiler’....................................................................................... 27
7.3 Connecting the designs....................................................................................... 28
7.4 Storing instructions............................................................................................. 29
7.5 Designing a shared datamodel............................................................................. 29
7.6 Memory representation...................................................................................... 30
7.7 Designing a stack............................................................................................... 30
7.8 Sequence and class diagrams............................................................................. 31
CHAPTER 8 – IMPLEMENTATION............................................................................ 36
8.1 Implementing the GUI........................................................................................ 36
8.2 Implementing the instruction objects.................................................................... 37
8.3 Implementing the instruction reader..................................................................... 37
8.4 Executing instructions......................................................................................... 38
8.5 Conditional execution......................................................................................... 39
8.6 Shift support...................................................................................................... 39
8.7 Branch abilities.................................................................................................. 39
8.8 The Autorun feature.......................................................................................... 39
8.9 Other implementation issues............................................................................... 41
CHAPTER 9 – TESTING............................................................................................... 44
9.1 Testing large operand substitution........................................................................ 44
9.2 Testing shift routines.......................................................................................... 44
9.3 Testing conditional execution.............................................................................. 45
9.4 Testing negative operand substitution................................................................... 45
9.5 Testing the Simulator with real users................................................................... 45
9.6 Testing the Simulator on different
platforms......................................................... 46
CHAPTER 10 – CONCLUSIONS.................................................................................. 47
10.1 Goals and achievements..................................................................................... 47
10.2 Personal thoughts............................................................................................... 47
CHAPTER 11 – RECOMMENDATIONS...................................................................... 49
11.1 Completing the instruction set............................................................................. 49
11.2 Serialization....................................................................................................... 49
11.3 Upgrading the ’compiler’.................................................................................... 49
11.4 Improving the help system.................................................................................. 49
11.5 Converting the Application to an Applet............................................................... 49
11.6 Thumb support................................................................................................... 49
11.7 Other features................................................................................................... 49
CHAPTER 12 – BIBLIOGRAPHY................................................................................ 51
APPENDIX A – PROJECT SPECIFICATION............................................................... 53
APPENDIX B – PROJECT TIME SCHEDULE............................................................. 54
APPENDIX C – USER GUIDE...................................................................................... 55
APPENDIX D – TEST RESULTS………………………………………………………..….77
APPENDIX E – USE CASE AND UML DIAGRAMS................................................... 85
APPENDIX F – CHOICE OF DEVELOPMENT LANGUAGE.................................... 124
APPENDIX G – SOURCE CODE................................................................................ 127
The
first ARM processor was designed by Acorn Computer Ltd, Cambridge, United
Kingdom in 1985. In 1990 Advanced RISC Machines (ARM) was founded and VLSI
Technology became their first licensee. Today ARM licenses high-performance,
low-cost, power-efficient RISC processors, peripherals, and system-chip designs
to leading international electronics companies and have offices worldwide.
The
objective of the project is to produce a simulation of a ARM processor. The
idea of the project came from my supervisor, Professor Alan Clements.
This project has the following overall goals:
·
Produce
a realistic, GUI based, simulation of a ARM processor.
·
The
simulator should be able executing ARM assembly programs.
·
The
simulator should display ARM component like registers and memory.
· The simulator should display the effect each instruction has on those registers, in an easy and consistent matter.
The chapters in this report have been positioned in the following order, according to the project handbook recommendations:
Chapter 2 - Discusses the methodologies used throughout the project.
Chapter 3 - Describes the hardware analysis carried out on the ARM architecture.
Chapter 4 - Describes the assembly analysis carried out.
Chapter 5 - Describes the requirement analysis for the simulator.
Chapter 6 - Describes design of the graphical user interface.
Chapter 7 - Describes the system design phase.
Chapter 8 - Describes the implementation.
Chapter
9 - Describes testing and the approach used in this phase.
Chapter
10 - Overall conclusion of the project.
Chapter
11 - Further recommendations.
This chapter describes the methodologies that were used throughout the project.
The core analysis done for this project involved gathering relevant information about the ARM family of processors, studying assembly language and looking at existing systems. A requirement analysis was written to identify the main requirements of the system.
This project was developed with a mixture of methodologies. Most of the object-oriented analysis and design was done by creating diagrams that were of great help when implementing the code itself.
UML (Unified Modelling Language) is a standard for modelling object-oriented applications like Java, and it is the evolution of notations used in OOSE (Object Oriented Software Engineering), Booch, and OMT (Object Modelling Technique). Used together with “use case diagrams”, it covers the full lifecycle of an object-oriented project
The lifecycle for this project is the ’Mini-Waterfall model’, which is an iterative process. Every iteration consists of analysing, designing, coding and integrating a small part of the system. When an iteration is complete, a new iteration is started dealing with another part of the system.

Figure 2.1 The iterative mini waterfall model
UML was employed to model the full system. Two UML diagrams were used in conjunction with use case.
Use case diagrams describes the interaction between the user and the system. A use case is a task the system should be able to deal with. Each use case defines a subtask of the system. This subtask can in it’s turn be described by another use case diagram, but eventually all use cases is described by a sequence diagram. Use case diagrams complement UML by adding the ability to describe the behaviour of the system from a users viewpoint.
Sequence diagrams isolates a use case event and describes the interaction between the system and the user for that particular task.
Class diagrams express the structure of a system, in terms of classes and their relationships. A class is described by its class name, it’s attributes and it’s methods.
All UML diagrams, whether or not included in the report, can be found in Appendix D.
Use case diagrams formed the base of the design phase. Each case within a use case diagram was further broken down and represented by sequence diagrams. Having described an operation, classes were designed or updated to handle that operation.
In addition some specific operations, like building the instructions and executing an instruction, were designed using flowchart diagrams to clarify the process.
To implement the simulator, decisions would have to be made about its appearance. Based on the use case diagrams, sketches were made. The sketches were mostly created with pen and paper, the same goes for some of the diagrams. All have been recreated in electronic format through the painting tool in Word and Rational Rose 2000.
A lot of figures have been created where a quite simple figure can explain as much as any UML- or flowchart- diagram. These figures are very simplified but they all describe the important aspects of what they are designed to represent.
Pseudo code was used when applicable but has not been used continuously throughout the project. It was adapted for certain complex methods, like the methods dealing with recognition and verification of instructions and assembly operands.
2.3 Implementation methodologies
Implementation was closely tied to the development of UML diagrams. All class diagrams created in the design phase were converted into code in the implementation phase.
This did of course not always work out the way it should. In these cases, the diagrams were scratched or changed, and the code was written over again or changed to adapt the changes in the diagrams. For complex problems the implementation was carried out based on pseudo code or flowchart diagrams created during design.
The testing methodologies used within the project comprise of Module, System and Boundary Value testing.
Module testing involves testing classes and all it’s methods after the implementation. This is done before the module is integrated with the full system.
System testing involves performing tests on the full system, ensuring that all the parts work seamlessly together. A system test is carried out each time a new module is integrated with the full system, to ensure that the modules work seamlessly together.
State Boundary testing involves testing critical parts of the system with boundary values, that is the maximum and minimum values the particular part is supposed to handle, and any other values that are known to produce special results.
All these methods will be used throughout the project to test each part independently and when integrated with the full system.
The final testing will be performed using System and State Boundary testing.
CHAPTER 3 – ARM HARDWARE ANALYSIS
The objective of the hardware analysis is to gain knowledge about the ARM architecture and to select the components needed to include in the simulator.
There are four major versions of the ARM architecture.
The initial architecture was never used in a commercial product. Version 2 was the first to be released and extended the original architecture by adding two new instructions, coprocessor support and two banked registers. The address range was 26-bits and r15 held a 24-bit program counter along with 8-bits of status information. It had three privileged processing modes, Supervisor, IRQ and FIQ.
Version 3 of the architecture extended the address range to 32-bits. Register 15 was dedicated to the program counter and the status information was moved to a new, 11-bit, status register. Two more privileged modes were added Undefined and Abort. For each privileged mode a new status register was added, called the SPSR, to preserve the CPSR contents when switching modes.
Version 4 added halfword load and store instructions. It defined several new undefined instructions.
3.2 Registers and register roles
The ARM has a total of 37 registers distributed across six processing modes. 6 of these are status registers, one for each mode, and one is the program counter, which is shared across all modes. The remaining 30 are general-purpose registers.
Registers 0-12 are always free for general-purpose use. Registers 13 and 14, is available for general use but have specific roles.
Register 13 is also called the SP, or Stack Pointer, and is banked across all modes to provide a private Stack Pointer for each mode.
Register r14 is called the LR, or Link Register and is used as the subroutine return address link register. R14 is also banked across all modes.
Register r15 is used to hold the PC, or Program Counter. The program counter holds the address of the next instruction to be carried out. R15 is shared over all processor modes.
The CPSR is an 11-bit register and contains the condition code flags, current processor mode and interrupt enable flags. See figure 3.2 for details.

Figure 3.1 The ARM register set

Figure 3.2 The CPSR register
The N, Z, C and V bits are called the condition code flags. These are located in the upper bits of the CPSR and can be changed by arithmetic and logical operations in the processor. The condition code flags determine if an ARM instruction is to be executed or not.
|
Flag |
|
Description |
|
N |
Negative |
Set if the last operation generated a negative result. |
|
Z |
Zero |
Set if the last operation generated a zero result. |
|
C |
Carry |
Set if the last operation resulted in a carry out from the most significant bit position of the operand. |
|
V |
Overflow |
Set if the last operation resulted in an arithmetic overflow. That is when an operation on a one or two’s complement number yields a result outside it’s permitted range. |
Figure 3.3 The Condition Code flags
The bottom 8-bits of the CPSR is occupied by the control bits, which include two interrupt disable bits, a state bit and five mode bits.
The I and F bit disables respectively the IRQ interrupt and the FIQ interrupt, when set.
Bit T indicates the processor mode. If this bit is set the processor is in Thumb mode. This bit is only used on thumb aware processors (processor capable of running 16-bit Thumb instructions). The last five bits indicates which mode the processor operates in.
The ARM view memory as a linear collection of bytes numbered upwards from zero. Since all ARM instructions are 32-bits wide, instructions are stored at 4 byte boundaries. The ARM can treat words in memory as being stored in either Big Endian or Little Endian formats.
Big Endian assumes that the most significant byte of a word is stored at the lowest numbered byte, and the least significant byte at the highest numbered byte.
Little Endian is the opposite of Big Endian with the most significant byte at the highest numbered byte and the least significant at the lowest numbered byte.
The ARM Simulator will operate in USER mode only. Architecture 3 and above will be used as model for the simulator and Little Endian will be used as the memory model.
The components that will be visually displayed within the simulator will be the user accessible registers including the CPSR. As an option the user should be able to view memory.
CHAPTER 4 – ARM ASSEMBLY LANGUAGE ANALYSIS
The objective of the assembly analysis is to gain knowledge about the ARM assembly language and to select an instruction set for the simulator. This chapter also discusses some compiler specific issues.
The ARM provides instructions for data processing, branches, register transfers, coprocessor interaction, software interrupts and more. Implementing the full set of instructions is a far to extensive task, way beyond the scope of this project, so a subset of commonly used instructions will have to be defined.
The software interrupt instruction is used to change the processor into another mode. Since the ARM Simulator will only run in user mode, this instruction is excluded.
The coprocessor instructions are used to interact with other processors. They are quite complex and will be excluded along with the software interrupt instructions.
4.2 The selected instruction set
The simulator will include data processing (also referred to as ALU instructions), branch and simple register transfer (memory) instructions.
ALU instructions may be classified as either logical or arithmetic. The ARM logical operations comprise of AND, EOR, TST, TEQ, ORR, MOV, BIC and MVN. Logical operations perform a logical action on all corresponding bits of the operand(s) to produce the result.
The ARM arithmetic operations perform variations of addition and subtraction on the operands and comprise of ADC, ADD, CMN, CMP, RSB, RSC, SBC and SUB. Each operand is treated as a 32-bit integer.
The syntax for most ALU instructions is:
opcode{ condition }{
S } destination, operand1, operand2
Four of the ALU instruction is test instructions and
consist of CMP, CMN, TEQ and TST. These operations produce no result other than
setting the CPSR bits. Both operands are preserved. The S bit is always
implied, however specifying the bit will not cause an error. The syntax for these
instructions is:
opcode{ condition} operand1, operand2
The MOV and MVN ALU instructions move a register or constant into another
register. The syntax for these instructions is:
opcode{ condition }{ S } destination, operand2
Branch and branch with link is required in order to use subroutines. Consequently the system must support labels. A branch forces the program to a new address. If a branch with link is specified, the address of the next instruction is stored in a dedicated register, before performing the branch. These instructions have the following syntax:
B{ L }{ condition }
< expression >
Register transfer operations is used to load and store values from memory. LDR and STR either load or store a value from memory respectively. The ARM also has multiple register transfer operations, capable of loading or storing up to 16 registers with a single instruction.
These will not be supported. The single register transfer operations have the following syntax:
opcode{ condition }{
B }{ T } destination,< address >{!}
These instructions may be both pre- and post- indexed. Initially the simplest form of the memory instructions will be supported and the pre-indexed form will be given prioritised. This will be sufficient to perform simple memory transactions.
Please refer to the last section of the Appendix C for a full description of the instructions discussed in this chapter.
All ARM instructions are conditionally executed. This means that the operation may or may not be carried out depending on the state of the status bits in the processor. If the condition is true the instruction is executed, if not the instruction will have no effect except from using one cycle. An instruction is conditionally executed by adding one of 16 possible, 2-character condition codes to the op-code. Every ARM instruction has a 4-bit field holding the condition under which it will be executed.
|
Mnemonic |
Code |
Condition |
Meaning |
|
EQ |
0000 |
Z set |
Equal |
|
NE |
0001 |
Z clear |
Not equal |
|
CS |
0010 |
C set |
Unsigned higher or same |
|
CC |
0011 |
C clear |
Unsigned lower |
|
MI |
0100 |
N set |
Negative |
|
PL |
0101 |
N clear |
Positive or zero |
|
VS |
0110 |
V set |
Overflow |
|
VC |
0111 |
V clear |
No overflow |
|
HI |
1000 |
C set and Z clear |
Unsigned higher |
|
LS |
1001 |
C clear or Z set |
Unsigned lower or same |
|
GE |
1010 |
N and V the same |
Greater or equal |
|
LT |
1011 |
N and V differ |
Less than |
|
GT |
1100 |
Z clear, N and V the same |
Greater than |
|
LE |
1101 |
Z set, N and V differ |
Less than or equal |
|
AL |
1110 |
- |
Always execute |
|
NV |
1111 |
- |
Never |
Figure 4.1 ARM Condition Codes
Instructions with the S bit set will update the processor status bits according to the result of the operation. Appending a ‘S’ character to the op-code of an instruction sets the S bit.
For the CMP, CMN, TST and TEQ instructions the S bit is always implied.
Almost all ARM instructions are shift instruction, meaning that an instruction can also perform shifting. A shift is carried out by the Barrel shifter, which can perform any of the LSL, LSR, ASR, ROR and RRX shift operations. The shift value may either be a numeric value or a register. If a numeric value is specified it must be in the range 1 to 31. Register-based shift counts are described in section 4.6.
LSL - Logical Shift Left moves each bit by the specified amount to a more significant position. The least significant bits are filled with zeroes. High bits that are shifted outside the 32-bit result range are discarded. The last discarded bit becomes the shifter carry output, which may be applied to the C bit of the CPSR if the instruction involved is a logical operation with the S bit set.

Figure 4.2 Logical Shift Left.
LSR - Logical Shift Right moves each bit by the specified amount to a less significant position. The most significant bits are filled with zeroes. Low bits that are shifted outside the 32-bit result range are discarded. Carry is generated as in LSL.

Figure 4.3 Logical Shift Right
ASR - Arithmetic Shift Right performs almost the same operation as Logical Shift Right. The difference is that the high bits are filled with replicates of the most significant bit of the shifted register instead of zeroes. This means that a negative value is extended with ones and a positive value is extended with zeroes. Carry is generated as in LSR.

Figure 4.4 Arithmetic Shift Right
ROR – Rotate Right reuses the bits that ’fall-of’ on the least significant end by wrapping them around at the most significant position of the result. A Carry is generated in the same way as LSR.

Figure 4.5 Rotate Right
RRX – Rotate Right
Extended shifts the contents one position to the right, inserting the
previous Carry into the most significant bit and then setting the carry to the
value of the bit that ‘falloff’ the least significant end.

Figure 4.6 Rotate Right Extended
4.6 Register based shift counts
If a register is specified as the shift amount, the amount held in the least significant byte is used. If the byte is in range 1 to 31 the result will be the same as a value specified shift. Values of 32 or more produces the results seen in figure 4.7.
|
Shift |
Action |
|
LSL by 32 |
Result zero, carry out equal to bit zero of shifted register |
|
LSL by > 32 |
Result zero, carry out zero |
|
LSR by 32 |
Result zero, carry out equal to bit 31 of shifted register |
|
LSR by > 32 |
Result zero, carry out zero |
|
ASR by >=32 |
Result filled with, and carry out equal to bit 31 of shifted register |
|
ROR by 32 |
Result equal to shifted register, carry out equal to bit 31 of shifted register |
|
ROR by > 32 |
Same result and carry out as ROR n-32 |
Figure 4.7 Shifts of 32 or more
4.7 Immediate operand substitution
The ARM has a 4-bit immediate operand rotate field that specifies a shift operation on the 8-bit immediate value. The immediate value is zero extended to 32 bits and then rotated right by twice the value in the rotate field.
In ARM assembly large constants may be specified directly and the compiler automatically convert (if possible) the constant into the appropriate set of values. The immediate operand substitution is a poorly documented feature in the ARM compiler. A large amount of time was used to figure out how this worked.
|
Hexadecimal range |
Description |
|
0 - 0xFF |
No rotate |
|
0x100 - 0x3FC |
Steps of 4 by rotating right by 30 bits |
|
0x400 - 0xFF0 |
Steps of 16 by rotating right by 28 bits |
|
0x100 – 00x3FC0 |
Steps of 64 by rotating right by 26 bits |
|
0x4000 – 0xFF00 |
Steps of 256 by rotating right by 24 bits |
|
0x10000 – 0x3FC00 |
Steps of 1024 by rotating right by 22 bits |
|
0x40000 – 0xFF000 |
Steps of 4096 by rotating right by 20 bits |
|
0x100000 – 0x3FC000 |
Steps of 16384 by rotating right by 18 bits |
|
0x400000 – 0xFF0000 |
Steps of 65536 by rotating right by 16 bits |
|
… and so on |
|
Figure 4.8 Large operand conversion
If a negative constant is specified as the 2nd operand, the instruction might be substituted with it’s opposite and the 1’s or 2’s complement of the constant is used. Figure 4.9 show the instructions that this rule applies to.
|
Instruction |
Substituted with |
New operand 2 value |
|
ADC |
SBC |
1’s complement |
|
ADD |
SUB |
2’s complement |
|
AND |
BIC |
1’s complement |
|
CMP |
CMN |
2’s complement |
|
MOV |
MVN |
1’s complement |
Figure 4.9 Substitution if second operand is a negative value
Data processing, branch and load/store instructions will be sufficient to produce a realistic simulation of the ARM. Ideally all 16 ALU instructions should be implemented, but considering the extent of the project, this may not be possible. Priority will be given to the ADD, SUB, CMP, CMN, MOV and MVN instructions.
Both branch and branch with link is necessary to provide the ability of accessing and returning from subroutines, hence it follows that the simulator must be able of handling labels. LDR and STR are necessary to provide a means of loading and storing values from memory.
The fact that all instructions are conditionally executed is an important aspect of the ARM therefore all the condition codes should be supported. In addition almost all ARM instructions are shift instruction so common shift operations should be supported.
Compiler specific issues such as large immediate operand substitution and instruction substitution need to be implemented. As the ARM the simulator should support decimal and hexadecimal values.
An extensive set of special cases will need to be considered during implementation.
CHAPTER 5 – REQUIREMENT ANALYSIS
The requirement analysis is a crucial part of the project. Failing to identify, or not understanding the requirements of an application, will not produce a satisfying result no matter how well the rest of the project is carried out.
The user should be able to load, modify and save assembly programs using a built in editor. When the simulator is in this state it is in EDIT mode.
A program has to be built in order to run a simulation. The simulator enters BUILD mode, locking all user controls, while reading, decoding and building the instructions. If an error occurs the simulator aborts the BUILD mode and returns to EDIT mode, re-enabling the appropriate user controls and giving the user an indication of what went wrong. If the BUILD mode completes successfully the simulator enters RUN mode, enabling the appropriate user controls.
The user may now step through the program one instruction at the time. The simulator carries out the instruction and displays the result. A set of instructions can be run using an autorun feature.
The program may be reset while running a simulation. A reset brings the simulation back to the starting point, with the initial values.
The user may select different views of the instructions, including assembly view, binary view and RTL (Register Transfer Language) view. Registers may be seen as binary, hexadecimal or decimal. When a selection is made the simulator displays the correct view.
The user may select to view memory. When the selection occurs, the simulator initialises the memory window and displays it. The memory window can be closed and opened by the user at any point while the simulator is in RUN mode.
The program can not be changed when the simulator is in RUN mode. The user must abort, leaving the simulator in EDIT mode in order to make changes to the program. The program will have to be rebuilt in order to RUN the simulation again.
The user should be able of controlling and storing main settings in the simulator through an options dialog. These settings should be loaded upon program start-up.
5.2 Specification of requirements
The following describes the requirement of the ARM Simulator based on the previous analysis:
The ARM Simulator should:
· Have basic file handling capabilities like load and save.
· Support a variety of ALU, branch and memory instructions discussed in section 4.9.
· Support condition based execution and shifting.
· Handle compiler specific features, such as Negative operand substitution and immediate operand substitution, as described in section 4.7 and 4.8.
· Display the user mode register and the CPSR as described in section 3.7.
· Display the effect each instruction has on those registers, in an easy and consistent matter.
· Offer flexibility. No restrictions should be laid on the number of instructions or the size of a program.
· Provide error messages to help the user find errors in the assembly programs.
The user should be able of:
· Load, edit and store assembly programs
· Using a variety of assembly instructions, including condition codes, different flags and several flavours of syntaxes.
· Run an assembly program consisting of any supported instructions.
· Step through the program one instruction at the time and visually see the effects
· Easily reset the simulation, to run it again.
· View memory contents, including program, user and stack memory.
· View the values of the registers in different number formats, including binary, hexadecimal and decimal.
· View the instructions as one of input, strict assembly, binary or Register Transfer Language.
· Setting and storing basic options within the ARM Simulator, using an option dialog.
CHAPTER 6 – GRAPHICAL USER INTERFACE DESIGN
A lot
of effort was put in the user interface in order to provide the user with the
best thinkable premises of understanding and follow the simulation.
Use
case design was employed in order to identify the requirements of the user
interface. The use cases were derived from the requirement analysis, and
describes the main actions the user may perform on the system.
The ARM Simulator will have to display a vast amount of information simultaneously. Considering that the 16 registers, the CPSR and memory may be shown concurrently the user has a lot of numbers to keep track of. A well-designed GUI can make a great difference when it comes to following the simulation.
When an instruction is executed, no more than 3 registers and maybe the CPSR get affected. The other 13 registers still contain the same value as before the operation. By highlighting the registers where changes actually took place, it will be easier for the user to follow the simulation.
Another feature that may clarify the simulation, is if the memory location pointed at by the program counter is highlighted, and similarly the next instruction in the instruction list. These are of course the same, the value in the memory location is the machine code equivalent of the instruction in the instruction list.
In designing and presenting data we can adopt the idea of the smallest effective difference. The idea is quite simple, but the effects are remarkable. When displaying data it is usual to have some sort of frame or table containing the data. Quite often a black frame is used. The idea is that the lighter that frame, the easier the eye catches the data, which is what we want to display. Consider figure 6.1. A set of frames is displayed, all with a different border. The heavy black border in the table at the left is quite disturbing. The eye is drawn to the frame instead of the text. At the right a light grey border is used, and the contents catches the eye rather than the frame.
|
Contents |
|
Contents |
|
Contents |
|
Contents |
|
Contents |
|
Contents |
|
Contents |
|
Contents |
|
Contents |
|
Contents |
|
Contents |
|
Contents |
Figure 6.1 Border effects (Tufte, [9] and [10])
In GUI design this relates to things like textboxes, comboboxes, lists, labels, grids, frames and so on. A textbox typically has a distinct 3D-border and is usually used for user input. Labels are often used to display static text or data, but have no border at all.
Having considered the different possibilities, a table was chosen to display the registers. The table component within Swing is considered the most heavy and difficult to use, but also the most powerful.
A means of displaying the instructions during a simulation was also needed. An instruction is static during runtime and cannot be changed by the user. A simple list was chosen. A list also provides the ability to select, or highlight, the next instruction to be executed as discussed earlier in this chapter.
The same approach was decided used when designing the memory dialog. A list displaying the memory address and the value contained at that address with the ability to highlight the address pointed at by the program counter.
As discussed in Section 5.1, the ARM Simulator will work in different modes. The edit mode is when the user is working with files, the build mode is a intermediate state where the system is building the program and the run mode is where the user can step through a program. Three solutions were possible and is listed below:
· The main window could contain the editor and a separate window containing the simulation could be spawned when the user builds a program.
· A MDI (Multiple Document Interface) solution could be used, where the editor and simulation is child windows within a main window.
· The main window could contain the editor, and then replace the editor with the simulation components when running a simulation.
After some consideration the last approach was selected. This was done for several reasons. Using several windows is generally not considered to be good design. The memory component, will probably be a separate dialog, so the user will have to keep track of three windows. Using the last approach helps keeping the simulations consistent. If a change is to be made, the simulation has to be stopped and then rebuilt ensuring that the change has been included in the simulation.
6.2 Designing the user interface
It was decided that the user controls would consist of a menubar, containing all possible user actions, and a toolbar containing the most frequently used actions.
Figure 6.2 show the overall use case diagram for the simulator. It defines the main operations a user may perform on the system. The diagram was used as a base when creating the user interface in order to provide the required user controls.

Figure 6.2 Main use case for the ARM Simulator
The
following actions were derived from the use case:
·
Open
and save file
·
Cut,
copy and paste
·
Edit
options
·
Build,
step, reset and stop simulation
·
The
different instruction views
·
The
different register views
·
View
memory
The
user interface was drawn on paper, and is reproduced in figure 6.3

Figure 6.3 The
ARM Simulator in edit mode at the left and run mode at the right.
The use
cases were further derived into sequence diagrams, which are described in the
section 7.8 and in appendix D.
This
chapter describes the main issues considered when designing the ARM Simulator
system. It is assumed that the reader have basic knowledge of Object Orientated
features like objects, interfaces, inheritance, polymorphism and the use of
abstract classes and methods. If this is not the case please refer to [2],
Chapters 6 and 7. These topics are also covered by most introductional books on
Object Oriented languages.
The
first sections discusses initial design issues, describing the approach taken
to create a framework for the ARM Simulator.
The
last section describes the final design of the ARM Simulator, mostly
represented by UML diagrams, as it exists after finishing the implementation.
7.1 Designing the
instruction objects
The
instruction objects make up the core of the system. Within the ARM Simulator a
instruction is responsible of executing itself, set results and tell the system
what instruction to execute next. A great effort was put down in designing
these objects and their connection with the main system.
Each
instruction object had to be capable of
holding all it’s attributes. In addition each instruction should be
capable of executing itself. The first problem encountered was how a set of
instructions could be stored within a datastructure, and be easily accessed at
a later time. If all the objects within a datastructure is of a different type,
the object needs to be identified before it can be accessed, and all possible
objects will need to be instantiated.
The
solution was to use abstract methods and polymorphism. A 3-split model was
designed, comprising of the following elements:
·
an
interface defining all constants needed by any instruction object
·
a
abstract superclass storing the opcode and condition code of a instruction,
this class also defines several abstract methods that any deriving class will
have to implement
·
the
actual instruction object derived from the superclass.
Polymorphism
is quite complex, so a further explanation may be appropriate. The design
consist of a abstract superclass ArmInstruction.
This is subclassed by ArmAddInstruction, ArmSubInstruction, ArmMovInstruction
and so on. The superclass defines several abstract methods that each subclass
has to implement. To invoke a method on a ArmAddInstruction object, a
superclass reference to that object is used.
In
practice this means that the ARM Simulator can always use a superclass
reference to access any instruction object, and do not need to know the exact
type of that object.
This
approach result in an easy and transparent way of working with instructions. It
allows any instruction object to be accessed via an reference to the
superclass. Any method that is declared abstract may then be invoked on this
reference, which will cause that method to execute in the referenced object.
Within
a instruction object everything is stored numerically, except from some label
values and the original instruction line as it was read from file. Matching
numbers are much faster than matching strings, so a instruction should be
converted to numeric values upon build. The full instruction set and constants
is declared in an interface, ArmInstructionSet that is implemented by all
instruction objects. Below is a extract of the ArmInstructionSet interface.
// Binary
representation of elements BINVALS[]={’0000’,’0001’,’0010’……
//0–15 ALU Instructions ’0000’,’0001’,’0010’…… //16–31 Condition codes ’0000’,’0001’,’0010’…… //32-49 Registers … more constants } // Textual
representation of elements ASMVALS[]={’AND’,’EOR’,’SUB’……
//0–15 ALU Instructions ’EQ’,’NE’,’CS’,…… //16–31 Condition codes ’R0’,’R1’,’R2’…… //32-49
Registers … more constants } public
static final int AND = 0; public
static final int EOR = 1; public
static final int SUB = 2; ………… more
instructions public
static final int EQ = 16; public
static final int NE = 17; public
static final int CS = 18; ………… more
condition codes public
static final int R0 = 32; public
static final int R1 = 33; public
static final int R2 = 34; ………… more
registers
Consider
an ArmSubInstruction object representing the following instruction :
SUBNE
r0, r1, r2
Within
the instruction object the opcode will be stored as 2, the condition code will
be stored as 17 and the three registers will be stored as 32, 33 and 34. The
arrays containing binary and assembly values are used both when identifying and
verifying objects and when creating the machine code representation of an
instruction. The constant SUB has the value 2, a look-up of position 2 in the
array of binary values returns ’0010’ which is the machine code representation
of the SUB opcode. In addition each element within an object has an identifier,
which is used to determine what is expected from that element. A shiftvalue
will get the constant identifier SHIFTVAL, so that the system can determine
that this value is supposed to be a 5-bit integer.
Having
determined a design for the instruction objects, a means of dynamically
creating instruction objects was needed.
After
careful consideration the ’compiler’ part was designed as an independent object
instead of integrated as methods within the main class. This approach add some
complexity to the overall design, but simplifies the process of adding support for new instructions or even
replace the ’compiler’ if necessary.
Based
on the result from the assembly analysis the ’compiler’ had to support the
following:
·
ALU
instructions with three operand syntax.
·
ALU
instructions with two operand syntax.
·
Branch
and branch with link syntax (meaning that labels must be supported).
·
Basic
memory instruction syntax.
·
Flags,
condition codes, shifts and special cases that may be used within any of the
above syntaxes.
·
Compiler
specific issues such as immediate operand substitution and negative operand
substitution.
The
first design of the ’compiler’ was built to support ALU instruction with two
and three operand syntax. Due to it’s complexity some pseudo code was written
to aid the general design. The pseudo code covers all types of instructions.
if
instruction is of type alu then read_alu_instruction
else if
instruction is of type branch then read_branch_instruction
else if
instruction is of type memory then read_memory_instruction
else
instruction is invalid
Figure 7.1 Pseudo
code for determining the what type of syntax to expect
verify
and convert opcode //
any ALU opcode
verify
and convert condition_code //
any cc, optional
verify
and convert condition_flag //
the S flag, optional
verify
and convert destination_register //
always a register
if alu
instruction is three operand
verify and convert operand_one_register // always a register
verify
and convert operand_two_value_one //
register or immediate
verify
and convert operand_two_value_two //
null or a shift
verify
and convert operand_two_value_three //
null, register or immediate
report
error or create instruction object
Figure 7.2 Pseudo
code for creating a ALU type instruction
Only
the ALU code is included here, the branch and memory equivalents are almost
identical. When applying this to implementation each line would typically refer
to a method handling a specialised task.
The
system design now consisted of a set of instruction objects, a object capable
of reading, verifying and creating instructions and the main class
containing the GUI. The instruction
reader object is what ties the GUI and instruction objects toghether. The only
instruction object known by the Simulator is a reference to the superclass. The
’compiler’ knows of all possible instruction types and instanciates one object
of each instruction.

Figure
7.3 Creating instructions
This
design makes up the framework of the ARM Simulator. It provides scalability
when it comes to adding new instructions and a transparent handling of
instruction objects within the main class. A new instruction is supported by
adding it’s keywords to the interface, upgrading the instruction reader to
support the syntax if not already supported and create an instance of that
instruction object within the instruction reader. The rest of the system
remains unchanged and only relates to a reference to superclass ArmInstruction.
When
working with objects there is no limit on how many instances that can be
created. The ARM Simulator need to save the instruction objects as they are
being created. The system should not have any restrictions on the number of
instruction. One approach could be to count the number of instructions prior to
a build, in order to allocate a correctly sized array. This approach was
rejected in favor of a vector, which is a dynamic datastructure. A vector is
capable of holding any type of object.
7.5 Designing a shared datamodel
It was
desired to have the whole system share the same datamodel. In Swing this is
possible because of the Model View Controller architecture (Please refer to
Appendix F for more information on Swing and MVC). A table, which is used in
the Graphical User Interface to represent the registers, may use a custom
datamodel. Such a datamodel simply defines the initial data and several methods
used by the table to retrieve and set values.
The
advantage of this approach is that the whole system access the same datamodel,
guaranteeing that the datamodel is consistent. Passing the datamodel to a
instruction upon execution allows the instruction object to modify the data
using call by reference.
As
within a real processor it was desired to have the program counter control
execution. Due to the shared datamodel design this was a quite easy task. Each
instruction object is responsible of updating the program counter so that it
points to the next instruction to be executed.

Figure 7.4 Main
framework of the ARM Simulator. Program counter controls execution.
In order to view memory contents, and load and store from memory a memory model was designed. The allowable address range was decided to be 0x00000000 to 0x7FFFFFFC, which is the maximum positive addressing range a register can handle, leaving 536,870,911 effective memory addresses available. This is of course way more than the simulator will be able of handle, but it add flexibility to the memory handling.
As with the storage of
instructions, a dynamic datastructure was desired to represent memory, so that
scalability could be retained. A hastable was selected, using the memory
address as the key and the memory value as the value. It was decided that only
memory used by the program or accessed by the user should be stored. All memory
addresses that are not in the hashtable are considered empty and are never
displayed to the user.
The organisation of memory
is quite simple. Program memory starts at zero and goes to whatever is
necessary. The user has full access to any address in the range.
In
order for the simulator to handle nested subroutines with several subsequent
returns, a means of storing more than one return address was needed. The problem
was solved by designing a simulated stack. The stack is of course represented
by a stack allowing an infinite number of branches with link. It was decided
that the stack should be located at the top of memory, running top down.

Figure 7.5 Stack
representation
This
design requires a register to be reserved as stack pointer, making this
register unavaliable to the user. It was desired to let the user decide what
register to use as stackpointer and also have the ability to disable the stack
simulation, leaving all registers free.
7.8 Sequence and class diagrams
Some
sample diagrams have been included within the report. For the full set of
diagrams, please refer to appendix E.
The sequence diagrams are described both visually and textual. These diagrams have a higher level of detail than the use case diagram, describing the actions carried out by both the user and the system. They do not however, describe in detail how the system behaves in order to, for example, read a file.

Figure 7.6 Sequence diagram describing the file open action
The overall class diagram describes the main interaction of the classes within the ARM Simulator software.
Figure 7.7 The ARM Simulator class diagram
Class diagrams express the structure of the system, in terms of classes and their relationships. A class is described by its class name, it’s attributes and it’s methods. Figure 7.8 describe the abstract class ArmInstruction, which is the superclass of all instruction, objects within the ARM Simulator.

Figure 7.8 The ArmInstruction class in its final
form
The ArmInstruction class holds the characteristics all ARM instructions have in common. Every instruction has an opcode and any instruction may be conditionally executed. The ArmInstruction class holds the opcode and condition code for any subclass. The methods displayed in Italics in figure 7.8 are abstract methods and must be implemented for each derived class of ArmInstruction from which objects are instantiated.
Figure 7.9 describes class ArmAddInstruction that is derived from ArmInstruction.

Figure 7.9 – Class ArmAddInstruction
The ArmAddInstruction describes a typical instruction
object. All instructions within the ARM simulator are designed in this way. The
differences are within the ‘executeInstruction()’, ‘getAsmInstruction()’,
‘getBinInstruction()’ and ‘getRtlInstruction()’ methods. In addition, the
variables vary slightly because of differences in syntax and variations in the
number of parameters.
This chapter describes some of the main issues carried out during implementation. High priority has been given in building the simulator as accurate as possible, all down to binary representation of the instructions. To achieve this a lot of effort has been put in functionality that is not directly visible to the user.
The
system is implemented using the Java Software Development Kit (SDK) freely
avaliable from SUN Microsystems. For more information about the choice of
language and why the ARM Simulator is developed as an application and not an
applet, please refer to appendix F.
It is assumed that the design chapter has been read prior to reading this chapter.
The
first part of the implementation involved creating the GUI, based on the design
discussed in section 6.1 and 6.2.

Figure 8.1 The
ARM Simulator in edit mode
The
user interface was implemented right before christmas and offered some challenges
due to the complexity of certain Swing components, like the Jtable used to
display the registers. Having created the user interface the functionality of
the editor was added. The editor offers simple file handling capabilities
similar to the ’Notepad’ application on the Windows platform. Figure 8.1 show
the the ARM Simulator in Edit mode.
8.2 Implementing the instruction objects
To start with, the classes necessary for representing an ADD instruction were written. The implementation was done based on the design described in section 7.1. At this point most of the ALU instruction constants were added to the interface, as well as all register constants and identifiers for the appropriate values. The first implementation was only capable of storing the values within the instruction object and returning a string representations of the instruction in four different formats. These comprised of the following:
· The actual input, which is the line read from the users file.
· Strict assembly, which is the result of reversing the internal storage of the instruction into assembly, appending default flags and using uppercase.
· Binary, which is the exact machine code representation of the instruction.
· Register Transfer Language.
The
’executeInstruction’ method was only defined at this stage and was first
implemented after creating the instruction reader component and integrated it
with the user interface.
8.3 Implementing the instruction reader
The instruction reader was written based on the design issues described in section 7.3. In order to create the instructions, the simulator needed a ’compiler’ to read, verify and create the instructions, handling any errors that might occur. Rather than handling the instruction creation within the GUI class, a custom object was designed and written.
When building the program the ArmSimulator class read one line at the time from the users file. This line is tokenised and each token is stored in a string array. A ’compiler’ object is created, passing the array as a parameter. The ‘compiler’ then identifies, verifies and creates the appropriate instruction object. If the operation terminated successfully, the instantiating class retrieves and stores the instruction object. This process is repeated until all code is processed.
The following pseudo code describes the instruction creation:
while( readline ) {
tokenize line
store tokens in array
create a new compiler
object with the array as parameter
if compiler completed
succesfully {
get instruction
object and store it in a vector
}
else {
get and display
error message
abort reading
}
}
The ’compiler’ needed to support compiler specific issues like large immediate operand substitution and automatic instruction substitution (Please refer to sections 4.7 and 4.8 for more information about these subjects). Both the immediate operand substitution and negative operand substitution were created as independent classes, instantiated by the ’compiler’ only when needed.
Each instruction object has a method ’executeInstruction()’ to carry out their operation.
Program execution is fully controlled by the program counter value, which is updated by each instruction as it executes. The built in ‘compiler’ creates a vector of instruction objects during build. The program counter is used to determine what instruction object in the vector that is waiting to be executed.
An instruction object is responsible of updating the registers according to the result of the operation. This is achieved by having each instruction update the register datamodel using call by reference. The register datamodel is directly connected to the table displaying the registers in the GUI, where custom-written renderers update each cell, using the appropriate colour.


3

![]()

Figure 8.2 The ARM Simulator running a simulation
Figure 8.2 shows a screenshot of the ARM Simulator running a simulation.
1. Any register that was changed during last operation is rendered black
2. The next instruction to be executed
3. The hexadecimal value seen in the memorydisplay is the actual encoding of the instruction. 0xE285547F equals 11100010 10000101 01010100 01111111 in binary. If we decode this according to the ALU instruction format we get the actual instruction.
|
1110 |
00 |
1 |
0100 |
0 |
0101 |
0101 |
0100 |
01111111 |
|
AL |
|
I |
AND |
S |
R5 |
R5 |
4 |
127 |
Register 15, the program counter points to next instruction in memory to be carried out. The program counter is always updated and will always be rendered black.
In order to support conditional execution a custom class was written. This class receives an instructions condition code and the current CPSR flags as parameters, and return true or false depending on the test result.
All instruction objects instantiate a ConditionHandler object, which decides whether execution is to be carried out or not. If the instruction is not to be executed, it does nothing but updating the program counter.
In order to support shift instructions a new class was designed and implemented. The ArmBarrelShifter class is capable of perform LSL, LSR, ASR and ROR shifts. All instruction objects instantiates an ArmBarrelShifter object, which perform the required rotation and returns the result.
The branch instruction was derived from the same superclass as the ALU instructions. Each branch object holds its target and, if a branch with link is specified, its return address. When a branch object executes, it writes the target address to the program counter. If a branch with link was specified the return address is written to the link register (r14).
The addresses are retrieved during program build. When a branch instruction is encountered, the simulator searches for a matching label. The address of that label is then stored as the target address, and the return address is set to the address of the branch instruction + 4, which points to the next word aligned instruction. A missing label causes the build to halt, and an error message to be displayed.
An autorun feature was implemented to offer the user the ability of running a set of instructions without having to step through each instruction. The user can either run to a label or run a user-defined number of instructions. The implementation of this feature required no new coding except from creating the dialog. Instructions are executed in the same manner as
described in section 8.5, but the display is not updated until the last instruction is executed.

Figure 8.3 The ARM Simulator Autorun feature
8.9 Other implementation
issues
Several
utility classes were written during implementation dealing with everything from
number conversions to customizing user interface components.
A simple configuration utility allows the user to enable stack simulation and select register and instruction views. The setting is of course saved and loaded the next time the user starts the application.

Figure 8.4 The ARM Simulator options dialog
A small HTML based help system containing a lightweight browser was also included. The documentation within the help system is not complete.

Figure 8.5 The
ARM Simulator help system
This chapter describes the testing which was carried out on the ARM Simulator application. Due to shortage in time, not all functionality could be tested. The full system consists of 44 classes containing several hundred methods.
Three test methods have been used. ’Module testing’ refers to the testing of classes. This method has been carried out throughout the implementation, testing each new part before integrating it with the full system.
’State boundary testing’ refers to testing the system with boundary values. ’System testing’ refers to an overall systems test. These two have been used in the testing phase of the project.
All tests are performed with registers and processor flags initially set to zero. No testresults are included in the report. For the full set of results please refer to appendix D
9.1 Testing large operand substitution
If a value larger than 255 is specified as the second operand this must be substituted with a value that goes within 8-bits, but when right rotated with a doubled 4-bit value produces the original value.
The operand substitution is handled by class ArmRotateFinder. This class receives the large immediate value as a parameter and if the constant can be generated, the instantiating class can retrieve the immediate value and the rotate value. Considering that this is an independent object it can be tested independently. If it produces the correct result for one instruction, it will work with any instruction.
When it comes to executing the instruction, the reverse operation must be done. This is handled by class ArmImmediateRotator.
A small test program was created using values stretching from small to maximal. During the simulation both the substituted values and the results were checked for correctness.
All instructions produced the expected result and created valid substitution values for the large constants. No bugs were detected during this test.
Shifting is handled by class ArmBarrelShifter. This class is used only if the shift operation involves a register as the second operand. All shift operations are carried out by the class ArmBarrelShifter. This means that if this produces the correct result with an ADD instruction, it will also be correct for any other instruction. For more information on how the shift operations works, please refer to section 4.5 of the report.
Test programs were written to test each of the shifts, and the results were checked for correctness. No errors were encountered during these tests.
9.3 Testing conditional execution
Conditional execution is handled by class ArmConditionHandler. Each instruction instantiates this class upon execution, and either gets permission to execute or is denied execution.
A large test program was written and simulated, testing all the condition codes. Each instruction result was also checked for correctness.
A bug in the MOV instruction was detected. If the condition code caused the instruction not to be executed, the program counter did not update and the program halted. The same error was located in the MVN, CMP, CMN, TEQ and TST instructions. This error is fixed.
9.4 Testing negative operand substitution
Instruction substitution occurs when an instruction has a negative second operand. The substitution is performed during program build, before creating the instruction object. This operation is carried out by the class ArmNegativeSubstitution. Any instruction that detects a negative second operand uses this class to determine if it should be substituted and, if that is the case, to retrieve its substituted values. However, not all instructions are substituted.
For more information about instruction substitution please refer to section 4.8.
A test program was written and simulated. All instructions produced the expected result and created valid substitution values for the large constants. No bugs were detected during this test.
9.5 Testing the Simulator with real users
In order to identify any problems with the GUI and user interaction, real users were set to test the program. They were given a set of programs and asked to run them. No instructions were given on program usage, but the help system was available (although not finished). After running these programs they were asked to write their own programs and try them out. The users were encouraged to play around with the program as much as possible, and also to make any remarks or thoughts they had regarding the interface.
This test proved to be the most successful. Two bugs were found and a lot were learnt by observing the users while they used the program.
A common mistake was to try to edit the program while running. The users selected an instruction in the list and tried to edit it. This was repeated a couple of times before they realised that they had to stop the simulation. The users quickly learnt to stop the program before trying to edit it, but it raises the question if a listbox is a good choice for displaying the instructions.
In addition two bugs were detected. Specifying an out of range integer value in the autorun dialog caused the simulator to crash. The other ’bug’ appeared in the open and save dialogs. This did not happen every time but occurred a couple of times during the test. The users double-clicked on a folder name, causing the folder not to open, but allowing the user to change its name. The solution seems to be to double click the folder icon and not the folder name. The open and save dialogs are however part of the Java API, so this bug must be dedicated to Sun Microsystems.
The bug with the autorun feature is fixed.
9.6 Testing the simulator on different platforms
The software has been tested and run on the following platforms:
· Windows95 using Java SDK 1.2.2
· Windows NT 4.0 using Java SDK 1.2.2
· Linux Redhat 5.2 using Java 1.2.Beta and Java 1.2.2
Unfortunately these are the only platforms the software has been tested on, but it works fine on all of these.
The aim of the project was to produce a simulation of an ARM processor, allowing the users to load and execute their own assembly programs, visually showing the results of the execution.
The following list summaries the main achievements of the software:
· The system fully supports the requirements described in the project specification.
· All data processing instructions are supported, supporting most syntaxes.
· Branch and branch with link allows usage of subroutines.
· Simple memory instructions are supported.
· All condition codes can be used with any instruction.
· A simulated stack enables the system to handle nested subroutines.
· Memory view is supported.
· A full-featured editor with file handling capabilities is built in.
· The system is scalable. There are no restrictions on the number of instructions.
The system fully supports the requirements described in the project specification.
10.2 Personal thoughts
Having no pre-knowledge of systems architecture, processors or assembly language I was quite anxious about how the project would turn out. A large effort was put down during analysis to gain the necessary knowledge to get started. During the project I have gained a thorough understanding of the ARM processor and the ARM assembly language, as I had to look at these areas in detail.
In advance of the project I had never used UML. While carrying out the project I have learned how to model and design a system using UML diagrams.
I had some experience with the Java programming language, but had never used Swing as a graphical user interface. The project has helped me brush-up old knowledge, as well as I have had to learn new things. I have come to appreciate the Java language as powerful, but yet simple to learn and easy to use.
Some important lessons have been learned during the project. One is the importance of continuos documentation throughout the project. The documentation produced during the different phases of the project was of great help when it came to produce the final report.
I have also understood the importance of the ability to approach a new subject, isolating the important aspects and then filter out the information needed to gain a broad overview.
Another important aspect is the ability to carry out a project in a consistent matter, making the correct decisions and selecting the right methods for solving the different phases of the project.
11.1 Completing the instruction set
The full instruction set could be implemented. Currently the full set of data processing and branch instructions is implemented. Single register load and store is supported, but only with pre-indexing. By completing memory instructions and maybe adding multiply, co-processor and software interrupt instructions, the instruction set will be close to the actual ARM.
Serialization is a powerful object-oriented feature, enabling objects to be saved and loaded preserving their current state. By implementing serialization support, instruction objects could be saved directly to file. This enables the user to store and load ready built simulations, sparing the user from having to rebuild a program each time. It would also introduce the possibility of changing programs during a simulation.
The ARM Simulator does not have anything like a true compiler. It has a means of decoding, verify and create instruction objects. By implementing a truer compiler, performing true parsing, the program build process could be much more efficient in terms of speed and memory usage.
11.4 Improving the help system
A more sophisticated help system could be implemented. A package called Java Help for creating Java based help systems is actually available from SUN. The only drawback is that the full package is several megabytes. The help system as it exists now is not finished. Full documentation of the instruction set should be included, together with information on the ARM architecture and a complete users guide.
11.5 Converting the Application to an Applet
Converting the application to an applet would make the simulator accessible through a browser. Considering the security restrictions for Java Applets most file handling capabilities would be needed to be removed. Instead a means of loading URL’s could be included, enabling a user to type in a local or remote URL to retrieve a file.
The simulator could be upgraded to support the 16-bit Thumb instruction set, supported by some ARM processors. This is a lightweight instruction set, often containing only two operand instructions and restrictions in the conditional execution abilities.
The ARM can
support both Big and Little Endian memory addressing. It might be an idea to
support this feature. Floating point emulation could make a useful add-on.
Breakpoint support would be a nice feature.
The following books have been consulted during the project period:
|
[01] |
VLSI Technology, Inc. |
Acorn Risc Machine Data Manual. Prentice Hall, 1990. ISBN : 0-13-781618-9 |
|
|
|
|
|
[02] |
Deitel & Deitel |
Java How To Program. Second Edition. Prentice Hall, 1997. ISBN : 0-13-899394-7 |
|
|
|
|
|
[03] |
M.Morris Mano |
Computer Engineering, Hardware Design. Prentice Hall, 1998. ISBN : 0-13-162926-3 |
|
|
|
|
|
[04] |
Alan Clements |
68000 Family Assembly Language. |
|
|
|
|
|
[05] |
G.W Gorsline |
Computer Organization : Hardware / Software. Prentice Hall 1986. |
|
|
|
|
|
[06] |
- |
Graphic Java 2, Mastering the JFC, third edition. Sun Microsystems Press. |
|
|
|
|
|
[07] |
Pierre-Alain Muller |
Instant UML, Wrox Press, 1997. ISBN : 1-861000-878-1 |
|
|
|
|
|
[08] |
Ivor Horton |
Beginning Java 2. Wrox Press. ISBN : 1861002238 |
|
|
|
|
|
[09] |
Edward R. Tufte |
Visual Explanations. Graphics Press, 1997. ISBN : 0961392126 |
|
|
|
|
|
[10] |
Edward R. Tufte |
Envisioning Information. Graphics Press, 1990. ISBN: 0961392118 |
|
|
|
|
|
[11] |
Jenny Preece |
Human-Computer Interaction. Addison-Wesley, 1994. ISBN : 0-201-62769-8 |
|
|
|
|
The following electronic documents have been consulted:
|
[01] |
ARM Ltd. |
ARM Software Development Toolkit Version 2.0, Reference Manual. Advanced RISC Machines Ltd, 1995. Document number : ARM DUI 0020D |
|
|
|
|
|
[02] |
ARM Ltd. |
ARM Software Development Toolkit Version 2.0,
Windows Toolkit Guide. Advanced RISC Machines Ltd, 1995. Document number :
ARM DUI 0022B |
|
|
|
|
|
[03] |
ARM Ltd. |
ARM 7 Data Sheet. Advanced RISC Machines Ltd, 1994. Document Number : ARM DDI 0020C |
|
|
|
|
|
[04] |
ARM Ltd. |
ARM Software Development Toolkit Version 2.0, Programming Techniques. Advanced RISC Machines Ltd, 1995. Document number : ARM DUI 0021A |
|
|
|
|
|
[05] |
ARM Ltd. |
ARM Instruction Set Quick Reference. Advanced RISC Machines Ltd. Document number : ARM QRC-0001C |
|
|
|
|
The following webpages have been consulted
|
[01] |
- |
ARM Ltd. Homepage http://www.arm.com/ |
|
|
|
|
|
[02] |
- |
Sun Microsystems Java page http://java.sun.com/ |
|
|
|
|
|
[03] |
- |
Alan Clements website on the SCM-intranet |
|
|
|
|
Other references consulted:
|
[01] |
M.Etchells |
Assembly Language Simulator, 1997. |
|
|
|
|
APPENDIX A – PROJECT SPECIFICATION
The objective of this project will be to design and develop an ARM processor simulator, capable of reading and executing ARM assembly instructions. The simulator will have a Graphical User Interface. It will visually show how the execution of the assembly instructions affects the memory, registers and other components of the ARM architecture. Users will be able to load and execute their own assembly programs.
The analysis phase of the project will be to examine the behaviour of the ARM system and see the effect different instructions have on the components that make up the system.
When the analysis-phase is finished, I will start the design phase. This includes everything from sketches of the GUI and designing the simulator down to appropriate detail, probably using UML or other tools. The code will be designed down to fine detail, including classes and methods. This will make the implementation quicker and easier.
Implementation will be done using an appropriate development language, probably JAVA.
The testing will first be unit-based, testing each part as I go along. Then I will choose an appropriate testing strategy for the whole system.
All software will be fully documented and be produced to common standards.
APPENDIX B – PROJECT TIME SCHEDULE
|
Week |
Description |
Comments |
|
|
|
|
|
43 |
Project start |
|
|
44 |
Background reading |
|
|
45 |
Background reading |
|
|
46 |
Background reading, Specification |
|
|
47 |
Specification, Analysis |
Specification by 23.11.1999 |
|
48 |
Analysis |
|
|
49 |
Analysis, Design, GUI |
HCI considerations |
|
50 |
Analysis, Design, GUI |
HCI considerations |
|
51 |
Christmas |
|
|
52 |
Christmas |
|
|
01 |
Christmas |
|
|
02 |
Start implementation |
|
|
03 |
Implementation |
Interim report by 18.01.2000 |
|
04 |
Implementation |
|
|
05 |
Implementation |
|
|
06 |
Implementation |
|
|
07 |
Implementation |
|
|
08 |
Testing |
|
|
09 |
Testing |
|
|
10 |
Documentation |
|
|
11 |
Documentation |
|
|
12 |
Documentation |
|
|
13 |
Hand over |
Final report by 28.03.2000 |
|
|
||
|
|
||
|
|
||
|
Documentation will be done continuously throughout the project. |
||
|
|
||
|
Testing will be a continiuos process, testing each part as I go along. When the system is implemented a proper method will be selected to test the system as a whole. |
||
|
|
||
|
|
||
The ARM
Simulator user guide is divided into the following sections:
Chapter
1 – Introduction
Starting the ArmSimulator
A visual guide to the program
Quick start
Problems
Chapter 2 - Working with files
Loading, editing and saving files
Edit, copy and paste
Chapter 3 - Running a simulation
Starting a simulation
Executing the instructions
Running a batch of instructions
Reset a simulation
Stopping the simulation
Keyboard shortcuts
Chapter 4 - Other features
Memory viewer
Instruction and register views
Stack simulation
The options dialog
Chapter 5 - Assembler syntax
Valid instructions, conditions and shift operations
Using labels
Starting the ArmSimulator
You will need to have the Java Runtime Environment installed on your machine. The version number should be at least 1.2.
On a Windows system you should be able to doubleclick the file called ArmSimulator.jar. If this does not work, open a command shell and switch to the directory where the ArmSimulator.jar file is resident. Type the following at the prompt :
path_to_java\bin\jawav
–v ArmSimulator
If this does not work, you have an error in your java installation. Try to de- and then reinstall it.
On a Linux/Unix system you need to start the program from a command shell. Start a shell and type the following at the prompt :
path_to_java\bin\jawav
–v ArmSimulator
Mac users should be able to drag and drop the ArmSimulator.jar file on the jawav tool in your java\bin directory. If this does not work, follow the instructions in your java documentation on how to set up a shortcut for a java program.
A visual guide to the program
The ArmSimulator work in two modes. One is the EDIT mode, where you load, store and edit your assembly programs. The other is RUN mode that actually run the assembly programs you worked with in EDIT mode. Figure 1.1 show the ARM Simulator in EDIT mode with a program loaded from file.

Figure 1.1 - The ARM Simulator in EDIT mode with a program loaded from
file.
The toolbar functions are explained in figure 1.2. The leftmost 7 functions are avaliable only when working in EDIT mode. The next 4 functions are avaliable in RUN mode only, and provide the functionality needed to step through a program. The rightmost button, Help, is always avaliable.

Figure 1.2 – The toolbar functions

Figure
1.3 – The ARM Simulator in RUN mode running the file from figure 1.1
Quick Start
There are some example programs bundled with the ArmSimulator. Start the simulator, select File from the menu and then Open. Browse to the directory where ArmSimulator is installed. Select the programs directory, select a file and click Open.
The selected file should now appear in the ArmSimulator window. To run the program, select Program from the menu and then Build.
The simulator window now split, a list is seen on the left and a table showing the registers on the right. You can now start the simulation by selecting Program from the menu and then step.
The ArmSimulator will then execute the statement, the program counter (r15) will increase and focus will be moved in the list on the left.
To view memory select View from the menu and the Memory. A dialog box will appear.
To reset the simulation select Program and the Reset.
Chapter 2 - Working with files
The ArmSimulator has a fully featured editor. It enables you to load, edit and save files similar to the Windows Notepad utility.
Loading a file
To load a file, either select the folder icon on the toolbar or use the File menu. A open file dialog will appear. Select the file you want to open and either doubleclick it or click the open button. If the file is large the open process may take a while.
The selected file should appear in the ArmSimulator editor. The keyboard shortcut for this operation is Control + O.
Edit a file
Editing files is done as in any other editor. Text can be selected, deleted, copied and pasted.
Saving a file
To save a file, select the save icon from the toolbar or use the File menu. If the file already excists the saving process is done automatically. If you want to save the file using another file name, you can select File->Save as… which will launch the save dialog.
The keyboard shortcut for this operation is Control + S.
Creating a new file
To create a new file, simply select the new icon fro the toolbar or use the File menu. If a file is already open and a change has occured since last save operation, the system will prompt you if you want to save your changes.
The keyboard shortcut for this operation is Control + O.
Cut, Copy and Paste
These commands are avaliable from the toolbar or the edit menu. To cut or copy simply select a piece of text and use the desired command. To paste a piece of text, put the cursor in the position where you want the text and select paste.
The keyboard shortcuts for these operations are:
Cut Control + X
Copy Control + C
Paste Control + V
Chapter 3 - Running
a simulation
Starting a simulation
To start a simulation, open the desired file or type the instructions right into the editor. Select Build from the toolbar or use the Program menu. If no errors occur, the program enters run mode.
If an error was encountered, an error message appears in the statusbar of the window. It tells you what type of error that was found and the linenumber of the instruction.
The keyboard shortcut for building the program is Alt + 5.
Executing the instructions
The ArmSimulator lets you step through the program one line at a time. This is done by selecting Step from the toolbar or using the Program menu. The simulator executes the instruction, updates the program counter, displays the changes and highlights the next instruction to be executed.
Reset a simulation
If you missed a step in simulation, you can reset it by selecting Reset from the toolbar or using the Program menu. A reset causes the simulation to og back to the entry point of your program.
Running a batch of instructions
The simulator has an autorun
feature to run large chunks of code, or running to a specific label. Select
Autorun from the Program menu. The Autorun dialog will appear (figure 3.1).
Select the desired action
and click OK to start. The simulator will run until it reaches the criteria
set, or if no such criteria can be fulfilled, until the program ends.
The simulation can now be continued from this point by stepping through the instructions.

Figure 3.1 – The ARM
Simulator AutoRun Dialog
Stopping the simulation
To stop a simulation, select Stop from the toolbar or use the Program menu. Stopping a simulation causes the ArmSimulator to go back in edit mode.
Keyboard shortcuts
The keyboard shortcuts for these operations are:
Step Alt + 1
Autorun Alt + 2
Build Alt + 5
Reset Alt + 8
Stop Alt + 9
Chapter 4 – Other features
Memory viewer

The ArmSimulator includes a memory viewer. To launch it, select Memory from the
toolbar or use the view menu.
Figure 4.1 – The ARM
Simulator memory dialog
At left you see the memory address of the instruction. The second hexadecimal value is the representation of the instruction in memory. The rightmost letter describes the ’owner’ of the memory address and can be any of P for program, U for user or S for stack.
Only memory addresses used by the program, the stack or accessed by the user is shown in the dialog. Any other memory address is considered empty and is therefore not necessary to show.
The memory dialog is updated in the same way as the instruction list in the ArmSimulator window. Each time the program counter is increased, the instruction pointed to is highlighted as shown in figure 4.1.
Instruction and register views
Another feature of the ArmSimulator is that both instructions and register values can be seen in different ways.
Instructions can be seen as:
Input - the same as the isntruction read during program build
Strict assebly - the way instructions are stored internally
Binary - the binary representation of this instruction
Rtl - this instruction expressed in Register Transfer Language
Register values can be seen as:
Binary - the binary representation of the value currently stored in a register
Hexadecimal - the hexadecimal representation of the value currently stored in a register
Decimal - the decimal representation of the value currently stored in a register
You can change these views during runtime. Select either Instructions or Registers from the View menu and select the desired view. These views can be set permanently in the ArmSimulator configuration dialog. Your setting will then be saved and loaded during startup. Please refer to the section called ‘The options dialog’ for instructions on how to do this.
Stack simulation
In order to handle nested subroutines the ArmSimulator provides a simulated stack. The stack is not enabled by default, so you will have to do this by selecting Options from the Edit menu.
Select the tab labeled ’Stack’, check the ’Activate Stack’ option and select a register to use as stack pointer.
When the stack is enabled BL (Branch with link), will save the return address to the stack. Return as usual with MOV PC, LR. This enables you to use nested subroutines in an easy and convinient matter.
The register selected as stack pointer is always read-only when stack is enabled. Any attempts to write to this register will cause an error. The stack is located at top of memory. You will see that the stack pointer contains large values. The stack values can bee seen in the memory dialog. The values are labeled with S.
The options dialog
The ArmSimulator provides a simple configuration tool where you can store your setting. Select Edit->Options to launch the dialog. The first tab contains the stack simulation setting. Please refer to the previous chapter for a more thorough explanation of this setting. The tab is shown in figure 4.2.

Figure 4.2 – The
Options dialog with stack settings active
The second tab enables you to choose what instruction view to use as default. The third tab defines the register view. Select the desired view from the dropdown box.
Click Ok to save your changes, or cancel to abandon. The ArmSimulator will save your changes and load them the next time the program is started.
Chapter 5 -
Assembler syntax
Valid instructions, conditions and shift
operations
This chapter discusses these subjects in the displayed order:
·
Data processing instructions
·
Branch
instructions
·
Memory
instructions
·
Shifts
Data processing
instructions
The data processing instruction set comprise of 16 different operations.
The syntax within the ARM Simulator is described below.
(1) MOV, MVN - single operand instructions
opcode{ condition }{ S } Rd, Operand2
(2) CMP, CMN, TEQ, TST – logical instructions
opcode{ condition } Rn, Operand2
(3) AND, EOR, SUB, RSB, ADD, ADC, SBC, RSC, ORR, BIC – arithmetic
instructions
opcode{ condition }{ S } Rd, Rn, Operand2
{ condition } is a
optional two character condition code
{ S } set
condition codes if present (implied for CMP, CMN, TEQ and TST)
Rd, Rn a
register
Operand2 is any
of :
Rm
#expression1
Rm shift Rs
Rm shift
#expression2
Rm a
register
Rs a
register containing a shift count in the range 1..32
shift any
of LSL, LSR, ASR, ROR
#expression1 any
signed expression shiftable into an 8-bi value
#expression2 any
positive absolute shift count in the range 1..31
ADC – Arithmetic add
with carry
ADC adds two 32-bit 2’s complement operands, storing the result into a
designated register. If the carry bit was set prior to the instruction a value
of +1 is added to the sum. Nothing is added if the carry bit was not set.
Operational function : Rd = Rn + Operand2 + Carry
Flags affected : N, Z, C, V
Syntax (3) : ADC{ condition }{ S } Rd, Rn,
Operand2
Examples :
ADC r0, r1, r3 ; R0 = R1 + R3 + Carry
(if any)
ADC r0, r1, #0xFF ; R0 = R1 + 255 + Carry (if any)
ADCS r2, r11, #1024 ; R2 = R11 + 1024 + Carry (if
any)
ADC r3, r4, r5, LSL #4 ; R2 = R4 + R5*16 + Carry (if any)
If a negative constant is specified as Operand2, the 1’s complement of it is used, and a SBC is substituted for the ADC.
ADD - Arithmetic add
ADD adds two 32-bit 2’s complement signed numbers together and store the result into a designated register.
Operational function : Rd = Rn + Operand2
Flags affected : N, Z, C, V
Syntax(3) : ADD{ condition }{ S } Rd, Rn,
Operand2
Examples :
ADD r0, r1, r3 ; R0 = R1 + R3
ADDEQ r0, r1, #0xCC ; R0 = R1 + 204( If Z set)
ADDS r2, r11, #125, 28 ; R2 = R11 + 2000
ADD r3, r4, r5, LSR #4 ; R2 = R4 + R5 / 16
If a negative constant is specified as Operand2, the 2’s complement of it is used, and a SUB is substituted for the ADD.
AND – Logical AND
A logical AND operation is performed on two operands, and the 32-bit result is stored into a designated register.
Operational function : Rd = Rn AND Operand2
Flags affected : N, Z, C
Syntax(3) : AND{ condition }{ S } Rd, Rn,
Operand2
Examples :
AND r0, r2, r3, LSL #2 ; Mask via another register
AND r0, r1, #0xFFFFFF00 ; Same as BIC R0, R1, #0xFF
AND r4, r4, r3 ;
If a negative constant is specified as Operand2, the 1’s complement of it
is used, and a BIC is substituted for the AND.
BIC – Bit clear
Clear the bits in one operand indicated by the bits in the same position in the other operand. The result is stored into a designated register.
Operational function : Rd = Rn AND ( 1’s complement of
Operand2 )
Flags affected : N, Z, C
Syntax(3) : BIC{ condition }{ S } Rd, Rn,
Operand2
Examples :
BIC r1, r1, #1 ; Clear least significant
byte of R1
If a negative constant is specified as Operand2, the 1’s complement of it
is used, and an AND is substituted for the BIC.
CMN – Set negative
compare
Compare an operand against a 2’s complement negative value. Result is not
stored.
Operational function : Rn + Operand2
Flags affected : N, Z, C, V
Syntax(2) : CMN{ condition } Rn, Operand2
Examples :
CMN r0, r1, #-204 ; Same as CMP R0, R1, #203
CMN r0, r2 ;
If a negative constant is specified as Operand2, the 2’s complement of it
is used, and a CMP is substituted for the CMN. The S suffix is always implied.
CMP – Arithmetic
comparison
Compare a register against a value in another register or a constant.
Result is not stored.
Operational function : Rn + Operand2
Flags affected : N, Z, C, V
Syntax(2) : CMP{ condition } Rn, Operand2
Examples :
CMN r0, r1, #-204 ; Same as CMP R0, R1, #203
CMN r0, r2 ;
If a negative constant is specified as Operand2, the 2’s complement of it
is used, and a CMN is substituted for the CMP. The S suffix is always implied.
EOR – Bitwise
exclusive OR
A bitwise exclusive OR is performed between two operand words, and the
32-bit result is written to a designated register.
Operational function : Rd = (Rn AND NOT Operand2) OR
(Operand2 AND NOT Rn)
Flags affected : N, Z, C
Syntax(3) : EOR{ condition }{ S } Rd, Rn,
Operand2
Examples :
MOV – Move register
or constant
Move a 32-bit item from one register to another, or move an constant into
a register. A constant must apply to the pattern of #expression1.
Operational function : Rd = Operand2
Flags affected : N, Z, C
Syntax(2) : MOV{ condition }{ S } Rd, Operand2
Examples :
MOV PC, LR ; Move contents of link register into program counter
MOV PC, R15 ; Same as above
MOV r1, #0x80000 ; Load a big constant
MOV r3, #-205 ; Same as MVN R3, 204
If a negative constant is specified as Operand2, the 2’s complement of it
is used, and a MVN is substituted for the MOV.
MVN – Move complement
of register
Load the 1’s complement of a register or register, into another register.
Operational function : Rd = 0xFFFFFFFF XOR Operand2
Flags affected : N,
Z, C
Syntax(2) : MVN{ condition }{ S } Rd, Operand2
Examples :
MVN r0, #40 ; Move contents of link register into program counter
MVN r1,#-201 ; Same as MOV R1, #200
MVN r1, r3, ASR #4 ; Shift register before operation
If a negative constant is specified as Operand2, the 2’s complement of it
is used, and a MOV is substituted for the MVN.
ORR – Logical OR
A logical OR operation is performed on two operand words, and the 32-bit
result is stored in a designated register.
Operational function : Rd = Rn OR Operand2
Flags affected : N, Z, C
Syntax(3) : ORR{ condition }{ S } Rd, Rn,
Operand2
Examples :
ORR r1, r1, r0 ; R1 = R1 OR R0
ORR R0, R1, r3, ROR #4
RSB – Reverse operand
subtract
Identical to the SUB instruction, except that the operand order is
reversed. The result is stored into a designated register.
Operational function : Rd = Operand2 - Rn
Flags affected : N, Z, C, V
Syntax(3) : RSB{ condition }{ S } Rd, Rn,
Operand2
Examples :
RSB r1, r1, #0xFF ; Subtract R1 from a constant
RSB r0, r1, r3, LSL #4
RSC – Reverse operand
subtract with carry
The RSC instruction is identical to the SBC instruction, except that the
operand order is reversed.
A value of +1 is added to the difference if the carry bit was set prior
to the instruction. Nothing is added if the carry bit was clear.The result is
stored in a designated register.
Operational function : Rd = Operand2 – Rn – 1 + Carry
Flags affected : N, Z, C, V
Syntax(3) : RSB{ condition }{ S } Rd, Rn,
Operand2
Examples :
RSC r1,
r1, #0xFF ; R1 = 255 – R1 –
1 + Carry (if set)
RSC r0, r1, r3, LSL #4 ; R0 = R3*16 – R1
SBC – Subtract with
carry
SBC subtracts two 32-bit operands, storing the difference in a register.
A value of +1 is subtracted from the difference if the carry bit was clear
prior to the instruction. Nothing is subtracted if the carry bit was set.
Operational function : Rd = Rn – Operand2 – 1 + Carry
Flags affected : N, Z, C, V
Syntax(3) : SBC{ condition }{ S } Rd, Rn,
Operand2
Examples :
SBC r1, r2, r3
SBC r0, r1, r3, LSL #4
If a negative constant is specified as Operand2, the 1’s complement of it is used, and a ADC is substituted for the SBC.
SUB – Subtract
Subtract one 32-bit operand from another storing the result into a
designated register.
Operational function : Rd = Rn - Operand2
Flags affected : N, Z, C, V
Syntax(3) : SUB{ condition }{ S } Rd, Rn,
Operand2
Examples :
SUB r0, r1, r3 ; R0 = R1 - R3
SUBEQ r0, r1, #0xCC ; R0 = R1 - 204( If Z set)
SUBS r2, r11, #125, 28 ; R2 = R11 - 2000
SUB r3, r4, r5, LSR #4 ; R2 = R4 - R5 / 16
If a negative constant is specified as Operand2, the 2’s complement of it is used, and a ADD is substituted for the SUB.
TEQ - Test
Equivalence
Performs a bitwise Exclusive OR between the two operands, setting the Z
flag if the result is zero. Result
is not stored.
Operational function : Rn XOR Operand2
Flags affected : N, Z, C
Syntax(2) : TEQ{ condition } Rn, Operand2
Examples :
TEQ r1, #32 ; See if R1 contains 32
TEQ r0, r2
The S suffix is always implied.
TST – Test under Mask
Performs a bitwise AND between the two operands, setting the Z flag if
the result is zero.
Operational function : Rn AND Operand2
Flags affected : N, Z, C
Syntax(2) : TST{ condition } Rn, Operand2
Examples :
TST r1, #32
TST r0, r2
The S suffix is always implied.
Branch instructions
The syntax within the ARM Simulator is described below.
B{ L }{ condition } #expression
{ L } is used to
request the Branch with Link form of the instruction. If absent, R14 will not
be affected by the instruction.
{ condition } is a two-char
condition code. If absent then AL (always) will be used.
#expression is the destination
(a label). The assembler calculates the offset.
If the stack simulation is enabled within the ARM Simulator a BL
automatically makes use of the stack.
Examples :
B subone ;
Branch to ’subone’
BLEQ subone ;
Branch with link to ’subone’ if Z = 1
MOV PC, LR ; Return from subroutine
When writing subroutines labels are used to identify the function. In the ARM Simulator a label must be at the line preceding the start of the subroutine. An example is given beloew.
subone
SUB R0, R0, #1
ADD r0, r1, #2
MOV PC, LR
Placing the label on the same line as the instruction will
cause an error.
Load and store
register instructions
Two memory instructions are supported by the ARM Simulator. Their syntax
is described below.
LDR|STR { condition } Rd, #address
{ condition } is a
two-char condition code. If absent then AL (ALways) will be used.
{ Rd } is a
register
#address is any of :
[Rn]
[Rn, #expression]
[Rn, Rm]
[Rn, Rm shift #count]
Rn, Rm is a register
#expression is a value in the
range 0..4095
shift is any of LSL,
LSR, ASR or ROR
#count is any positive
constant in the range 1..31
STR - store from a
register into memory
STR r0, [r1] ; Store
value in R0 into address pointed to by R1
STR r0,[r1, r2] ; Store
value in R0 into address pointed at by R1 + R2
STR r0,[r1,#16] ;
Store value in R0 into address pointed at by R1 + 16
STR r0,[r1, r2 ,LSL #2] ; Store value in R0 into address pointed at by R1 + R2*4
LDR - load from
memory into a register
Same
syntax as STR. The first register acts as the destination register, rather than
the source register.
LD r0, [r1] ;
Store value in address pointed to by R1 into R0.
Condition codes
Any of
the 16 condition codes may be used with any of the instructions supported by
the ARM Simulator. The condition codes are listed below.
|
Mnemonic |
Code |
Condition |
Meaning |
|
EQ |
0000 |
Z set |
Equal |
|
NE |
0001 |
Z clear |
Not equal |
|
CS |
0010 |
C set |
Unsigned higher or same |
|
CC |
0011 |
C clear |
Unsigned lower |
|
MI |
0100 |
N set |
Negative |
|
PL |
0101 |
N clear |
Positive or zero |
|
VS |
0110 |
V set |
Overflow |
|
VC |
0111 |
V clear |
No overflow |
|
HI |
1000 |
C set and Z clear |
Unsigned higher |
|
LS |
1001 |
C clear or Z set |
Unsigned lower or same |
|
GE |
1010 |
N and V the same |
Greater or equal |
|
LT |
1011 |
N and V differ |
Less than |
|
GT |
1100 |
Z clear, N and V the same |
Greater than |
|
LE |
1101 |
Z set, N and V differ |
Less than or equal |
|
AL |
1110 |
- |
Always execute |
|
NV |
1111 |
- |
Never |
Shifts
The
shifts supported by the ARM Simulator are LSL, LSR, ASR and ROR.
LSL - Logical Shift Left moves each bit by the specified amount to a more significant position. The least significant bits are filled with zeroes. High bits that are shifted outside the 32-bit result range are discarded. The last discarded bit becomes the shifter carry output, which may be applied to the C bit of the CPSR if the instruction involved is a logical operation with the S bit set.
LSR - Logical Shift Right moves each bit by the specified amount to a less significant position. The most significant bits are filled with zeroes. Low bits that are shifted outside the 32-bit result range are discarded. Carry is generated as in LSL.
ASR - Arithmetic Shift Right performs almost the same operation as Logical Shift Right. The difference is that the high bits are filled with replicates of the most significant bit of the shifted register instead of zeroes. This means that a negative value is extended with ones and a positive value is extended with zeroes. Carry is generated as in LSR.
ROR – Rotate Right reuses the bits that ’fall-of’ on the least significant end by wrapping them around at the most significant position of the result. A Carry is generated in the same way as LSR.
Using labels
When writing subroutines labels are used to identify the function. In the ARM Simulator a label must be at the line preceding the start of the subroutine. An example is given beloew.
subone
SUB R0, R0, #1
ADD r0, r1, #2
MOV PC, LR
Placing the label on the same line as the instruction will cause an error.
APPENDIX D – TEST RESULTS
Large operand substitution test results
|
Instruction |
Result |
Immediate value |
Rotate value |
Assembly value |
|
ADD r0, r1, #89128960 |
OK |
01010101 = 85 |
0110 = 6 |
85, 12 |
|
ADD r1, r0, #0xDF |
OK |
11011111 = 223 |
0000 = 0 |
223, 0 |
|
SUB r1, r0, #0x4000 |
OK |
01000000 = 64 |
1100 = 12 |
64, 24 |
|
ADD r3, r4, #1024 |
OK |
01000000 = 64 |
1110 = 14 |
64, 28 |
|
MOV r3, #71303168 |
OK |
01000100 = 68 |
0011 = 3 |
68, 6 |
|
ADD r4, r5, #6720 |
OK |
01101001 = 105 |
1101 = 13 |
105, 26 |
|
SUB r3, r4, #65,28 |
OK |
01000001 = 65 |
1110 = 14 |
65, 28 |
LSL – Logical Shift
Left
|
Instruction |
Expected result |
Decimal value |
|
1. ADD r0, r0, #30 |
R0 = 0x0000001E |
30 |
|
2. ADD r1, r1, r0, LSL #4 |
R1 = 0x000001E0 |
480 |
|
3. ADD r2, r2, r0, LSL #30 |
R2 = 0x80000000 |
-2147483648 |
|
4. ADD r3, r3, r0, LSL #31 |
R3 = 0x00000000 |
0 |
LSR – Logical Shift
Right
|
Instruction |
Expected result |
Decimal value |
|
1. ADD r0, r0, #120 |
R0 = 0x00000078 |
120 |
|
2. ADD r1, r1, r0, LSR #2 |
R1 = 0x0000001E |
30 |
|
3. ADD r2, r2, r0, LSR #5 |
R2 = 0x00000003 |
3 |
|
4. ADD r3, r3, r0, LSR #10 |
R3 = 0x00000000 |
0 |
ASR – Arithmetic
Shift Right
|
Instruction |
Expected result |
Decimal value |
|
1. ADD r0, r0, #250 |
R0 = 0x000000FA |
250 |
|
2. SUB r1, r1, #250 |
R1 = 0xFFFFFF06 |
-250 |
|
3. ADD r2, r2, r0 ASR #4 |
R2 = 0x0000000F |
15 |
|
5. ADD r3, r3, r1 ASR #4 |
R3 = 0xFFFFFFF0 |
-16 |
ROR – Rotate Right
|
Instruction |
Expected result |
Decimal value |
|
1. ADD r0, r0, #120 |
R0 = 0x00000078 |
120 |
|
2. ADD r1, r1, r0, ROR #4 |
R1 = 0x80000007 |
-2147483641 |
|
3. ADD r2, r2, r0, ROR #12 |
R2 = 0x07800000 |
125829120 |
RRX – Rotate Right
Extended
Due to lack of time the RRX shift operation was not implemented.
Conclusion
The shift operations seem to work fine. No errors were encountered during these tests. The fact that shifts are handled by a special object, makes this part quite failsafe. Instructions only pass it the parameters and the result is returned.
Conditional execution test results
|
Instruction |
Condition Code |
Execute |
N |
Z |
C |
V |
|
ADD r0,r0,#1 |
AL |
Y |
0 |
0 |
0 |
0 |
|
SUBNES r0,r0,#1 |
NE |
Y |
0 |
1 |
1 |
0 |
|
ADDEQ r0,r0,#1 |
EQ |
Y |
0 |
1 |
1 |
0 |
|
ADDNE r0,r0,#1 |
NE |
N |
0 |
1 |
1 |
0 |
|
RSBCSS r0,r0,#0 |
CS |
Y |
1 |
0 |
0 |
0 |
|
ADCSS r0,r1,r2 |
CS |
N |
1 |
0 |
0 |
0 |
|
ADCCCS r0,r0,#267386880 |
CC |
Y |
0 |
0 |
1 |
0 |
|
BICHI r1,r0,#10 |
HI |
Y |
0 |
0 |
1 |
0 |
|
MOVLS r0,#0xFF |
LS |
N |
0 |
0 |
1 |
0 |
|
ADDGT r2,r2,#0xCE |
GT |
Y |
0 |
0 |
1 |
0 |
|
RSCALS r2,r2,#0x10 |
AL |
Y |
1 |
0 |
0 |
0 |
|
ADDLTS r2,r2,#4096 |
LT |
Y |
0 |
0 |
1 |
0 |
|
EORMI r0,r1,#10 |
MI |
N |
0 |
0 |
1 |
0 |
|
SUBPLS r0,r4,#1 |
PL |
Y |
1 |
0 |
0 |
0 |
|
ADDS r0,r1,r0 |
AL |
Y |
0 |
0 |
1 |
0 |
|
MOVLES r5,#0x4000 |
LE |
Y |
0 |
0 |
1 |
0 |
|
ADD r4,r4,#127,8 |
AL |
Y |
0 |
0 |
1 |
0 |
|
ADD r5,r5,#127,8 |
AL |
Y |
0 |
0 |
1 |
0 |
|
ADDS r6,r4,r5 |
AL |
Y |
1 |
0 |
0 |
1 |
|
ADDGE r0,r7,#0 |
GE |
Y |
1 |
0 |
0 |
1 |
|
SUBVCS r0,r7,#0xFF |
VC |
N |
1 |
0 |
0 |
1 |
|
SBCVS r0,r7,#10 |
VS |
Y |
1 |
0 |
0 |
1 |
|
MOVLE r0,#0 |
LE |
N |
1 |
0 |
0 |
1 |
|
MVNLTS r1,#0 |
LT |
N |
1 |
0 |
0 |
1 |
|
ORREQ r2,r3,r4 |
EQ |
N |
1 |
0 |
0 |
1 |
|
MOVGES r1,#0 |
GE |
Y |
0 |
1 |
0 |
1 |
|
MOVLE r0,#0 |
LE |
Y |
0 |
1 |
0 |
1 |
|
ADDVSS r0,r1,r2, LSL #4 |
VS |
Y |
0 |
0 |
0 |
0 |
|
|
|
|
|
|
|
|
Negative operand substitution test results
|
Instruction |
Expected result |
|
ADC r0,r0,#-5 |
SBC r0,r0,#4 |
|
SBC r0,r0,#-1025 |
ADC r0,r0,#64,28 |
|
ADD r0,r0,#-10 |
SUB r0,r0,#10 |
|
SUB r0,r0,#-132 |
ADD r0,r0,#132 |
|
AND r0,r3,#-45 |
BIC r0,r3,#44 |
|
BIC r4,r5,#-4097 |
AND r4,r5,#64,26 |
|
CMP r10,#-25 |
CMN r10,#25 |
|
CMN r11,#-255 |
CMP r11,#255 |
|
MOV r7,#-12 |
MVN r7,#11 |
|
MVN r6,#-98 |
MOV r6,#97 |
APPENDIX E – USE CASE AND UML DIAGRAMS
This section contains the use case and UML diagrams describing the ARM Simulator software.
The diagrams are displayed in the following sequence :
· Use case diagrams
· Sequence diagrams
· Overall class diagram
· Class diagrams of each class
The overall use case diagram for the application is displayed first, followed by the sequence diagram for each case.
The overall class diagram show how all the classes within the ARM Simulator are connected. Due to the limited space, only the class names are shown in this diagram. For the same reason the diagram had to become a mixture of a Rational Rose and a Word diagram.
The last section show detailed class diagrams of each class. Due to the fact that many classes has a identical set of variables and methods, one class has been chosen to represent all of these classes.


The above diagram gives a short introduction to the
symbols and syntax if the diagrams. Blue items are variables, purple are
methods. A lock means private, while a key means protected. If a ’$’ sign is
appended the item is also static. A class name or method in italics indicates that the class or
method is abstract. A circle defines an interface.
Main Use case for the ARM Simulator
The following diagram describes the main use cases:
Start Simulator
sequence diagram

Open File sequence
diagram

Save File sequence
diagram

Edit File sequence
diagram

Build program
sequence diagram

Run Program
sequence diagram

Change View
sequence diagram
View memory
sequence diagram
Edit Option
sequence diagram

Stop Program
sequence diagram

The following diagram shows the main connections between the classes within the ARM Simulator. A mixture of Rational Rose diagrams, and Word drawings had to be used to make it fit within the report.

ArmSimulator and
ArmSimulatorFrame
The ArmSimulator class is the main class of the application. It instanciates a new ArmSimulatorFrame object which contains the full GUI and handles all interaction with the user. No GUI elements are shown in the ArmSimulatorFrame model, because of spacelimitations. The most important variables and methods for program execution is included.


ArmInstruction
class
The layout of the
ArmAddInstruction class is identical to those sharing the same syntax.
Therefore the ArmAndInstruction, ArmEorInstruction, ArmSubInstruction,
ArmRsbInstruction, ArmAdcInstruction, ArmSbcInstruction, ArmRscInstruction,
ArmOrrInstruction and ArmBicInstruction class diagrams are not included. Their
variables and methods are identical to those of the ArmAddInstruction class.
The
ArmMovInstruction and ArmMvnInstruction class diagrams are identical when it
comes to variables and methods, therfore only the ArmMovInstruction class
diagram is included here.

The ArmCmpInstruction class diagram is identical to those sharing the same syntax. These comprise of the ArmCmnInstruction, ArmTeqInstruction and ArmTstInstruction diagrams. Only the ArmCmpInstruction class diagram is included.
The ArmBranchInstruction defines both B and BL. It has the following layout:

The ArmLdrInstruction and ArmStrInstruction
The class diagrams of the two is identical, therefore only the ArmLdrInstruction diagram is shown here.

ArmInstructionParser
The ArmInstructionParser class is responsible of creating all the instruction objects.


Utility classes
The rest of the classes shown in the main diagram is shown here.








APPENDIX F – CHOICE OF DEVELOPMENT LANGUAGE
The
first section of this appendix discusses the software requirements. Section two
discusses choice of development language for the project. Section three
discusses the Swing user interface library and the Model View Controller
architecture. Section four discusses the differences between Java applications
and applets.
This chapter describes the process of selecting the
programming language. When selecting a programming language several factors
need to be considered. Before any specific
language was considered a list of the required and wanted functionality was
created.
Object Orientation provides reusability and easier scaling of
projects. Its modular class hierarchy makes it easy to introduce new classes
and functionality during development.
Graphic capabilities the simulator will of course offer a graphical
user interface. Languages not supporting this are automatically discarded.
Portability is an important factor to keep in mind. If the application runs on
several platforms instead of one, the number of users that can be reached
Speed for the developer speed may not matter that much, but for the end user
that is actually going to use the product it does.
Ease of development one may discuss if this should be a factor. For
a large scale project with several developers this may not matter much.
Considering the time limit on the project, an easy and rapid development tool
helps produce a better result.
These five criterias
will help decide what language to choose.
C++
offers object orientation, it has great speed, and it has good graphic
capabilities. Several good window libraries are accessible as for example MFC,
OWL or QT. None of these libraries are platform independent. Development is
hard for unexperienced, and sometimes even experienced, Windows programmers.
Visual Basic can hardly be called object oriented, although it offers reusability and
modularity through its modules. It has all the graphic capabilities needed but
runs rather slow. Visual Basic programs run only on the Windows platform.
Development is easy.
Delphi is a graphical development package from Borland, built on top of Pascal.
It has all the graphic capabilities needed and the speed as well as development
is intermediate. It is not platform independent.
Java is object orientated, it has all the graphic capabilities needed. It is
supposed to be platform independent but runs rather slow. Development is easy.
Condsidering the criteras first set out, Java will be the language of choice.
F.3 Selecting a window toolkit
The Java Software Development Kit is bundled with a window library collectively known as JFC or Java Foundation Classes. This library actually contains two different packages, AWT and Swing. Although both AWT and Swing is commonly referred to as JFC, Sun recommends to use one of the two, and not mixing GUI components.
Swing was first introduced with the 1.2 release of the
Development Kit. It defines nearly 40
graphical components, and is said to be 100% system independent.
Awt uses native peers
to handle actions, in Swing this is solved fully in Java and a more complex
framework is being used. This framework is called MVC – Model View Controller.
Model View Controller is a design pattern or framework originally developed by Prof. Trygve Reenskaug at Xerox PARC in 1978/79. It was developed to allow Smalltalk to conveniently support GUIs.
MVC is used extensively in Swing. Basically, the "model" contains the data, the "view" is the graphical representation, and the "controller" is responsible for the interaction between the other two.
As an example, think of visually editing a Tree component that represents a directory.
The display is the view. Selecting a file, and dragging it to another directory will move or copy the file. In order for the operation to happen, the controller must tell the model what just happened in the view.
In practice, inter-communication between the view and the controller is complex, so the two are bundled together in one category in Swing. The model (data) is separate though.
The MVC architecture makes most of the Swing components more difficult to use than the respective AWT ones, but they are also much more customizable.
It was
decided to implement the simulator as an application. Java applications have
full access on a users system. The drawback is that the user must have the appropriate
Java Runtime Environment installed which is a several megabyte download.
If the
simulator should be implemented as an applet the software could run in a
browser. However applets have strong security restrictions when it comes to
accessing a users files. Considering that Swing will be used to create the GUI,
the user would have to download and install the Java Plug-In which is, just as
JRE, a several megabyte download. The user would also lose the ability of
creating and saving assembly programs.
Please
note that not all source code has been included and that some of the listed
files only contain extractions of the full source. Only that which was deemed
to be of interest to the reader was included. The complete source code can be
found on the accompanying CD-Rom.
The
following source files are printed overleaf:
ArmSimulator.java - main class for the project
ArmSimulatorFrame.java - GUI and user interaction
ArmInstructionSet.java - static constants used by all
instruction objects
ArmInstruction.java - the superclass of all
instruction objects
ArmAddInstruction.java - an example instruction object
ArmInstructionReader.java - create the instructions from a user
program
/*
*
@(#)ArmSimulator.java 1.00 2000/03/07
*
* Class
ArmSimulator.
*
* Main class.
This initializes the application and
* launches
ArmSimulatorFrame, which contains the GUI.
*
* Torkild
Magnussen, BSc Informatics 1999/2000.
* Email :
torkild@magnussen.nu
* Copyright
(c) University of Teesside, Middlesbrough, UK.
* All Rights
Reserved.
*/
import java.awt.*;
public class ArmSimulator {
private
static ArmSimulatorFrame window;
private
static ArmSimulator application;
public
static void main(String[] args) {
application = new ArmSimulator();
application.init();
}
public void
init() {
window =
new ArmSimulatorFrame("ArmSimulator - ");
Toolkit tk
= window.getToolkit();
Dimension
wndSize = tk.getScreenSize();
window.setBounds(wndSize.width/6, wndSize.height/6,
2*wndSize.width/3, 2*wndSize.height/3);
window.setVisible(true);
}
}
/*
*
@(#)ArmSimulatorFrame.java 1.00 2000/03/07
*
* Class
ArmSimulatorFrame.
*
* This class
hold the GUI,and handles all user interaction.
*
* Torkild
Magnussen, BSc Informatics 1999/2000.
* Email :
torkild@magnussen.nu
* Copyright
(c) University of Teesside, Middlesbrough, UK.
* All Rights
Reserved.
*/
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.lang.*;
import java.util.*;
public class ArmSimulatorFrame extends Jframe
implements
ActionListener, ItemListener, DocumentListener, WindowListener {
//
DocumentViewer
private
ArmDocumentViewer helpView;
// Memory
viewer
private
ArmMemoryView extView;
// Program
options
private
ArmOptionsView optView;
// Autorun
dialog
private
ArmAutoRun autoRun;
//
Splashscreen and about box
private
ArmSplashScreen splashScreen;
// Parsing
and building instructions
private
StreamTokenizer instructionReader;
private
Reader textReader;
private
ArmInstructionReader instReader;
private
Vector program = new Vector(1);
private
Vector listReference = new Vector(1);
private
Hashtable labelvals = new Hashtable();
private
Vector labels = new Vector(1);
private
Stack linkvals = new Stack();
private
Hashtable memory;
private
boolean stackSimulationActive = false;
private int
currentStackRegister = 13;
private int
currentRegisterView = VIEW_REG_AS_BIN;
private int
currentInstructionView = VIEW_INST_AS_USR;
private
ArmInstruction reference;
private
ArmInstruction refHelper;
private
ArmBinaryToDecimal converter;
private
Enumeration enumParseAll;
private
Enumeration enumHelper;
public
ArmSimulatorFrame( String title ) {
// Display
a splash screen to monitor application loading
createSplashScreen( 6 );
// Set up
initial variables and increase progress
initApplication( title );
readIniFile();
splashScreen.setProgress(
1 );
// Set up
the menubar and increase progress
setJMenuBar( createMenuBar() );
splashScreen.setProgress( 2 );
// Set up
the toolbar and editor and increase progress
contentPane.add( createToolBar(), BorderLayout.NORTH );
contentPane.add( createEditor(), BorderLayout.CENTER );
splashScreen.setProgress( 3 );
// Set up
the statusbar and increase progress
contentPane.add( createStatusBar(), BorderLayout.SOUTH );
createMemoryView();
createOptionsView();
splashScreen.setProgress( 4 );
// Set up
programspace and register table, increase progress
createSimArea();
splashScreen.setProgress( 5 );
//
Initialize help dialog and increase progress
createHelpView();
setEditMode();
splashScreen.setProgress( 6 );
// Pack
all elements of the application
pack();
// Loading
is done, so we remove the splashscreen
splashScreen.dispose();
}
/******************************************************************
Definining
events for menu, toolbar, editor and document viewer.
Toolbar
button and menu item events are handled by ActionListener.
Checkbox
menu item events are handled by ItemListener.
Events in
the editor are handled by DocumentListener.
*****************************************************************/
// Trigger
is something is inserted into document
public void
insertUpdate(DocumentEvent e) {
// Set
document changed flag
if(!documentChanged) documentChanged = true;
}
// Trigger
if something is deleted in the document
public void
removeUpdate(DocumentEvent e) {
// Set
document changed flag
if(!documentChanged) documentChanged = true;
}
// Trigger
if any change is detected in the document
public void
changedUpdate(DocumentEvent e) {
// Set
document changed flag
if(!documentChanged) documentChanged = true;
}
// Triggered
by menu selections or toolbar buttons
public void
actionPerformed(ActionEvent e) {
// If this
is either File->New or New from toolbar
if((e.getSource() == tlbNew) || (e.getSource() == mnuNew)) {
// Check
if changes has occured since last save
if(checkForSave()) {
// Clear editor area
editorText.setText("");
// Set
change flag
documentChanged = false;
// Set
document title
documentName = "Untitled";
// No
file assosciated with this document
documentFile = null;
//
Update simulator title
setTitle(simulatorTitle + documentName);
}
}
// If this
is either File->Open or Open from toolbar
else
if((e.getSource() == tlbOpen) ||
(e.getSource()
== mnuOpen)) {
// Check
if changes has occured since last save
if(checkForSave()) {
// Get
file from dialog
File
file = openDialog();
// If
file exists
if(
file != null ) {
//
Load another cursor to indicate that system is busy
setWaitCursor();
//
If load was sucessfull set file variables
if(
openDocument(file) ) fileCompleted(file);
//
Set change flag
documentChanged = false;
//
Update simulator title
setTitle(simulatorTitle + documentName);
//
Load the default cursor when done
setDefaultCursor();
}
}
}
// If this
is either File->Save or Save from toolbar
else
if((e.getSource() == tlbSave) ||
(e.getSource()
== mnuSave)) {
// Call
save operation, also deals with documents with no file
saveOperation();
// Set
change flag
documentChanged = false;
//
Update simulator title
setTitle(simulatorTitle + documentName);
}
// If this
is File->Save as
else
if(e.getSource() == mnuSaveas) {
// If
save was ok set change flag
if(saveAsOperation()) documentChanged = false;
//
Update simulator title
setTitle(simulatorTitle + documentName);
}
// If this
is File->Exit
else
if(e.getSource() == mnuExit) {
// Check
if document changed
if(checkForSave()) {
// Dispose our frame
dispose();
//
Explicit call system exit
System.exit(0);
}
}
// If this
is eiter Edit->Cut or Cut from toolbar
else
if((e.getSource() == tlbCut) || (e.getSource() == mnuCut)) {
// Cut
any selected text and store to clipboard
editorText.cut();
}
// If this
is eiter Edit->Copy or Copy from toolbar
else
if((e.getSource() == tlbCopy) ||
(e.getSource()
== mnuCopy)) {
// Copy
any selected text and store to clipboard
editorText.copy();
}
// If this
is eiter Edit->Paste or Paste from toolbar
else
if((e.getSource() == tlbPaste) ||
(e.getSource()
== mnuPaste)) {
// Past
content of clipboard into current position
editorText.paste();
}
// If this
is eiter Edit->Options
else if(
e.getSource() == mnuOptions ) {
// If an
instance of options is running kill it
if
(optView != null) optView.dispose();
// Re
create object to make sure latest settings is applied
optView
= new ArmOptionsView(this, " ArmSimulator - Options");
//
Position the help dialog
optView.setLocationRelativeTo(this);
// Show
a new instance of the dialog
optView.show();
}
// If this
is Program->Build or Build from toolbar
else
if((e.getSource() == tlbBuild) ||
(e.getSource()
== mnuBuild)) {
// Load
another cursor to indicate that system is busy
setWaitCursor();
// Enter
build mode ( disable certain controls ... )
setBuildMode();
// Try
to build the program
readtext();
if(
stackSimulationActive ) {
registerValues[currentStackRegister] = sp;
}
//
Update the registers so that they show the current view
updateRegisters( currentRegisterView );
//
Update instruction list to show current view
setInstructionView( currentInstructionView );
//
Current instruction should be the first
current
= 0;
// Load
the default cursor when done
setDefaultCursor();
}
// If this
is Program->Reset or Reset from toolbar
else
if((e.getSource() == tlbReset) ||
(e.getSource()
== mnuReset)) {
// Load
another cursor to indicate that system is busy
setWaitCursor();
// Get
an instance of a instruction and clear datamodel */
reference = (ArmInstruction) program.elementAt(0);
// Set
clear mode
reference.executeInstruction(registerValues, false,
linkvals,
memory);
if( stackSimulationActive ) {
registerValues[currentStackRegister] = sp;
}
//
Update the registers so that they show the current view
updateRegisters( currentRegisterView );
//
Update instruction list to show current view
setInstructionView( currentInstructionView );
//
Current instruction should be the first
current
= 0;
// Clear
the stack
linkvals
= new Stack();
// Point
to first instruction in program list
programList.setSelectedIndex(current);
// Reset
view
programList.ensureIndexIsVisible(current);
// Make
sure step button is enables
tlbStep.setEnabled( true );
// Make
sure step menu is enabled
mnuStep.setEnabled( true );
// Make
sure run is enabled
mnuRun.setEnabled( true );
// Load
the default cursor when done
setDefaultCursor();
}
// If this
is Program->Stop or Stop from toolbar
else
if((e.getSource() == tlbStop) ||
(e.getSource()
== mnuStop)) {
//
Remove the list and register table
getContentPane().remove(dividerArea);
// Add
the editor
getContentPane().add(editorArea, BorderLayout.CENTER);
//
Invalidate the frame to say that components have changed
invalidate();
//
Validate the frame to show the list and register tables
validate();
//
Explicit call to repaint() to make sure frame gets updated
repaint();
//
Current instruction should be the first
current
= 0;
// Clear the stack
linkvals
= new Stack();
// Get
an instance of a instruction and clear datamodel */
reference = (ArmInstruction) program.elementAt(0);
// Set
clear mode
reference.executeInstruction(registerValues, false,
linkvals,
memory);
//
Update the registers
updateRegisters( currentRegisterView );
// Kill
memory dialog
//if(
memoryView != null ) memoryView.dispose();
// Kill
stackdialog
//if(
stackView != null ) stackView.dispose();
/* Kill
memory dialog */
if(
extView != null ) extView.dispose();
// Set
edit mode ( enable and disable controls )
setEditMode();
}
// If this
is Program->Step or Step from toolbar
else
if((e.getSource() == tlbStep) ||
(e.getSource()
== mnuStep)) {
//
Create an int representation of the program counter
converter = new
ArmBinaryToDecimal(registerValues[15].substring(0,35));
// Get
the in representation
int pc =
converter.getValue();
// Convert program counter so that we can
apply it to the list
if( pc
!= 0 ) current = pc / 4;
int tracker
=
((Integer)listReference.elementAt(current*2+1)).intValue();
// Try
to process the next instruction
try {
// Get
an instance of the next instruction
reference = (ArmInstruction) program.elementAt( tracker );
//
Pass the datamodel using call by reference
if(
reference.executeInstruction(
registerValues, true, linkvals, memory ) ) {
//
Set new register values using the current view
updateRegisters( currentRegisterView );
}
//
Create an int representation of the program counter
converter = new
ArmBinaryToDecimal(registerValues[15].substring(0,35));
// Get
the in representation
pc =
converter.getValue();
//
Convert program counter so we can apply it to the list
if( pc
!= 0 ) current = pc / 4;
tracker =
((Integer)listReference.elementAt(current*2+1)).intValue();
//
Update list selection
programList.setSelectedIndex(tracker);
//
Update listview
programList.ensureIndexIsVisible( tracker );
//
Update stackview
//if(
stackView != null ) stackView.setData( linkvals );
if( extView !=
null ) extView.setMemory( memory, linkvals,
stackSimulationActive );
//
Update memory view
if(
extView != null ) extView.setSelected( current );
}
// Catch
out of bounds
catch(
ArrayIndexOutOfBoundsException aiobe ) {
statusBarText.setText(" End of
program ");
tlbStep.setEnabled( false );
mnuStep.setEnabled( false );
mnuRun.setEnabled( false );
}
}
// If this
is Program->AutoRun
else if( e.getSource() == mnuRun ) {
// If an
instance of helpview is running, the kill it
if
(autoRun != null) autoRun.dispose();
//
Reinitialize dialog
autoRun
= new ArmAutoRun(this, " ArmSimulator - AutoRun");
// Position
the help dialog
autoRun.setLocationRelativeTo(this);
// Show
a new instance of the dialog
autoRun.show();
}
// If this
is View->Memory or Memory from toolbar
else if(
(e.getSource()==tlbMemory) ||
(e.getSource() == mnuMemory) ) {
if(
extView != null ) extView.dispose();
extView.setLocationRelativeTo( this );
extView.setMemory( memory, linkvals, stackSimulationActive );
extView.show();
}
// If this
is Help->Contents or Contents from toolbar
else
if((e.getSource()==tlbContents) ||
(e.getSource()==mnuContents)) {
// If an
instance of helpview is running, the kill it
if
(helpView != null) helpView.dispose();
//
Position the help dialog
helpView.setLocationRelativeTo(this);
// Show
a new instance of the dialog
helpView.show();
}
// If this
is Help->About or About from toolbar
else
if(e.getSource() == mnuAbout) {
// If an
instance is running, kill it
if (splashScreen
!= null) splashScreen.dispose();
// Hide
the progress bar
splashScreen.useProgress(false);
// Show
the about box
splashScreen.show();
//
Request focus for our about box
splashScreen.requestFocus();
}
}
// If main
frame gets activated
public void
windowActivated(WindowEvent e) {
// Kill
any instances of about box
if
(splashScreen != null) splashScreen.dispose();
}
// If window
is closing
public void
windowClosing(WindowEvent e) {
// Check
if document has changed
if(
checkForSave() ) {
//
Dispose main frame
dispose();
//
Explixit call to system exit
System.exit(0);
}
else { }
//Do nothing
}
// Do
nothing, these must be declared
public void
windowClosed(WindowEvent e) { }
public void
windowDeactivated(WindowEvent e) { }
public void
windowDeiconified(WindowEvent e) { }
public void
windowIconified(WindowEvent e) { }
public void
windowOpened(WindowEvent e) { }
// Handle
checkbox menu items
public void
itemStateChanged( ItemEvent ec ) {
// If this
is View->ToolBar or ToolBar from toolbar
if(
ec.getSource() == mnuToolbar ) {
// If
toolbar is visible, then hide and vice versa
toolBar.setVisible( ! toolBar.isVisible() );
}
// Else
this must be the statusbar
else {
// If
statusbar is visible, then hide and vice versa
statusBar.setVisible( ! statusBar.isVisible() );
}
//
Invalidate the frame to say that components have changed
invalidate();
//
Validate the frame to show changes
validate();
}
// Create a
SplashScreen
private void
createSplashScreen(int num) {
// Create
a new instance of ArmSplashScreen
splashScreen = new ArmSplashScreen(num);
// Show
the splashScreen
splashScreen.show();
}
//
Initialize application
private void
initApplication(String t) {
// Apply a
window listener
this.addWindowListener(this);
// Change
default close operation
this.setDefaultCloseOperation( DO_NOTHING_ON_CLOSE );
// Set
change flag
documentChanged = false;
// Set
document name
documentName = "Untitled";
// Create
a new instance of a JFileChooser object
fileHandler = new JFileChooser();
// Set title
String
simulatorTitle = t;
// Set
simulator title
setTitle(simulatorTitle + documentName);
// Get
this frames content pane
contentPane = getContentPane();
// Apply
BorderLayout to the content pane
contentPane.setLayout(new BorderLayout());
}
// Create
memory view
private void
createMemoryView() {
// Create
a new instance of an ArmStackView
extView =
new ArmMemoryView(this, " ArmSimulator - MemoryView");
}
// Create
memory view
private void
createOptionsView() {
// Create
a new instance of an ArmStackView
optView =
new ArmOptionsView(this, " ArmSimulator - Options");
}
// Create
help system
private void
createHelpView() {
// Create
a new instance of an ArmDocumentViewer
helpView = new ArmDocumentViewer(
this,
" ArmSimulator - HelpViewer", "index.html");
}
/******************************************************************
readText()
reads user input and creates the instructions using
the
ArmInstructionParser help class.
******************************************************************/
private void
readtext() {
// new
instance of a StringReader with editor text as argument
textReader
= new StringReader(editorText.getText()+"\n");
// new
instance of StreamTokenizer with StringReader as argument
instructionReader = new StreamTokenizer(textReader);
// Tell
StreamTokenizer that we want reports on EOL's
instructionReader.eolIsSignificant(true);
// Set ';'
as comment char
instructionReader.commentChar(';');
// Set
spaces as whitespace chars, these will be ignored
instructionReader.whitespaceChars(' ',' ');
// Set
square brackets as whitespace chars
instructionReader.whitespaceChars('[','[');
// Set square brackets as whitespace chars
instructionReader.whitespaceChars(']',']');
// Set ','
as whitespace chars, these will be ignored
instructionReader.whitespaceChars(',',',');
// Set '!'
as regular char
instructionReader.wordChars('!','!');
// We need
some helper variables
int token
= 0; int wc = 0;
// String
array to store values in
String[]
vals = new String[7];
// We need
to be able to abort reading
boolean
read = true;
// Help
variable to keep track of valid instructions
int
counter = 0;
// Vector
to store ArmInstruction objects in
program =
new Vector(1);
// Vector
to track listreferences
listReference = new Vector(1);
// Create
an StringReader with a BufferedReader wrapper
BufferedReader in = new BufferedReader(new
StringReader(editorText.getText()+"\n"));