diff --git a/.travis.yml b/.travis.yml index 0846ee0..01db5da 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,6 +20,10 @@ script: --cov=revelation revelation/test/ - python -m doctest scripts/diff_trace.py - python -m doctest scripts/get_instructions_used.py +- cd docs +- make html +- make linkcheck +- cd .. - PYTHONPATH=${HOME}/pydgin/:. ${HOME}/pypy/rpython/bin/rpython --no-pdb --opt=jit revelation/sim.py - if [ "${TRAVIS_PULL_REQUEST}" == "false" ] && [ "${TRAVIS_BRANCH}" == "master" ] ; then PYTHONPATH=${HOME}/pydgin/:. ${HOME}/pypy/rpython/bin/rpython --no-pdb --opt=jit revelation/sim.py --debug ; diff --git a/README.md b/README.md index 43cc4b0..9bdadf3 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,7 @@ If you want your compiled Revelation simulator to be able to write out a trace o Please report any problems you have with Revelation on the [Issues page](https://github.com/futurecore/revelation/issues). -To contribute to Revelation itself, please raise a Pull Request, and if it is relevant to your changes please include unit tests. +To contribute to Revelation itself, please fork this repository and raise a Pull Request, and if it is relevant to your changes please include unit tests. Translating Revelation will be relatively slow, so it is easiest to run and test the simulator un-translated, until your changes are stable, e.g.: ```bash @@ -151,7 +151,7 @@ More information about this license can be found here: * http://choosealicense.com/licenses/bsd-3-clause * http://opensource.org/licenses/BSD-3-Clause -Some test programs within this repository were previously published by other authors, and come with their own license agreements. +Some test programs and benchmarks within this repository were previously published by other authors, and come with their own license agreements. ## Acknowledgements diff --git a/docs/ambiguities.rst b/docs/ambiguities.rst deleted file mode 100644 index 101f35f..0000000 --- a/docs/ambiguities.rst +++ /dev/null @@ -1,65 +0,0 @@ -Mistakes and ambiguities in v14.03.11 of the Epiphany Architecture Reference Manual ------------------------------------------------------------------------------------ - -These notes are for anyone wishing to contribute to Revelation. -The `Epiphany Architecture Reference Manual `_ is the definitive reference for the architecture. -Revelation was originally based on v14.03.11 of this manual and v2015.1 of the eSDK. -This page documents a list of issues and potential misunderstandings with that version of the manual. - - -Issues with the decode table (pp 155) -===================================== - -* In ``LD/STR(INDEX)(32)`` and ``RM`` should be ``RN`` -* The ``BITR`` instruction has a 5-bit immediate integer, according to the decode table on page 155, but on page 81, the instruction only takes operands from registers. -* ``FLOAT``, ``FIX`` and ``FABS`` have some extra bits in the decode table for an ``RM`` operand, even though these instructions are unary -* In the last row of the decode table, the ``UNIMPL`` instruction is marked as 16 bit but cannot fit into 16 bits, this should be written as ``UNIMPL(32)`` - - -Issues in Appendix A -===================== -* ``BCOND`` example on pp 80 ``add r1,r1#1 ; some operation`` should be ``add r1,r1,#1`` -* In description of ``ADD`` and ``SUB`` (pp 76 and 108) flag ``OV`` should be ``AV`` -* In description of ``JALR`` (pp 100) ``LR = PC;`` should be ``LR = PC + 2 (16 bit), PC + 4 (32 bit)`` -- i.e. the jump should save the address of the *next* instruction, to prevent infinite loops -* The DMA transfer example on pp 72 fails to compile with this error: ``dma_transfer.s:7: Error: unrecognised instruction `_1d_descr'`` -* All ``ldrs`` and ``strs`` should be ``ldrh`` and ``strh``: - * The ``LDR (POSTMODIFY)`` example on pp 103 fails to compile with the error ``ldrdpm.s:3: Error: unrecognised form of instruction 'ldrs r31,[r2],#1'`` - * The ``LDR (DISPLACEMENT-POSTMODIFY)`` example on pp 105 fails to compile with the error ``ldrpm.s:3: Error: unrecognised form of instruction 'ldrs r31,[r2],r1'`` - * The ``STR (POSTMODIFY)`` example on pp 121 fails to compile with the error ``str_pm.s:3: Error: unrecognised form of instruction 'strs r31,[r2],r1'`` - * The ``STR (DISPLACEMENT-POSTMODIFY)`` example on pp 122 fails to compile with the error ``str_dpm.s:3: Error: unrecognised form of instruction 'strs r31,[r2],#2'`` -* In the ``SUB`` instruction on page 118, ``AC = BORROW`` should say ``AC = ~BORROW``. -* In the ``MOVTS`` and ``MOVFS`` operations, the code the compiler produces swaps ``rd`` and ``rn``, which is not mentioned in Appendix A. The code on page 81 says: - -.. code-block:: asm - - MOV R0,%low(x87654321) ; - MOV R0,%high(x87654321) ; - BITR R0,R0 ; R0 gets 0x84C2A6B1 - - -which does not compile, and isn't correct in any case. This should say: - -.. code-block:: asm - - MOV R0,%low(0x87654321) ; - MOVT R0,%high(0x87654321) ; - BITR R0,R0 ; R0 gets 0x84C2A6E1 - - -Ambiguities -=========== -* In the ``SUB`` instruction on page 118, the carry flag, ``AC``, is not used in the subtraction. i.e. should the operation be: ``Rd = Rn - Rm - ~(AC)``? The same applies to ``ADD``. -* In the ``TRAP`` instruction on page 124, each system call will produce a return value and an error number, but the manual does not say whether these are saved in registers. -* In the ``RTI`` instruction on page 116, the **Operation** section says ``IPEND[i]=0; where i is the current interrupt level being serviced``, but it is not clear how the current interrupt level is set. - - -Typographical mistakes -======================= -* In Appendix A, pp 81 the ``BITR`` instruction does not have a section heading (or the heading has the wrong styling), so ``BITR`` does not appear in the Table of Contents. -* pp 109: Too many right parentheses in **Operation** section. - - -Would-be-nice-to-have improvements -================================== - -* Instruction descriptions contain pseudo-code for each ISA instruction, but do not deal with incrementing ``COUNTER0`` and ``COUNTER1``. Ideally it would be nice for each instruction in Appendix A to state clearly whether and when counters are updated. diff --git a/docs/conf.py b/docs/conf.py index d5e552b..3d82449 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -54,16 +54,16 @@ # General information about the project. project = u'Revelation' -copyright = u'2015, Sarah Mount, Carl Friedrich Bolz' +copyright = u'2015-2016, Sarah Mount, Carl Friedrich Bolz' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = '0.1' +# version = '0.1' # The full version, including alpha/beta/rc tags. -release = '0.1' +# release = '0.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/contributing.rst b/docs/contributing.rst index cd61253..fa62efe 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -1,57 +1,105 @@ Contributing to Revelation ========================== -Contributions to Revelation are welcome. +Contributions to Revelation are welcome, particularly bug reports. The project source code is available `on GitHub `_ and bugs can be reported via the `issue tracker `_. If you wish to contribute code, or improvements in this documentation, please fork the project on `on GitHub `_ and issue a pull request. Your pull request will be automatically checked by the `travis continuous integration `_ tool before it is merged. To understand how the Revelation source code is structured, it is a good idea to start by reading about the `Pydgin `_ framework. -.. seealso:: Derek Lockhart and Berkin Ilbeyi (2015) `Pydgin: Using RPython to Generate Fast Instruction-Set Simulators `_ Guest post on the PyPy status blog. +.. seealso:: Derek Lockhart and Berkin Ilbeyi (2015) `Pydgin: Using RPython to Generate Fast Instruction-Set Simulators `_ Guest post on the PyPy status blog. -Any changes to the source code should normally be accompanied by unit tests, and should certainly not reduce the current code coverage below 99%. +Any changes to the source code should normally be accompanied by unit tests, and should certainly not reduce the current code coverage below 100%. -Running the unit tests locally ------------------------------- +Running Revelation un-translated +--------------------------------- -Revelation comes with a large number of unit tests, which are intended to be run with the `py.test `_ framework. +When working with the Revelation source code, it is easiest to run and test the simulator un-translated, until your changes are stable. +Translating Revelation is relatively slow, however it is easy (albeit slower) to run the simulator without translating it, e.g.: + +.. code-block:: bash + + $ pypy revelation/sim.py revelation/test/c/hello.elf # Use pypy or python2 here + Loading program revelation/test/c/hello.elf on to core 0x808 (32, 08) + Hello, world! + Done! Total ticks simulated = 1951 + Core 0x808 (32, 08): STATUS=0x00000005, Instructions executed=1951 + +To work with the code here you need a copy of Pydgin, which you can obtain a copy from the `Pydgin project page `_. +Pydgin is a framework for writing functional simulators as `just in time interpreters `_. + + +Structure of the code +--------------------- + +To understand the Revelation source code, it is helpful to read about Pydgin, and have a copy of the `Epiphany Architecture Reference Manual `_ to hand. +However, there are a number of mistakes in that document, many of which are `listed on the Parallella discussion forum `_. +This `set of notes `_ from Alex Rønne Petersen is also extremely helpful, as is the `Epiphany GDB code `_. + +Revelation is structured as follows: + +- `revelation/argument_parser.py `_ simple argument parser (RPtyhon projects do not use `argparse` or similar). +- `revelation/condition_codes.py `_ condition codes for branch instructions. +- `revelation/elf_loader.py `_ function to load an ELF file onto an individual Epiphany core. +- `revelation/execute_bitwise.py `_ semantics of bitwise instructions. +- `revelation/execute_branch.py `_ semantics of branch instructions. +- `revelation/execute_farith.py `_ FPU model. +- `revelation/execute_interrupt.py `_ semantics of instructions relating to interrupts (``rti``, ``trap``, etc.). +- `revelation/execute_jump.py `_ semantics of ``jr`` and ``jalr`` instructions. +- `revelation/execute_load_store.py `_ semantics of load and store instructions. +- `revelation/execute_mov.py `_ semantics of move instructions. +- `revelation/instruction.py `_ simple model of an instruction, with methods to retrieve operands. +- `revelation/isa.py `_ instruction encodings. +- `revelation/logger.py `_ an object for logging ``--debug`` strings to ``r_trace.out``. +- `revelation/machine.py `_ model of a single Epiphany core, including flags. +- `revelation/registers.py `_ dictionaries and functions for finding named registers and their sizes. +- `revelation/sim.py `_ entry point to simulator. +- `revelation/storage.py `_ RAM model. +- `revelation/utils.py `_ bit manipulation utilities. + + +Running the unit tests +---------------------- + +Revelation comes with a large number of unit tests, which are intended to be run with the `py.test `_ framework. To run the provided tests, first ensure that the required packages are installed: .. code-block:: bash $ pip install -r requirements.txt - Then run the tests themselves: .. code-block:: bash - $ py.test -s --cov-report term-missing --cov epiphany epiphany/test/ --no-cov-on-fail -n 4 + $ py.test --cov-report term-missing --cov revelation revelation/test/ + +Note that the tests may take some time to run, particularly those that load an ELF file. Structure of the unit tests --------------------------- -All unit tests can be found in the ``epiphany.test`` package. -Most tests are written in pure Python and test the internals of the simulator code, but there are also two directories of C and Assembler code which contain integration tests. - +All unit tests can be found in the `revelation.test `_ package. +Most tests are written in pure Python and test the internals of the simulator code. Revelation provides a number of convenience modules which are intended to make it easier to quickly construct unit tests and reduce duplicate code. It is recommended that anyone adding new tests make uses of these modules, which are described below. + The ``opcode_factory`` module ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Epiphany instructions are 32bit or 16bit binary numbers. -Writing these by hand is error prone and tedious, and loading an ELF file is not appropriate for small unit tests. -The `epiphany.test.opcode_factory `_ module provides a function to create each instruction in the Epiphany ISA. +Writing these by hand is error prone and tedious, and loading an ELF file is not always appropriate for small unit tests. +The `revelation.test.opcode_factory `_ module provides a function to create every instruction in the Epiphany ISA. Where there are 32bit and 16bit variants of the same instruction, both versions are available. For example, the following code creates 32 and 16bit versions of the *logical shift left* instruction: .. code-block:: python - >>> import epiphany.test.opcode_factory as opcode_factory + >>> import revelation.test.opcode_factory as opcode_factory >>> bin(opcode_factory.lsl32(rd=43, rn=42, rm=41)) '0b10110110100010100110100010101111' >>> bin(opcode_factory.lsl16(rd=3, rn=2, rm=1)) @@ -62,9 +110,9 @@ Note that operands to the instruction are passed to the factory function as keyw These are named exactly as they are described in the opcode decode table on page 155 of the `Epiphany Architecture Reference Manual `_. In the example above, the LSL instruction takes three operands: -* **rd** a destination register -* **rn** an operand register -* **rm** an operand register + - **rd** a destination register + - **rn** an operand register + - **rm** an operand register The ``new_state`` function @@ -72,7 +120,7 @@ The ``new_state`` function Unit tests for Revelation usually check whether the simulator halts with the expected state (i.e. flags, registers and RAM). It is often useful to be able to start the simulator in a particular state. -Rather than setting each register or flag individually, Revelation provides the `epiphany.test.machine.new_state `_ function which can accept register and flag values as named parameters. +Rather than setting each register or flag individually, Revelation provides the `epiphany.test.machine.new_state `_ function which can accept register and flag values as named parameters. For example: @@ -93,7 +141,7 @@ The ``StateChecker`` class ^^^^^^^^^^^^^^^^^^^^^^^^^^ Similarly, it is inconvenient to write separate assertions to check each flag, register or word in RAM . -The `epiphany.test.machine `_ module provides a class called ``StateChecker`` which manages this. +The `epiphany.test.machine `_ module provides a class called ``StateChecker`` which manages this. A new ``StateChecker`` takes register and flag values as parameters to its constructor, in exactly the same way as the ``new_state`` function described above. The ``StateChecker.check`` method takes a state as a parameter, then automatically runs assertions to check that each register or flag of interest is as expected. @@ -101,18 +149,16 @@ For example: .. code-block:: python - from epiphany.instruction import Instruction - from epiphany.isa import decode - from epiphany.machine import RESET_ADDR - from epiphany.test.machine import StateChecker, new_state + from revelation.instruction import Instruction + from revelation.isa import decode + from revelation.machine import RESET_ADDR + from revelation.test.machine import StateChecker, new_state - import opcode_factory + import revelation.test.opcode_factory as opcode_factory import pytest @pytest.mark.parametrize('is16bit,val', [(True, 0b111), (False, 0b1111)]) def test_execute_movcond(is16bit, val): - """Test that MOV can move values between registers. - """ state = new_state(AZ=1, rf1=val) instr = (opcode_factory.movcond16(condition=0b0000, rd=0, rn=1) if is16bit else opcode_factory.movcond32(condition=0b0000, rd=0, rn=1)) @@ -123,7 +169,7 @@ For example: expected_state.check(state) -Note that like most unit tests in Revelation, the example above uses `pytest.mark.parametrize `_ to avoid duplicating code. +Note that like most unit tests in Revelation, the example above uses `pytest.mark.parametrize `_ to avoid duplicating code. Checking the contents of RAM @@ -136,127 +182,136 @@ For example: .. code-block:: python - @pytest.mark.parametrize('sub,new_rn', [(1, 8 - 4), ... (0, 8 + 4)]) + @pytest.mark.parametrize('sub,new_rn', [(1, 8 - 4), + (0, 8 + 4), + (1, 8 - 4), + (0, 8 + 4)]) def test_execute_str_disp_pm(sub, new_rn): - state = new_state(rf0=0xFFFFFFFF, rf5=8) - # We can set the contents of a word in memory here: - # state.mem.write(8, 4, 42) # Start address, number of bytes, value + # Store. + state = new_state(rf0=0xffffffff, rf5=8) + # bb: 00=byte, 01=half-word, 10=word, 11=double-word instr = opcode_factory.ldstrpmd32(rd=0, rn=5, sub=sub, imm=1, bb=0b10, s=1) name, executefn = decode(instr) executefn(state, Instruction(instr, None)) - expected_state = StateChecker(rf0=0xFFFFFFFF, rf5=new_rn) - # Check the contents of the half-word starting at address 8: - expected_state.check(state, memory=[(8, 4, 0xFFFFFFFF)]) + expected_state = StateChecker(rf0=0xffffffff, rf5=new_rn) + expected_state.check(state, memory=[(8, 4, 0xffffffff)]) The ``MockEpiphany`` class ^^^^^^^^^^^^^^^^^^^^^^^^^^ In the examples above, each unit test executed exactly one Epiphany instruction. -It is possible to execute a list of instructions, using the `epiphany.test.sim.MockEpiphany `_ class. +It is possible to execute a list of instructions, using the `epiphany.test.sim.MockEpiphany `_ class. This allows you to write a simple "program" using the opcode factory to construct each instruction, without having to compile an ELF file. -The following example tests that the ``bkpt16`` instruction correctly advances the program counter and halts the simulator: +The following example tests that the ``trap16(3)`` instruction correctly halts the simulator: .. code-block:: python - from epiphany.machine import RESET_ADDR - from epiphany.test.sim import MockEpiphany - from epiphany.test.machine import StateChecker + from revelation.machine import RESET_ADDR + from revelation.test.sim import MockRevelation + from revelation.test.machine import StateChecker + from revelation.test.opcode_factory as opcode_factory - import opcode_factory - - def test_sim_nop16_bkpt16(): - instructions = [(opcode_factory.nop16(), 16), - (opcode_factory.bkpt16(), 16), - ] - epiphany = MockEpiphany() - epiphany.init_state(instructions) - assert epiphany.state.running - epiphany.run() - expected_state = StateChecker(pc=(4 + RESET_ADDR)) - expected_state.check(epiphany.state) - assert not epiphany.state.running + def test_sim_trap16_3(): + instructions = [(opcode_factory.trap16(3), 16)] + revelation = MockRevelation() + revelation.init_state(instructions) + assert revelation.states[0].running + exit_code, ticks = revelation.run() + expected_state = StateChecker(pc=(2 + RESET_ADDR)) + expected_state.check(revelation.states[0]) + assert EXIT_SUCCESS == exit_code + assert len(instructions) == ticks + assert not revelation.states[0].running Integration tests that run ELF files ------------------------------------- -Tests that load and execute ELF files are structured differently to the unit tests above. +Many tests use compiled ELF files, which should be compiled with the `2016.3.1 version of the eSDK `_ and checked into the repository. +Makefiles are provided in all relevant directories. + +You can find compiled ELF files, and the source that generated them, in the following directories: + +- ``revelation/test/asm`` Assembler files compiled to Epiphany ELF format (intended to run on a single-core). +- ``revelation/test/c`` C files compiled to Epiphany ELF format (intended to run on a single-core). +- ``revelation/test/multicore`` C files compiled to Epiphany ELF format (intended to run on more than one core). +- ``revelation/test/syscall-layout`` C files compiled to Epiphany ELF format. +- ``revelation/test/zigzag`` C files compiled to Epiphany ELF format (intended to run on more than one core). + +The `asm` directory contains at least one assembler file for each Epiphany instruction, most test cases are taken from the `Epiphany Architecture Reference Manual `_. +The `c` and `multicore` directories contain more complex test cases (e.g. testing interrupts and system calls). + +The ``syscall-layout`` and ``zigzag`` directories are different to the others. +``syscall-layout`` tests write out the format of ``stat`` and ``fstat`` objects, this is intended to help debugging Revelation syscalls on a new platform. +``zigzag`` contains a complex multicore test case written by Ola Jeppsson, you can find the original in the `esim-test-bins `_ repository. + +Where test cases are written by other authors, they should contain all relevant copyright notices and attributions. + +Tests that load and execute ELF files are structured differently to the pure-Python unit tests. Instead of using the mocking framework that Revelation provides, integration tests need to load ELF files into memory and run the simulator as if it had been invoked on the command line. -Assertions can then use the `epiphany.test.machine.StateMachine `_ class, or can use the `capsys `_ fixture provided by `py.test `_. +Assertions can then use the `revelation.test.machine.StateMachine `_ class, or can use the `capsys `_ fixture provided by `py.test `_. -For example, this simple piece of C can be found in the file `epiphany/test/c/nothing.c `_: +For example, this simple piece of C can be found in the file `epiphany/test/c/hello.c `_: .. code-block:: c + #include + #include int main() { - return 0; + printf("Hello, world!\n"); } -The code is compiled with a `Makefile `_ which can be found in the same directory as the C code. +The code is compiled with a `Makefile `_ which can be found in the same directory as the C code. -Each ELF file which has been compiled from C code has a corresponding Python unit test which can be found in `epiphany/test/test_compiled_c.py `_. +Each ELF file which is in the ``revelation/test/c/`` directory has a corresponding Python unit test which can be found in `revelation/test/test_compiled_c.py `_. These tests are normally parametrized, to avoid duplicate code. For example: .. code-block:: python + from revelation.sim import EXIT_SUCCESS, Revelation + from revelation.test.machine import StateChecker + import os.path import pytest - elf_dir = os.path.join('epiphany', 'test', 'c') + elf_dir = os.path.join(os.path.dirname(os.path.abspath('__file__')), + 'revelation', 'test', 'c') + - @pytest.mark.parametrize("elf_file,expected", [('nothing.elf', 176), - ... - ]) - def test_compiled_c(elf_file, expected, capsys): + @pytest.mark.parametrize('elf_file,expected', + [('hello.elf', 'Hello, world!\n'), + ... + ]) + def test_compiled_c_with_output(elf_file, expected, capfd): """Test an ELF file that has been compiled from a C function. - This test checks that the correct number of instructions have been executed. + This test checks text printed to STDOUT. """ elf_filename = os.path.join(elf_dir, elf_file) - epiphany = Epiphany() + revelation = Revelation() with open(elf_filename, 'rb') as elf: - epiphany.init_state(elf, elf_filename, '', [], False, is_test=True) - epiphany.max_insts = 10000 - epiphany.run() - out, err = capsys.readouterr() - expected_text = 'Instructions Executed = ' + str(expected) - assert expected_text in out + revelation.init_state(elf, elf_filename, False, is_test=True) + revelation.max_insts = 100000 + revelation.run() + assert not revelation.states[0].running + out, err = capfd.readouterr() assert err == '' - assert not epiphany.state.running + expected_full = (('Loading program %s on to core 0x808 (32, 08)\n' % elf_filename) + + expected) + assert out.startswith(expected_full) -Similarly, the `epiphany/test/asm/ `_ directory contains an assembler file for each opcode in the Epiphany ISA. -Unit tests for the resulting ELF files can be found in `epiphany/test/test_asm.py `_. +Similarly, the `epiphany/test/asm/ `_ directory contains an assembler file for each opcode in the Epiphany ISA. +Unit tests for the resulting ELF files can be found in `epiphany/test/test_asm.py `_. Compiling your own ELF files ---------------------------- -In order to recompile the ELF files in the Revelation repository, or create new ELFs, you will need to install the `official Epiphany SDK `_ provided by Adapteva. -If you do not wish to install the Adapteva toolchain on your own machine, we have provided a `Docker image `_ which has the Epiphany toolchain pre-installed. - - -Compiling the simulator ------------------------ - -To compile the simulator to a native executable, you need to first clone (or download) a recent version of the `PyPy toolchain `_. -The ``rpython`` directory from PyPy needs to be included in your ``PYTHONPATH`` environment variable. - -To compile *without* a JIT: - -.. code-block:: bash - - $ PYTHONPATH=. .../pypy/rpython/bin/rpython -Ojit epiphany/sim.py - - -To compile the simulator *with* a JIT: - -.. code-block:: bash - - $ PYTHONPATH=. ../../pypy/rpython/bin/rpython -Ojit epiphany/sim.py +In order to recompile the ELF files in the Revelation repository, or create new ELFs, you will need to install version 2016.3.1 of the `official Epiphany SDK `_ provided by Adapteva. .. toctree:: diff --git a/docs/index.rst b/docs/index.rst index 53a19af..973943d 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -10,11 +10,29 @@ You can read more about Pydgin in this paper: .. image:: https://www.parallella.org/wp-content/uploads/2014/11/parallella-board-22-609x400.jpg +License +------- + +Revelation is offered under the terms of the Open Source Initiative BSD 3-Clause License. +More information about this license can be found here: + +- http://choosealicense.com/licenses/bsd-3-clause +- https://opensource.org/licenses/BSD-3-Clause + +Some test programs and benchmarks were previously published by other authors, and come with their own license agreements. + + +Acknowledgements +---------------- + +Early work on Revelation was funded by a `University of Wolverhampton ERAS award `_. +`Carl Friedrich Bolz `_ helped to write the early Revelation commits. +Thanks to `the Pydgin project `_, especially `Berkin Ilbeyi `_ and Derek Lockhart. + + .. toctree:: :maxdepth: 3 :hidden: quickstart contributing - ambiguities - notes diff --git a/docs/notes.rst b/docs/notes.rst deleted file mode 100644 index e6c4652..0000000 --- a/docs/notes.rst +++ /dev/null @@ -1,150 +0,0 @@ -Notes on the Epiphany architecture -================================== - -Registers ---------- - -+----------+-------------+-----------------------------------------+--------------+ -| **Name** | **Synonym** | **Role in the Procedure Call Standard** | **Saved By** | -+==========+=============+=========================================+==============+ -| R0 | A1 | Argument/result/scratch register #1 | Caller saved | -+----------+-------------+-----------------------------------------+--------------+ -| R1 | A2 | Argument/result/scratch register #2 | Caller saved | -+----------+-------------+-----------------------------------------+--------------+ -| R2 | A3 | Argument/result/scratch register #3 | Caller saved | -+----------+-------------+-----------------------------------------+--------------+ -| R3 | A4 | Argument/result/scratch register #4 | Caller saved | -+----------+-------------+-----------------------------------------+--------------+ -| R4 | V1 | Register variable #1 | Callee Saved | -+----------+-------------+-----------------------------------------+--------------+ -| R5 | V2 | Register variable #2 | Callee Saved | -+----------+-------------+-----------------------------------------+--------------+ -| R6 | V3 | Register variable #3 | Callee Saved | -+----------+-------------+-----------------------------------------+--------------+ -| R7 | V4 | Register variable #4 | Callee Saved | -+----------+-------------+-----------------------------------------+--------------+ -| R8 | V5 | Register variable #5 | Callee Saved | -+----------+-------------+-----------------------------------------+--------------+ -| R9 | V6/SB | Register variable #6/Static base | Callee Save | -+----------+-------------+-----------------------------------------+--------------+ -| R10 | V7/SL | Register Variable #7/Stack limit | Callee Saved | -+----------+-------------+-----------------------------------------+--------------+ -| R11 | V8/FP | Variable Register #8/Frame Pointer | Callee Saved | -+----------+-------------+-----------------------------------------+--------------+ -| R12 | - | Intra-procedure call scratch register | Caller saved | -+----------+-------------+-----------------------------------------+--------------+ -| R13 | SP | Stack Pointer | N/A | -+----------+-------------+-----------------------------------------+--------------+ -| R14 | LR | Link Register | Callee Saved | -+----------+-------------+-----------------------------------------+--------------+ -| R15 | | General Use | Callee Saved | -+----------+-------------+-----------------------------------------+--------------+ -| R16-R27 | | General use | Caller saved | -+----------+-------------+-----------------------------------------+--------------+ -| R28-R31 | | Reserved for constants | N/A | -+----------+-------------+-----------------------------------------+--------------+ -| R32-R43 | | General use | Callee saved | -+----------+-------------+-----------------------------------------+--------------+ -| R44-R63 | | General Use | Caller saved | -+----------+-------------+-----------------------------------------+--------------+ - - -Flags ------ - -ACTIVE -^^^^^^ -When set, it indicates that core is currently active. -The core is inactive at reset and is activated by an external agent asserting an interrupt. Once activated, the core stays active until the user asserts the IDLE instruction, at which time the core enters a standby state. -During the standby state, core clocks are disabled and the power consumption is minimized. -Applications that need minimal power consumption should use the IDLE instruction to put the core in a standby state and use interrupts to activate the core when needed. - -GID -^^^ -When set it indicates that all external interrupts are blocked. -The bit is set immediately on an interrupt occurring, giving the interrupt service routine enough time to save critical registers before another higher priority interrupt can occur. -The flag is cleared by executing an RTI instruction, indicating the end of the service routine or by a GIE instruction indicating it is safe to allow a higher priority to begin if one is currently latched in the ILAT register. - -WAND -^^^^ -A multicore flag set by the WAND instruction. -The WAND flag is an output of the core that gets "ANDed" together with the WAND flags from other cores to produce a global WAND interrupt when cores have raised their respective flags. - -AZ -^^ -The AZ (integer zero) flag set by an integer instruction when all bits of the result are zero and -cleared for all other bit patterns. The flag is unaffected by all non-integer instructions. - -AN -^^ -The AN (integer negative) flag set to on by an integer instruction when the most-significant bit (MSB) of the result is 1 and cleared when the MSB of the result is 0. -The flag is unaffected by all non-integer instructions. - -AC -^^ -The AC (integer carry) flag is the carry out of an ADD or SUB instruction, is cleared by all other integer instructions, and is unaffected by all non-integer instructions. - -AV -^^ -The AV (integer overflow) flag set by the ADD instruction when the input signs are the same and the output sign is different from the input sign or by the SUB instruction when the second operand sign is different from the first operand and the resulting sign is different from the first operand. -The flag is cleared by all other integer instructions and is unaffected by all non-integer instructions. - -BZ -^^ -The BZ (floating-point zero) flag is set by a floating-point instruction when the result is zero. -The flag unaffected by all non-floating-point instructions. - -BN -^^ -The BN (floating-point negative) flag is set by a floating-point instruction when the sign bit (MSB) of the result is set to 1. -The flag unaffected by all non-floating-point instructions - -BV -^^ -The BV (floating-point overflow) flag is set by a floating-point instruction when the post rounded result overflows(unbiased exponent>127), otherwise the BV flag is cleared. -The flag unaffected by all non-floating-point instructions. - -AVS -^^^ -Sticky integer overflow flag set when the AV flag goes high, otherwise not cleared. -The flag is only affected by the ADD and SUB instructions. - -BVS -^^^ -Sticky floating-point overflow flag set when the BV flag goes high, otherwise not cleared. -The flag is unaffected by all non-floating-point instructions. - -BIS -^^^ -Sticky floating-point invalid flag set by a floating-point instruction if the either of the input operand is NAN, otherwise not cleared. -The flag is unaffected by all non-floating-point instructions. - -BUS -^^^ -Sticky floating-point underflow flag set by a floating-point instruction if the result is denormal or -one of the inputs to the operation is denormal, otherwise not cleared. -The flag is unaffected by all non-floating-point instructions. - -EXCAUSE -^^^^^^^ -A three bit field indicating the cause of a software exception. -A software exception edge interrupt is generated whenever this field is non-zero. -The software exception cause values differ for Epiphany-III and IV and can be found in Appendix-C. - - -LD / STR data size ------------------- -Load and store transactions with unaligned addresses generate a software exception that is handled by the node's interrupt controller. -For unaligned write accesses, data is still written to memory, but the data written will be incorrect. -Unaligned reads return values to the register file before an unaligned exception occur:: - - 00=byte, 01=half-word, 10=word, 11=double-word - - -Memory-mapping --------------- -The 32-bit address map supports up to 4095 cores in a single shared memory system, but practically some of the memory space will probably be dedicated to off-chip SDRAM and memory mapped IO peripherals. - -.. toctree:: - :maxdepth: 2 - :hidden: diff --git a/docs/quickstart.rst b/docs/quickstart.rst index af34fb3..b23df3b 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -1,122 +1,167 @@ Quickstart guide ================ -Revelation can be run either as a Python program or as a native executable. -A compiled version of the simulator will include a just in time compiler, and will therefore simulate long running programs much faster. -However, the simulator is invoked in the same way, with the same command-line switches, whether you have compiled it or not. -See below for instructions on how to compile the code to an executable. +In order to use Revelation, you need to obtain a native binary build of the simulator. +Intel / GNU-Linux builds are available from the `revelation-bins repository `_. +You should normally use the JITed version of the simulator, ``pydgin-revelation-jit`` or ``pydgin-revelation-jit-debug``. +The ``--debug`` options is enabled in the ``pydgin-revelation-jit-debug`` build. +For other platforms, you will need to translate Revelation yourself (instructions are below). -Simulating an Epiphany ELF file -------------------------------- - -If you are running Revelation as a Python script, you need to have the `Pydgin module `_ available on your ``PYTHONPATH``. -At present, Pydgin is not available on PyPI, so you have to do this by hand: +To run the simulator, pass it an Epiphany ELF file on the command line: .. code-block:: bash - $ cd $HOME - $ wget https://github.com/cornell-brg/pydgin/archive/master.zip - $ unzip master.zip - $ mv pydgin-master/ pydgin - $ export PYTHONPATH=${PYTHONPATH}:$HOME/pydgin/:. + $ ./pydgin-revelation-jit revelation/test/c/hello.elf + Loading program revelation/test/c/hello.elf on to core 0x808 (32, 08) + Hello, world! + Total ticks simulated = 1,951. + Core 0x808 (32, 08) STATUS: 0x00000005, Instructions executed: 1,951 + $ +In the above example, an ELF file from the Revelation repository was simulated. +To compile your own binaries for the Epiphany platform, you will need the `Adapteva eSDK `_. -You may want to add the last line to your ``~/.bashrc`` or similar. +Command line options +--------------------- -The file `epiphany/sim.py `_ is the entry point to the simulator: +By default, Revelation will be configured to simulate a single-core version of the Epiphany. +Like ``e-sim``, the default core has ID ``0x808`` and lies at row ``32`` and column ``8`` of of the memory map. +You can configure this at the command line: .. code-block:: bash - $ python epiphany/sim.py epiphany/test/c/nothing.elf - NOTE: Using sparse storage - sparse memory size 400 addr mask 3ff block mask fffffc00 - DONE! Status = 0 - Instructions Executed = 176 + $ ./pydgin-revelation-jit -r 1 -c 2 -f 0x808 revelation/test/multicore/manual_message_pass.elf + Loading program revelation/test/multicore/manual_message_pass.elf on to core 0x808 (32, 08) + Loading program revelation/test/multicore/manual_message_pass.elf on to core 0x809 (32, 09) + Received message. + Total ticks simulated = 14,193. + Core 0x808 (32, 08) STATUS: 0x00000005, Instructions executed: 7,894 + Core 0x809 (32, 09) STATUS: 0x00000055, Instructions executed: 6,299 -Full command line options to the simulator are as follows: +The ``-f`` switch selects the first core, and must always be written in hex. -.. code-block:: bash +The full list of command-line options is: - $ python epiphany/sim.py --help +.. code-block:: bash - Pydgin Epiphany Instruction Set Simulator - usage: epiphany/sim.py - the executable to be simulated - arguments to be passed to the simulated executable - the following optional arguments are supported: + $ ./pydgin-revelation-jit --help + Pydgin revelation Instruction Set Simulator + Usage: ./pydgin-revelation-jit [OPTIONS] [ELFFILE] + Simulate the execution of ELFFILE. + + The following OPTIONS are supported: + --help, -h Show this message and exit + --rows, -r ROWS Number of rows (default: 1) + --cols, -c COLS Number of columns (default: 1) + --first-core, -f COREID Coreid, in hex, of North West core (default: 0x808) + --ext-base, -b COREID Base address of external RAM (default: 0x8e000000) + --ext-size, -s SIZE Size of external RAM in MB (default: 32) + --env, -e ENVIRONMENT Either USER or OPERATING (ignored) + --max-insts NUM Halt after executing NUM instructions + --switch N Switch cores every N instructions (ignored) + --time, -t Print approximate timing information + --jit FLAGS Set flags to tune the JIT (see + rpython.rlib.jit.PARAMETER_DOCS) + --debug,-d FLAGS Enable debug flags in a comma-separated form. The + following flags are supported: + trace pc, decoded instructions + rf register file accesses + mem memory accesses + flags update to CPU flags + syscalls system call information + + EXAMPLES: + $ ./pydgin-revelation-jit -r 1 -c 2 -f 0x808 program.elf + $ ./pydgin-revelation-jit -r 1 -c 2 --max-insts 20000 program.elf + $ ./pydgin-revelation-jit --time program.elf + $ ./pydgin-revelation-jit --debug trace,rf,mem,flags program.elf + + +Debugging an Epiphany program with Revelation +--------------------------------------------- + +You can learn more about how Revelation simulates your ELF file with the ``--debug`` options. +These options will write a trace of simulator operations to a file called ``r_trace.out`` in your current working directory. +You can optionally choose to trace instructions, register reads/writes, memory reads/writes, CPU flags and/or system calls. +For example: - --help,-h Show this message and exit - --test Run in testing mode (for running asm tests) - --env,-e = - Set an environment variable to be passed to the - simulated program. Can use multiple --env flags to set - multiple environment variables. - --debug,-d [:] - Enable debug flags in a comma-separated form (e.g. - "--debug syscalls,insts"). If provided, debugs starts - after cycles. The following flags are - supported: - insts cycle-by-cycle instructions - rf register file accesses - mem memory accesses - regdump register dump - syscalls syscall information - bootstrap initial stack and register state +.. code-block:: bash - --max-insts Run until the maximum number of instructions - --jit Set flags to tune the JIT (see - rpython.rlib.jit.PARAMETER_DOCS) + $ ./pydgin-revelation-jit-debug --debug trace,rf,mem,flags revelation/test/c/hello.elf + Trace will be written to: r_trace.out. + Loading program revelation/test/c/hello.elf on to core 0x808 (32, 08) + Hello, world! + Done! Total ticks simulated = 1951 + Core 0x808 (32, 08): STATUS=0x00000005, Instructions executed=1951 + + $ cat r_trace.out + + 0 000080e8 bcond32 0 AN=0 AZ=0 AC=0 AV=0 AVS=0 BN=0 BZ=0 BIS=0 BUS=0 BV=0 BVS=0 + 100 0012660b movimm32 1 :: WR.RF[3 ] = 00000130 + 104 1002600b movtimm32 2 :: RD.RF[3 ] = 00000130 :: WR.RF[3 ] = 00000130 + 108 00000d52 jalr16 3 :: WR.RF[14] = 0000010a :: RD.RF[3 ] = 00000130 + 130 27f2be0b movimm32 4 :: WR.RF[13] = 00007ff0 + 134 3002a00b movtimm32 5 :: RD.RF[13] = 00007ff0 :: WR.RF[13] = 00007ff0 + 138 2002e00b movimm32 6 :: WR.RF[15] = 00000000 + 13c 00020b0b movimm32 7 :: WR.RF[0 ] = 00000058 + 140 1002000b movtimm32 8 :: RD.RF[0 ] = 00000058 :: WR.RF[0 ] = 00000058 + 144 202b0044 ldstrdisp16 9 :: RD.RF[0 ] = 00000058 :: WR.RF[0 ] = 00000000 + 146 0002202b movimm32 10 :: WR.RF[1 ] = 00000001 + 14a 1002200b movtimm32 11 :: RD.RF[1 ] = 00000001 :: WR.RF[1 ] = 00000001 + 14e 111000da and16 12 :: RD.RF[1 ] = 00000001 :: RD.RF[0 ] = 00000000 :: WR.RF[0 ] = 00000000 AN=0 AZ=1 AC=0 AV=0 AVS=0 BN=0 BZ=0 BIS=0 BUS=0 BV=0 BVS=0 + 150 1d0b1110 bcond16 13 AN=0 AZ=1 AC=0 AV=0 AVS=0 BN=0 BZ=0 BIS=0 BUS=0 BV=0 BVS=0 + ... + + +The left-most column represents the program counter, the next column shows the opcode being simulated, next is the Revelation name for the opcode, then how many instructions have been executed so far. +On the right you can see register, memory and flag reads and writes. +The Revelation name for each instruction will not look exactly like the equivalent assembler code (e.g. ``bcond32`` could be a ``blt`` or ``beq``). +Each instruction name will end in ``32`` or ``16``, depending on whether the compiler has produced a 32-bit or 16-bit version of the instruction. + +If you are simulating a multi-core program, then **only** the first (south-west) core is traced. + + +Translating Revelation +---------------------- + +Revelation is written in RPython, a statically typed version of Python. +"Translating" is the process of converting RPython code here into C, and compiling that to a native executable. +To translate the simulator, you need to first clone (or download) a recent version of the `PyPy toolchain `_. +The ``rpython`` directory from PyPy needs to be included in your ``PYTHONPATH`` environment variable. +You will also need a copy of `the Pydgin framework `_, which should also be on your ``PYTHONPATH``. +If you are in any doubt about this, the Revelation `Travis configuration `_ contains a script which translates the simulator. +You can translate versions of Revelation with and without the just-in-time component of the simulator. +The JITed version of the simulator will be faster, especially for long-running programs. -The ``--debug`` flags can be used to give a more detailed trace of a simulation: +To translate *without* a JIT: .. code-block:: bash - $ python epiphany/sim.py --debug insts,rf epiphany/test/c/nothing.elf - NOTE: Using sparse storage - sparse memory size 400 addr mask 3ff block mask fffffc00 - 0 00002ce8 bcond32 0 - 58 0002720b movimm32 1 :: WR.RF[3 ] = 00000090 - 5c 1002600b movtimm32 2 :: RD.RF[3 ] = 00000090 :: WR.RF[3 ] = 00000090 - 60 00000d52 jalr16 3 :: WR.RF[14] = 00000062 :: RD.RF[3 ] = 00000090 - 90 27f2be0b movimm32 4 :: WR.RF[13] = 00007ff0 - 94 3002a00b movtimm32 5 :: RD.RF[13] = 00007ff0 :: WR.RF[13] = 00007ff0 - 98 2002600b movimm32 6 :: WR.RF[11] = 00000000 - 9c 0022190b movimm32 7 :: WR.RF[0 ] = 000002c8 - ... - 8e0005c8 ffe80fe2 trap16 175 :: RD.RF[0 ] = 00000000 :: RD.RF[1 ] = 8e0005c8 :: RD.RF[2 ] = 00000000 - DONE! Status = 0 - Instructions Executed = 176 - - -Compiling Revelation --------------------- - -To compile Revelation to a native executable, you need to first clone (or download) a recent version of the `PyPy toolchain `_. -The ``rpython`` directory from PyPy needs to be included in your ``PYTHONPATH`` environment variable. + $ PATH_TO_PYPY/rpython/bin/rpython -O2 epiphany/sim.py -To compile *without* a JIT: + +To translate the simulator *with* a JIT: .. code-block:: bash - $ PYTHONPATH=. .../pypy/rpython/bin/rpython -Ojit epiphany/sim.py + $ PATH_TO_PYPY/rpython/bin/rpython -Ojit epiphany/sim.py -To compile the simulator *with* a JIT: +To translate the simulator *with* a JIT and debug support, so that you can use the ``--debug`` command-line option: .. code-block:: bash - $ PYTHONPATH=. ../../pypy/rpython/bin/rpython -Ojit epiphany/sim.py + $ PATH_TO_PYPY/rpython/bin/rpython -Ojit epiphany/sim.py --debug +To translate with RPython debug support (e.g. to run the simulator through GDB whilst debugging): -Support -------- +.. code-block:: bash -Revelation is currently under active development, it is not yet able to simulate full, multicore, Epiphany programs. -However, if you do try Revelation, please do report any bugs you find on the project `issue tracker `_. + $ PATH_TO_PYPY/rpython/bin/rpython -Ojit --lldebug epiphany/sim.py --debug .. toctree:: diff --git a/requirements.txt b/requirements.txt index 7b81a2c..b869bad 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,3 +6,6 @@ pytest-capturelog==0.7 pytest-cov==2.2.1 pytest-xdist==1.14 requests==2.9.1 +Sphinx==1.4.5 +sphinx-rtd-theme==0.1.9 +