Skip to content

XavKearney/fsharp-arm-emulator

Repository files navigation

fsharp-arm-emulator

The goal of this project is to create a fully functional ARM Assembly Language Emulator in F#.

This repository is for the back-end code, which performs instruction emulation. This is used in an electron-based GUI, which is defined here.

For individual project statements, see the docs directory.

Running the Project

If you don't have paket installed, run .paket/paket.bootstrapper.exe and then .paket/paket.exe install. paket should now be installed.

To run from a fresh clone, if you have paket installed then from the root directory run: paket update

This will install the necessary packages.

Then you can run the project at any time using:

dotnet run --project ArmEmulator/ArmEmulator.fsproj

NB: To test using the VisualTest framework, you must first populate the visualapp/visual/jre/ folder with the correct binaries which can be downloaded here.

Structure

This project is both a self-contained emulator for ARM code, and also used as the back-end emulation for an electron app, whose repository is here. As such, this project contains two .fsproj files:

  1. ArmEmulator.fsproj - this is the main project file to be used in this repository. It includes all modules and all tests.
  2. EmulatorInterface.fsproj - this is a dummy project file used by the electron app, which excludes all tests and the Main.fs file. It uses the TargetFramework netstandard2.0 instead of netcoreapp2.0 to enable use with FABLE.

The project is split into independent modules, each with their own file of tests. The modules, in the order that the project includes them, along with their respective purposes and level of testing are:

Module Purpose Unit Tests Property-based Tests Tested vs. VisUAL
VTest Framework for testing against VisUAL. n/a n/a n/a
CommonData Defines generic, project-wide types for data processing. n/a n/a n/a
CommonLex Defines generic, project-wide types for parsing instructions. n/a n/a n/a
ParseExpr Defines generic, project-wide types for parsing instructions. ✔️ ✖️ n/a
Arithmetic Implements arithmetic instructions, e.g. ADD,SUB,CMP ✔️ ✔️ ✔️
BitArithmetic Implements bitwise arithmetic instructions, e.g. MOV,ORR,LSL ✔️ ✔️ ✔️
Mem Implements memory-based instructions, e.g. LDR,ADR,FILL ✔️ ✔️ ✖️
MultMem Implements multiple-location memory-based instructions, as well as misc. instructions, e.g. LDM,STM,B ✔️ ✔️ ✔️
TopLevel Implements complete emulation & instruction execution ✔️ ✖️ n/a
Main CLI to run tests or execute instructions from file. ✖️ ✖️ n/a

Unit tests have been written for all modules with significant complexity. Property-based testing has been employed in all cases where randomised generation of parameters is feasible (e.g. in TopLevel, randomly generating a random source file is not feasible).

Proof of the tests passing (configured to run 10,000 iterations for all property-based tests): Proof of tests passing

Features

Instructions

The complete set of ARM instructions supported by this project are:

Module Instruction Comments
Arithmetic ADD
Arithmetic SUB
Arithmetic ADC
Arithmetic SBC
Arithmetic RSB
Arithmetic RSC
Arithmetic CMP
Arithmetic CMN
BitArithmetic MOV
BitArithmetic MVN
BitArithmetic AND Flag setting conforms to ARM spec, not VisUAL.
BitArithmetic ORR
BitArithmetic EOR Flag setting conforms to ARM spec, not VisUAL.
BitArithmetic BIC
BitArithmetic LSL Shift value is modulo 32.
BitArithmetic LSR Shift value is modulo 32.
BitArithmetic ASR Shift value is modulo 32.
BitArithmetic ROR
BitArithmetic RRX
BitArithmetic TST
BitArithmetic TEQ
Mem LDR Does not support the LDR RX, =someLabel syntax.
Mem STR
Mem ADR
Mem FILL
Mem DCD
Mem EQU Does not support >1 forward reference.
MultMem LDM
MultMem STM
MultMem B
MultMem BL
MultMem END

Unless otherwise stated, the syntax for each instruction is the same as for VisUAL. More information on each of the instructions can be found at the Arm InfoCenter.

All instructions can be paired with any of the ARM condition codes, which can also be found in the InfoCenter.

For more detailed information on individual modules and instructions, see the individual documentation in the docs folder.

Top Level

The TopLevel module brings all of the instructions together and enables execution of a complete program in the form of a list of strings. It provides a simple interface for the GUI, which only has to provide the source file as a list of strings, as well as the current CPU & symbol state (which can easily be initialised using initDataPath).

The features of this module include:

  • Forward & backward referencing of labels in instructions (2 pass parsing).
  • Module-specific error handling. Each module can optionally return a custom error type in an Error monad (this is currently just a string).
  • Errors returned with a corresponding line number, to enable syntax highlighting in the GUI.
  • Branches using B, BL, MOV R15 or MVN R15 behave as expected, causing a program loop. _NB: in the GUI code, tail recursion is not optimised by FABLE and therefore > 500 branches results in a stack overflow.
  • Infinite loop protection: an error is thrown if more than 100,000 branches are taken. (this could be changed to a setting)
  • Program counter is always 8 greater than the current instruction value.
  • Parsing lines is immune to arbitrary whitespace within the line.
  • All condition codes are supported - an instruction's execution is dependent on current flag contents.
  • Arbitrary initialisation of registers, flags and memory contents (allows GUI to maintain CPU state)
  • Code is stored in memory.
  • Code is protected from being overwritten by instructions (returns an error). NB: if an instruction was somehow overwritten, execution would continue as if it was not
  • EQU instructions execute correctly; they are not stored in memory.

Please see the app respository for details of the GUI features.

The Main module also defines a command line interface to the TopLevel code, which enables loading and execution from an arbitrary file location. The resultant CPU state is stored in a JSON file in another arbitrary file location. Registers and flags can also be initialised via the CLI.

The TopLevelTests module defines a series of unit tests which test: parsing of individual lines, execution of individual lines, parsing of multiple lines in order, and execution of multiple lines in order. Every supported instruction is tested, and advanced features such as forward referencing, branches and label instructions are also included in testing.

Use of Github

Throughout the group stage of the project we adopted agile development practices. Weekly sprint goals were set in the first two weeks, with daily goals set in the last week.

Each team member was allocated tasks. Individual tasks were completed on branches, and pull requests were submitted once a branch was deemed complete by the author. Branches were not allowed to be merged without an approved review from another team member. All tests were required to pass before merging a pull request into master.

This module was referenced as a submodule in the electron app (GUI) repository, meaning any changes here could automatically be included in the app with a simple git pull --recurse-submodules.

NB: Originally, Travis CI was set up to automatically run tests on branches/commits but, as it runs on Linux, it wasn't compatible with the VisualTesting framework and so CI was disabled.

About

ARM Assembly Language Emulator implemented in F#

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages