VIXL Release 1.0

Refer to the README.md and LICENCE files for details.
diff --git a/tools/cross_build_gcc.sh b/tools/cross_build_gcc.sh
new file mode 100755
index 0000000..3a365d9
--- /dev/null
+++ b/tools/cross_build_gcc.sh
@@ -0,0 +1,67 @@
+#!/bin/sh
+
+# Copyright 2013, ARM Limited
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+#   * Redistributions of source code must retain the above copyright notice,
+#     this list of conditions and the following disclaimer.
+#   * Redistributions in binary form must reproduce the above copyright notice,
+#     this list of conditions and the following disclaimer in the documentation
+#     and/or other materials provided with the distribution.
+#   * Neither the name of ARM Limited nor the names of its contributors may be
+#     used to endorse or promote products derived from this software without
+#     specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+if [ "$#" -lt 1 ]; then
+  echo "Usage: tools/cross_build_gcc.sh <GCC prefix> [scons arguments ...]"
+  exit 1
+fi
+
+export CXX=$1g++
+export AR=$1ar
+export RANLIB=$1ranlib
+export CC=$1gcc
+export LD=$1ld
+
+OK=1
+if [ ! -x "$CXX" ]; then
+  echo "Error: $CXX does not exist or is not executable."
+  OK=0
+fi
+if [ ! -x "$AR" ]; then
+  echo "Error: $AR does not exist or is not executable."
+  OK=0
+fi
+if [ ! -x "$RANLIB" ]; then
+  echo "Error: $RANLIB does not exist or is not executable."
+  OK=0
+fi
+if [ ! -x "$CC" ]; then
+  echo "Error: $CC does not exist or is not executable."
+  OK=0
+fi
+if [ ! -x "$LD" ]; then
+  echo "Error: $LD does not exist or is not executable."
+  OK=0
+fi
+if [ $OK -ne 1 ]; then
+  exit 1
+fi
+
+
+shift
+scons $@
diff --git a/tools/git.py b/tools/git.py
new file mode 100644
index 0000000..b661d11
--- /dev/null
+++ b/tools/git.py
@@ -0,0 +1,75 @@
+# Copyright 2013 ARM Limited
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+#   * Redistributions of source code must retain the above copyright notice,
+#     this list of conditions and the following disclaimer.
+#   * Redistributions in binary form must reproduce the above copyright notice,
+#     this list of conditions and the following disclaimer in the documentation
+#     and/or other materials provided with the distribution.
+#   * Neither the name of ARM Limited nor the names of its contributors may be
+#     used to endorse or promote products derived from this software without
+#     specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY ARM LIMITED AND CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL ARM LIMITED BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import re
+import util
+import os.path
+
+def is_git_repository_root():
+  return os.path.isdir('.git')
+
+def get_current_branch():
+  status, branches = util.getstatusoutput('git branch')
+  if status != 0: util.abort('Failed to run git branch.')
+  match = re.search("^\* (.*)$", branches, re.MULTILINE)
+  if not match: util.abort('Failed to find the current branch.')
+
+  branch = match.group(1);
+
+  # If we are not on a named branch, return the hash of the HEAD commit.
+  # This can occur (for example) if a specific revision is checked out by
+  # commit hash, or during a rebase.
+  if branch == '(no branch)':
+    status, commit = util.getstatusoutput('git log -1 --pretty=format:"%H"')
+    if status != 0: util.abort('Failed to run git log.')
+    match = re.search('^[0-9a-fA-F]{40}$', commit, re.MULTILINE)
+    if not match: util.abort('Failed to find the current revision.')
+    branch = match.group(0)
+
+  return branch
+
+
+def get_tracked_files():
+  command = 'git ls-tree '
+  branch = get_current_branch()
+  options = ' -r --full-tree --name-only'
+
+  status, tracked = util.getstatusoutput(command + branch + options)
+  if status != 0: util.abort('Failed to list tracked files.')
+
+  return tracked
+
+
+# Get untracked files in src/, test/, and tools/.
+def get_untracked_files():
+  status, output = util.getstatusoutput('git status -s')
+  if status != 0: util.abort('Failed to get git status.')
+
+  untracked_regexp = re.compile('\?\?.*(src/|test/|tools/).*(.cc$|.h$)')
+  files_in_watched_folder = lambda n: untracked_regexp.search(n) != None
+  untracked_files = filter(files_in_watched_folder, output.split('\n'))
+
+  return untracked_files
diff --git a/tools/make_instruction_doc.pl b/tools/make_instruction_doc.pl
new file mode 100755
index 0000000..a244962
--- /dev/null
+++ b/tools/make_instruction_doc.pl
@@ -0,0 +1,112 @@
+#!/usr/bin/perl
+
+# Copyright 2013, ARM Limited
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+#   * Redistributions of source code must retain the above copyright notice,
+#     this list of conditions and the following disclaimer.
+#   * Redistributions in binary form must reproduce the above copyright notice,
+#     this list of conditions and the following disclaimer in the documentation
+#     and/or other materials provided with the distribution.
+#   * Neither the name of ARM Limited nor the names of its contributors may be
+#     used to endorse or promote products derived from this software without
+#     specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Assembler header file.
+my $hfile = "src/a64/assembler-a64.h";
+
+# Extra pseudo instructions added to AArch64.
+my @extras = qw/bind debug dci dc32 dc64/;
+
+my %inst = ();  # Global hash of instructions.
+
+$/ = '';
+open(IN, "<$hfile") or die("Can't open header file $header.\n");
+while(<IN>)
+{
+  # Find a function formatted like an instruction.
+  if(my($t) = /^  ((?:void|inline void) [a-z0-9]{1,6})\(/mgp)
+  {
+    my $before = ${^PREMATCH};
+    my $after = ${^POSTMATCH};
+
+    # Extract the instruction.
+    my($i) = $t =~ /(?:void|inline void) ([a-z0-9]{1,6})/;
+
+    # Extract the comment from before the function.
+    my($d) = $before =~ /.*  \/\/ ([A-Z].+?\.)$/;
+
+    # Extract and tidy up the function prototype.
+    my($p) = $after =~ /(.*?\))/ms;
+    $p =~ s/\n/\n  /g;
+    $p = "$t(".$p;
+
+    # Establish the type of the instruction.
+    my $type = 'integer';
+    ($i =~ /^f/) and $type = 'float';
+    ($i ~~ @extras) and $type = 'pseudo';
+
+    # Push the results into a hash keyed by prototype string.
+    $inst{$p}->{'type'} = $type;
+    $inst{$p}->{'mnemonic'} = $i;
+    $inst{$p}->{'description'} = $d;
+  }
+}
+close(IN);
+
+print <<HEADER;
+VIXL Supported Instruction List
+===============================
+
+This is a list of the AArch64 instructions supported by the VIXL assembler,
+disassembler and simulator. The simulator may not support all floating point
+operations to the precision required by AArch64 - please check the simulator
+source code for details.
+
+HEADER
+
+print describe_insts('AArch64 integer instructions', 'integer');
+print describe_insts('AArch64 floating point instructions', 'float');
+print describe_insts('Additional or pseudo instructions', 'pseudo');
+
+# Sort instructions by mnemonic and then description.
+sub inst_sort
+{
+  $inst{$a}->{'mnemonic'} cmp $inst{$b}->{'mnemonic'} ||
+  $inst{$a}->{'description'} cmp $inst{$b}->{'description'};
+}
+
+# Return a Markdown formatted list of instructions of a particular type.
+sub describe_insts
+{
+  my($title, $type) = @_;
+  my $result = '';
+  $result .= "$title\n";
+  $result .= '-' x length($title);
+  $result .= "\n\n";
+
+  foreach my $i (sort inst_sort keys(%inst))
+  {
+    next if($inst{$i}->{'type'} ne $type);
+    $result .= sprintf("### %s ###\n\n%s\n\n", $inst{$i}->{'mnemonic'}, $inst{$i}->{'description'});
+    $result .= "    $i\n\n\n";
+  }
+  $result .= "\n";
+  return $result
+}
+
+
diff --git a/tools/presubmit.py b/tools/presubmit.py
new file mode 100755
index 0000000..6632e4b
--- /dev/null
+++ b/tools/presubmit.py
@@ -0,0 +1,202 @@
+#!/usr/bin/env python2.7
+
+# Copyright 2013, ARM Limited
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+#   * Redistributions of source code must retain the above copyright notice,
+#     this list of conditions and the following disclaimer.
+#   * Redistributions in binary form must reproduce the above copyright notice,
+#     this list of conditions and the following disclaimer in the documentation
+#     and/or other materials provided with the distribution.
+#   * Neither the name of ARM Limited nor the names of its contributors may be
+#     used to endorse or promote products derived from this software without
+#     specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import os
+import sys
+import argparse
+import re
+
+import util
+import git
+
+# Google's cpplint.py from depot_tools is the linter used here.
+CPP_LINTER_RULES = '''
+build/class
+build/deprecated
+build/endif_comment
+build/forward_decl
+build/include_order
+build/printf_format
+build/storage_class
+legal/copyright
+readability/boost
+readability/braces
+readability/casting
+readability/constructors
+readability/fn_size
+readability/function
+readability/multiline_comment
+readability/multiline_string
+readability/streams
+readability/utf8
+runtime/arrays
+runtime/casting
+runtime/deprecated_fn
+runtime/explicit
+runtime/int
+runtime/memset
+runtime/mutex
+runtime/nonconf
+runtime/printf
+runtime/printf_format
+runtime/references
+runtime/rtti
+runtime/sizeof
+runtime/string
+runtime/virtual
+runtime/vlog
+whitespace/blank_line
+whitespace/braces
+whitespace/comma
+whitespace/comments
+whitespace/end_of_line
+whitespace/ending_newline
+whitespace/indent
+whitespace/labels
+whitespace/line_length
+whitespace/newline
+whitespace/operators
+whitespace/parens
+whitespace/tab
+whitespace/todo
+'''.split()
+
+
+def BuildOptions():
+  result = argparse.ArgumentParser(description='Run the linter and unit tests.')
+  result.add_argument('--verbose', '-v', action='store_true',
+                      help='Print all tests output at the end.')
+  result.add_argument('--notest', action='store_true',
+                      help='Do not run tests. Run the linter only.')
+  result.add_argument('--nolint', action='store_true',
+                      help='Do not run the linter. Run the tests only.')
+  result.add_argument('--noclean', action='store_true',
+                      help='Do not clean before build.')
+  result.add_argument('--jobs', '-j', metavar='N', type=int, default=1,
+                      help='Allow N jobs at once.')
+  return result.parse_args()
+
+
+def CleanBuildSystem():
+  status, output = util.getstatusoutput('scons mode=release --clean')
+  if status != 0: util.abort('Failed to clean in release mode.')
+  status, output = util.getstatusoutput('scons mode=debug --clean')
+  if status != 0: util.abort('Failed to clean in debug mode.')
+
+
+class Test:
+  def __init__(self, name, command, get_summary):
+    self.name = name
+    self.command = command
+    self.get_summary = get_summary
+    self.output = 'NOT RUN'
+    self.status = 'NOT RUN'
+    self.summary = 'NOT RUN'
+
+  def Run(self):
+    retcode, self.output = util.getstatusoutput(self.command)
+    self.status = 'PASS' if retcode == 0 else 'FAILED'
+    self.summary = self.get_summary(self.output)
+
+  def PrintOutcome(self):
+    print(('%s :'.ljust(20 - len(self.name)) + '%s\n' + ' ' * 18 + '%s')
+          %(self.name, self.status, self.summary))
+
+  def PrintOutput(self):
+    print('\n\n### OUTPUT of ' + self.name)
+    print(self.output)
+
+
+class Tester:
+  def __init__(self):
+    self.tests = []
+
+  def AddTest(self, test):
+    self.tests.append(test)
+
+  def RunAll(self, verbose):
+    for test in self.tests:
+      test.Run()
+      test.PrintOutcome()
+
+    if verbose:
+      for test in self.tests:
+        test.PrintOutput()
+
+
+if __name__ == '__main__':
+  original_dir = os.path.abspath('.')
+  # $ROOT/tools/presubmit.py
+  root_dir = os.path.dirname(os.path.dirname(os.path.abspath(sys.argv[0])))
+  os.chdir(root_dir)
+  args = BuildOptions()
+
+  if not args.nolint and not git.is_git_repository_root():
+    print 'WARNING: This is not a Git repository. The linter will not run.'
+    args.nolint = True
+
+  tester = Tester()
+  if not args.nolint:
+    lint_args = '--filter=-,+' + ',+'.join(CPP_LINTER_RULES) + ' '
+    tracked_files = git.get_tracked_files().split()
+    tracked_files = filter(util.is_cpp_filename, tracked_files)
+    tracked_files = ' '.join(tracked_files)
+    lint = Test('cpp lint',
+                'cpplint.py ' + lint_args + tracked_files,
+                util.last_line)
+    tester.AddTest(lint)
+  if not args.notest:
+    release = Test('cctest release',
+                   './tools/test.py --mode=release --jobs=%d' % args.jobs,
+                   util.last_line)
+    debug = Test('cctest debug',
+                 './tools/test.py --mode=debug --jobs=%d' % args.jobs,
+                 util.last_line)
+    tester.AddTest(release)
+    tester.AddTest(debug)
+
+  if not args.noclean:
+    CleanBuildSystem()
+
+  tester.RunAll(args.verbose)
+
+  # If the linter failed, print its output. We don't do the same for the debug
+  # or release tests because they're easy to run by themselves. In verbose mode,
+  # the output is printed automatically in tester.RunAll().
+  if not args.nolint and lint.status == 'FAILED' and not args.verbose:
+    lint.PrintOutput()
+
+  if git.is_git_repository_root():
+    untracked_files = git.get_untracked_files()
+    if untracked_files:
+      print '\nWARNING: The following files are untracked:'
+      for f in untracked_files:
+        print f.lstrip('?')
+
+  # Restore original directory.
+  os.chdir(original_dir)
diff --git a/tools/test.py b/tools/test.py
new file mode 100755
index 0000000..cf20385
--- /dev/null
+++ b/tools/test.py
@@ -0,0 +1,247 @@
+#!/usr/bin/env python2.7
+
+# Copyright 2013, ARM Limited
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+#   * Redistributions of source code must retain the above copyright notice,
+#     this list of conditions and the following disclaimer.
+#   * Redistributions in binary form must reproduce the above copyright notice,
+#     this list of conditions and the following disclaimer in the documentation
+#     and/or other materials provided with the distribution.
+#   * Neither the name of ARM Limited nor the names of its contributors may be
+#     used to endorse or promote products derived from this software without
+#     specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import os
+import sys
+import argparse
+import re
+import subprocess
+import threading
+import time
+import util
+
+
+def BuildOptions():
+  result = argparse.ArgumentParser(description = 'Unit test tool')
+  result.add_argument('name_filters', metavar='name filters', nargs='*',
+                      help='Tests matching any of the regexp filters will be run.')
+  result.add_argument('--mode', action='store', choices=['release', 'debug', 'coverage'],
+                      default='release', help='Build mode')
+  result.add_argument('--simulator', action='store', choices=['on', 'off'],
+                      default='on', help='Use the builtin a64 simulator')
+  result.add_argument('--timeout', action='store', type=int, default=5,
+                      help='Timeout (in seconds) for each cctest (5sec default).')
+  result.add_argument('--nobuild', action='store_true',
+                      help='Do not (re)build the tests')
+  result.add_argument('--jobs', '-j', metavar='N', type=int, default=1,
+                      help='Allow N jobs at once.')
+  return result.parse_args()
+
+
+def BuildRequiredObjects(arguments):
+  status, output = util.getstatusoutput('scons ' +
+                                        'mode=' + arguments.mode + ' ' +
+                                        'simulator=' + arguments.simulator + ' ' +
+                                        'target=cctest ' +
+                                        '--jobs=' + str(arguments.jobs))
+
+  if status != 0:
+    print(output)
+    util.abort('Failed bulding cctest')
+
+
+# Display the run progress:
+# [time| progress|+ passed|- failed]
+def UpdateProgress(start_time, passed, failed, card):
+  minutes, seconds = divmod(time.time() - start_time, 60)
+  progress = float(passed + failed) / card * 100
+  passed_colour = '\x1b[32m' if passed != 0 else ''
+  failed_colour = '\x1b[31m' if failed != 0 else ''
+  indicator = '\r[%02d:%02d| %3d%%|' + passed_colour + '+ %d\x1b[0m|' + failed_colour + '- %d\x1b[0m]'
+  sys.stdout.write(indicator % (minutes, seconds, progress, passed, failed))
+
+
+def PrintError(s):
+  # Print the error on a new line.
+  sys.stdout.write('\n')
+  print(s)
+  sys.stdout.flush()
+
+
+# List all tests matching any of the provided filters.
+def ListTests(cctest, filters):
+  status, output = util.getstatusoutput(cctest +  ' --list')
+  if status != 0: util.abort('Failed to list all tests')
+
+  available_tests = output.split()
+  if filters:
+    filters = map(re.compile, filters)
+    def is_selected(test_name):
+      for e in filters:
+        if e.search(test_name):
+          return True
+      return False
+
+    return filter(is_selected, available_tests)
+  else:
+    return available_tests
+
+
+# A class representing a cctest.
+class CCtest:
+  cctest = None
+
+  def __init__(self, name, options = None):
+    self.name = name
+    self.options = options
+    self.process = None
+    self.stdout = None
+    self.stderr = None
+
+  def Command(self):
+    command = '%s %s' % (CCtest.cctest, self.name)
+    if self.options is not None:
+      command = '%s %s' % (commnad, ' '.join(options))
+
+    return command
+
+  # Run the test.
+  # Use a thread to be able to control the test.
+  def Run(self, arguments):
+    command = [CCtest.cctest, self.name]
+    if self.options is not None:
+      command += self.options
+
+    def execute():
+      self.process = subprocess.Popen(command,
+                                      stdout=subprocess.PIPE,
+                                      stderr=subprocess.PIPE)
+      self.stdout, self.stderr = self.process.communicate()
+
+    thread = threading.Thread(target=execute)
+    retcode = -1
+    # Append spaces to hide the previous test name if longer.
+    sys.stdout.write('  ' + self.name + ' ' * 20)
+    sys.stdout.flush()
+    # Start the test with a timeout.
+    thread.start()
+    thread.join(arguments.timeout)
+    if thread.is_alive():
+      # Too slow! Terminate.
+      PrintError('### TIMEOUT %s\nCOMMAND:\n%s' % (self.name, self.Command()))
+      # If timeout was too small the thread may not have run and self.process
+      # is still None. Therefore check.
+      if (self.process):
+        self.process.terminate()
+      # Allow 1 second to terminate. Else, exterminate!
+      thread.join(1)
+      if thread.is_alive():
+        thread.kill()
+        thread.join()
+      # retcode is already set for failure.
+    else:
+      # Check the return status of the test.
+      retcode = self.process.poll()
+      if retcode != 0:
+        PrintError('### FAILED %s\nSTDERR:\n%s\nSTDOUT:\n%s\nCOMMAND:\n%s'
+                   % (self.name, self.stderr.decode(), self.stdout.decode(),
+                      self.Command()))
+
+    return retcode
+
+
+# Run all tests in the list 'tests'.
+def RunTests(cctest, tests, arguments):
+  CCtest.cctest = cctest
+  card = len(tests)
+  passed = 0
+  failed = 0
+
+  if card == 0:
+    print('No test to run')
+    return 0
+
+  # When the simulator is on the tests are ran twice: with and without the
+  # debugger.
+  if arguments.simulator:
+    card *= 2
+
+  print('Running %d tests... (timeout = %ds)' % (card, arguments.timeout))
+  start_time = time.time()
+
+  # Initialize the progress indicator.
+  UpdateProgress(start_time, 0, 0, card)
+  for e in tests:
+    variants = [CCtest(e)]
+    if arguments.simulator: variants.append(CCtest(e, ['--debugger']))
+    for v in variants:
+      retcode = v.Run(arguments)
+      # Update the counters and progress indicator.
+      if retcode == 0:
+        passed += 1
+      else:
+        failed += 1
+    UpdateProgress(start_time, passed, failed, card)
+
+  return failed
+
+
+if __name__ == '__main__':
+  original_dir = os.path.abspath('.')
+  # $ROOT/tools/test.py
+  root_dir = os.path.dirname(os.path.dirname(os.path.abspath(sys.argv[0])))
+  os.chdir(root_dir)
+
+  # Parse the arguments and build the executable.
+  args = BuildOptions()
+  if not args.nobuild:
+    BuildRequiredObjects(args)
+
+  # The test binary.
+  cctest = os.path.join(root_dir, 'cctest')
+  if args.simulator == 'on':
+    cctest += '_sim'
+  if args.mode == 'debug':
+    cctest += '_g'
+  elif args.mode == 'coverage':
+    cctest += '_gcov'
+
+  # List available tests.
+  tests = ListTests(cctest, args.name_filters)
+
+  # Delete coverage data files.
+  if args.mode == 'coverage':
+    status, output = util.getstatusoutput('find obj/coverage -name "*.gcda" -exec rm {} \;')
+
+  # Run the tests.
+  status = RunTests(cctest, tests, args)
+  sys.stdout.write('\n')
+
+  # Print coverage information.
+  if args.mode == 'coverage':
+    cmd = 'tggcov -R summary_all,untested_functions_per_file obj/coverage/src/aarch64'
+    p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
+                         stderr=subprocess.PIPE)
+    stdout, stderr = p.communicate()
+    print(stdout)
+
+  # Restore original directory.
+  os.chdir(original_dir)
+
+  sys.exit(status)
+
diff --git a/tools/util.py b/tools/util.py
new file mode 100644
index 0000000..2e84d9a
--- /dev/null
+++ b/tools/util.py
@@ -0,0 +1,56 @@
+# Copyright 2013, ARM Limited
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+#   * Redistributions of source code must retain the above copyright notice,
+#     this list of conditions and the following disclaimer.
+#   * Redistributions in binary form must reproduce the above copyright notice,
+#     this list of conditions and the following disclaimer in the documentation
+#     and/or other materials provided with the distribution.
+#   * Neither the name of ARM Limited nor the names of its contributors may be
+#     used to endorse or promote products derived from this software without
+#     specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import sys
+import subprocess
+import shlex
+import re
+
+
+def abort(message):
+  print('ABORTING: ' + message)
+  sys.exit(1)
+
+
+# Emulate python3 subprocess.getstatusoutput.
+def getstatusoutput(command):
+  try:
+    args = shlex.split(command)
+    output = subprocess.check_output(args, stderr=subprocess.STDOUT)
+    return 0, output.rstrip('\n')
+  except subprocess.CalledProcessError as e:
+    return e.returncode, e.output.rstrip('\n')
+
+
+def last_line(text):
+  lines = text.split('\n')
+  last = lines[-1].split('\r')
+  return last[-1]
+
+
+CPP_EXT_REGEXP = re.compile('\.cc$|\.h$')
+def is_cpp_filename(filename):
+  return CPP_EXT_REGEXP.search(filename) != None