[
  {
    "path": ".gitignore",
    "content": "# CMake\nbuild/\n\n# Object files\n*.o\n*.ko\n*.obj\n*.elf\n\n# Libraries\n*.lib\n*.a\n\n# Shared objects (inc. Windows DLLs)\n*.dll\n*.so\n*.so.*\n*.dylib\n\n# Executables\n*.exe\n*.out\n*.app\n*.i*86\n*.x86_64\n*.hex\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "# This file is part of the Team 28 Project\n# Licensing information can be found in the LICENSE file\n# (C) 2014 The Team 28 Authors. All rights reserved.\ncmake_minimum_required(VERSION 2.8)\nproject(PiFox ASM)\n\n# Find the python interpreter\nset( PythonInterp_FIND_VERSION 2 )\nfind_package( PythonInterp REQUIRED )\n\nset(SOURCES\n  kernel.s\n  math.s\n  mbox.s\n  gfx.s\n  ports.s\n  input.s\n  printf.s\n  game.s\n  bullets.s\n  objects.s\n  pillars.s\n  player.s\n  sound.s\n  rockets.s\n  enemies.s\n  assets/rock.s\n  assets/ship.s\n  assets/enemy.s\n  assets/rocket.s\n)\n\nSET(IMAGES\n  bullet.png\n  rocket.png\n  wrench.png\n  flare.png\n  mountains.png\n  tristan.png\n  monkey.png\n  pifox.png\n)\n\nset( CMAKE_EXECUTABLE_SUFFIX .elf )\nset( CMAKE_ASM_FLAGS \"-march=armv6zk -mfpu=vfp -g -Wa,--fatal-warnings -nostartfiles -nostdlib\" )\nset( CMAKE_EXE_LINKER_FLAGS \"-Wl,-T,${PROJECT_SOURCE_DIR}/kernel.ld\" )\ninclude_directories( ${CMAKE_CURRENT_SOURCE_DIR} )\n\n# Compile all images\nforeach(file ${IMAGES})\n  get_filename_component(file_path ${file} PATH)\n  get_filename_component(file_name ${file} NAME_WE)\n\n  set(file \"${file_name}\")\n  set(object \"${CMAKE_BINARY_DIR}/assets${file_path}/${file_name}.bin\")\n  set(source \"${CMAKE_SOURCE_DIR}/assets${file_path}/${file_name}.png\")\n  get_filename_component(dir ${object} PATH)\n\n  file(MAKE_DIRECTORY ${dir})\n  add_custom_command(\n    OUTPUT ${object}\n    DEPENDS ${source}\n    COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/imager.py ${source} --out=${object}\n  )\n\n  list(APPEND IMAGES_BIN ${object})\nendforeach(file)\n\n# Build a binary file out of the elf\nadd_executable( kernel ${SOURCES} ${IMAGES_BIN} )\n\n# Without an operating system, there is no executable loader, so we just need\n# the raw machine code (or binary) from the ELF output of the toolchain.\n# objcopy can do that for us.\nadd_custom_command(\n    TARGET kernel POST_BUILD\n    COMMAND ${CMAKE_OBJCOPY} ${CMAKE_BINARY_DIR}/kernel.elf -O binary ./kernel.img\n    WORKING_DIRECTORY ${CMAKE_BINARY_DIR}\n    COMMENT \"Convert the ELF output file to a binary image\" )\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2014, Licker Nandor, Ilija Radosavovic, David Avedissian, Nic Prettejohn\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the {organization} nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "README.md",
    "content": "PiFox\n=====\n\nVideo of the game in action: https://www.youtube.com/watch?v=-5n9IxSQH1M\n\nDeveloped as an extension to a first year group project at Imperial College London.\n\nBare Metal 3D rail shooter game\n\n* 5800 lines of ARM assembly (ARMv6 + VFP1)\n* Software rasterizer\n* 3D objects\n* 2D billboards\n* Sound using DMA\n* NES controller input\n* Math & utility library\n* GitHub: https://github.com/ICTeam28/PiFox\n* Emulator: https://github.com/ICTeam28/PiEmu\n\nDependencies\n-----\n\nUsing your favourite Linux package manager, install:\n\n* arm-none-eabi-binutils\n* cmake\n\nBuild\n-----\n\nThe project uses CMake and requires an ARM assembler supporting\nGNU as syntax. \n\n    mkdir build\n    cd build\n    cmake ..\n    make\n    \nEmulation\n-----\n\nPiEmu (https://github.com/ICTeam28/PiEmu) can run the game without sound. Assuming PiFox and PiEmu have been cloned in the same directory and both are built, PiEmu must be invoked with the following command inside PiFox's build directory:\n\n    ../../PiEmu/build/piemu --graphics --quiet --memory=256M --addr=65536 --nes kernel.img \n\nA qemu branch can be used to emulate the game at a higher framerate, but sound must be disabled. (https://github.com/Torlus/qemu/tree/rpi)\n\nconfig.txt\n----------\n\nIn order to be compatible with qemu, the kernel must be loaded at address 0x10000.\n\n    disable_overscan=1\n    disable_pvt=1\n    force_turbo=1\n    gpu_mem_256=160\n    gpu_mem_512=316\n    cma_lwm=16\n    cma_hwm=32\n    kernel_address=65536\n\nWiring the controller\n---------------------\n\n|    NES   |  Raspberry Pi  |\n|:--------:|:--------------:|\n| GND      | Ground         |\n| VCC      | 3v3            |\n| CUP      | GPIO 10        |\n| OUT 0    | GPIO 11        |\n| D1       | GPIO 4         |\n\n![NES Pinout](https://raw.github.com/ICTeam28/PiFox/master/assets/nes-controller-pinout.png)\n\n![Raspberry PI Pinout](https://raw.github.com/ICTeam28/PiFox/master/assets/raspbery-pi-pinout.png)\n\nAuthors\n-------\nNandor Licker\n- Email: nandor.licker13[at]imperial.ac.uk\n- Github [@nandor](https://github.com/nandor)\n\nIlija Radosavovic\n- Email: ilija.radosavovic13[at]imperial.ac.uk\n- Github [@ir413](https://github.com/ir413)\n\nDavid Avedissian\n- Email: david.avedissian13[at]imperial.ac.uk\n- Github [@davedissian](https://github.com/davedissian)\n- Twitter [@davedissian](https://twitter.com/davedissian)\n\nNic Prettejohn\n- Email: nicolas.prettejohn13[at]imperial.ac.uk\n- Github [@nkp](https://github.com/nkp)\n- Twitter [@thisisnkp](https://twitter.com/thisisnkp)\n\nSpecial thanks\n--------------\n\n* https://github.com/dwelch67/raspberrypi\n* https://github.com/PeterLemon/RaspberryPi\n\n\nSpecial thanks to chpatrick (Patrick Chilton) for his advice.\n"
  },
  {
    "path": "assets/enemy.s",
    "content": "@ This file is part of the Team 28 Project\n@ Licensing information can be found in the LICENSE file\n@ (C) 2014 The Team 28 Authors. All rights reserved.\n.global enemy_vtx\n.global enemy_idx\n\n@ ------------------------------------------------------------------------------\n@ Enemy model\n@ X Y Z 1.0\n@ ------------------------------------------------------------------------------\n.align 2\nenemy_vtx:\n  .float  0.00,    0.75,    0.0,  1.0 @ 0\n  .float -0.75,    0.00,    0.0,  1.0 @ 1\n  .float  0.00,   -0.75,    0.0,  1.0 @ 2\n  .float  0.75,    0.00,    0.0,  1.0 @ 3\n\n  .float -0.90,    0.90,    0.0,  1.0 @ 4\n  .float -0.90,   -0.90,    0.0,  1.0 @ 5\n  .float  0.90,   -0.90,    0.0,  1.0 @ 6\n  .float  0.90,    0.90,    0.0,  1.0 @ 7\n\n  .float  0.00,    0.00,    2.0,  1.0 @ 8\n\n  .float -0.60,    0.60,    1.0,  1.0 @ 9\n  .float -0.60,   -0.60,    1.0,  1.0 @ 10\n  .float  0.60,   -0.60,    1.0,  1.0 @ 11\n  .float  0.60,    0.60,    1.0,  1.0 @ 12\n\nenemy_idx:\n  .long 0, 1, 8\n  .float 1.0, 0.2, 0.2\n  .long 1, 2, 8\n  .float 1.0, 0.2, 0.2\n  .long 2, 3, 8\n  .float 1.0, 0.2, 0.2\n  .long 3, 0, 8\n  .float 1.0, 0.2, 0.2\n\n  .long 1, 0, 9\n  .float 1.0, 0.7, 0.2\n  .long 0, 4, 9\n  .float 1.0, 0.7, 0.2\n  .long 4, 1, 9\n  .float 1.0, 0.7, 0.2\n\n  .long 2, 1, 10\n  .float 1.0, 0.7, 0.2\n  .long 1, 5, 10\n  .float 1.0, 0.7, 0.2\n  .long 5, 2, 10\n  .float 1.0, 0.7, 0.2\n\n  .long 3, 2, 11\n  .float 1.0, 0.7, 0.2\n  .long 2, 6, 11\n  .float 1.0, 0.7, 0.2\n  .long 6, 3, 11\n  .float 1.0, 0.7, 0.2\n\n  .long 0, 3, 12\n  .float 1.0, 0.7, 0.2\n  .long 7, 0, 12\n  .float 1.0, 0.7, 0.2\n  .long 3, 7, 12\n  .float 1.0, 0.7, 0.2\n\n"
  },
  {
    "path": "assets/pillar.s",
    "content": "@ This file is part of the Team 28 Project\n@ Licensing information can be found in the LICENSE file\n@ (C) 2014 The Team 28 Authors. All rights reserved.\n.global pillar_vtx\n.global pillar_idx\n\n@ ------------------------------------------------------------------------------\n@ Cube model\n@ X Y Z 1.0\n@ ------------------------------------------------------------------------------\n.align 2\npillar_vtx:\n  @ Front\n  .float -0.5, -0.5,  0.5,  1.0\n  .float  0.5, -0.5,  0.5,  1.0\n  .float  0.5,  0.5,  0.5,  1.0\n  .float -0.5,  0.5,  0.5,  1.0\n  @ Back\n  .float -0.5, -0.5, -0.5,  1.0\n  .float  0.5, -0.5, -0.5,  1.0\n  .float  0.5,  0.5, -0.5,  1.0\n  .float -0.5,  0.5, -0.5,  1.0\n  @ Top\n  .float  0.5,  0.5, -0.5,  1.0\n  .float -0.5,  0.5, -0.5,  1.0\n  .float -0.5,  0.5,  0.5,  1.0\n  .float  0.5,  0.5,  0.5,  1.0\n  @ Left\n  .float  0.5, -0.5, -0.5,  1.0\n  .float  0.5,  0.5, -0.5,  1.0\n  .float  0.5,  0.5,  0.5,  1.0\n  .float  0.5, -0.5,  0.5,  1.0\n  @ Right\n  .float -0.5,  0.5, -0.5,  1.0\n  .float -0.5, -0.5, -0.5,  1.0\n  .float -0.5, -0.5,  0.5,  1.0\n  .float -0.5,  0.5,  0.5,  1.0\n\npillar_idx:\n  .long 0, 1, 3\n  .float 0.5, 0.5, 0.5\n  .long 3, 1, 2\n  .float 0.5, 0.5, 0.5\n\n  .long 4, 7, 5\n  .float 0.5, 0.5, 0.5\n  .long 7, 6, 5\n  .float 0.5, 0.5, 0.5\n\n  .long 8, 9, 11\n  .float 0.5, 0.5, 0.5\n  .long 11, 9, 10\n  .float 0.5, 0.5, 0.5\n\n  .long 12, 13, 15\n  .float 0.5, 0.5, 0.5\n  .long 15, 13, 14\n  .float 0.5, 0.5, 0.5\n\n  .long 16, 17, 19\n  .float 0.5, 0.5, 0.5\n  .long 19, 17, 18\n  .float 0.5, 0.5, 0.5\n\n"
  },
  {
    "path": "assets/rock.s",
    "content": "@ This file is part of the Team 28 Project\n@ Licensing information can be found in the LICENSE file\n@ (C) 2014 The Team 28 Authors. All rights reserved.\n.global rock_vtx\n.global rock_idx\n\n@ ------------------------------------------------------------------------------\n@ Rock model\n@ X Y Z 1.0\n@ ------------------------------------------------------------------------------\n.align 2\nrock_vtx:\n  .float  0.0,    0.75,    1.2135,  1.0\n  .float  0.0,    0.75,   -1.2135,  1.0\n  .float  0.0,   -0.75,    1.2135,  1.0\n  .float  0.0,   -0.75,   -1.2135,  1.0\n  .float  0.75,    1.2135,  0.0,    1.0\n  .float  0.75,   -1.2135,  0.0,    1.0\n  .float -0.75,    1.2135,  0.0,    1.0\n  .float -0.75,   -1.2135,  0.0,    1.0\n  .float  1.2135,  0.0,    0.75,    1.0\n  .float  1.2135,  0.0,   -0.75,    1.0\n  .float -1.2135,  0.0,    0.75,    1.0\n  .float -1.2135,  0.0,   -0.75,    1.0\n\nrock_idx:\n  .long 0, 2, 8\n  .float 0.9, 0.2, 0.2\n  .long 10, 2, 0\n  .float 0.9, 0.2, 0.2\n  .long 0, 4, 6\n  .float 0.9, 0.2, 0.2\n  .long 8, 4, 0\n  .float 0.9, 0.2, 0.2\n  .long 0, 6, 10\n  .float 0.9, 0.2, 0.2\n  .long 1, 9, 3\n  .float 0.9, 0.2, 0.2\n  .long 11, 1, 3\n  .float 0.9, 0.2, 0.2\n  .long 4, 1, 6\n  .float 0.9, 0.2, 0.2\n  .long 9, 1, 4\n  .float 0.9, 0.2, 0.2\n  .long 6, 1, 11\n  .float 0.9, 0.2, 0.2\n  .long 2, 7, 5\n  .float 0.9, 0.2, 0.2\n  .long 5, 8, 2\n  .float 0.9, 0.2, 0.2\n  .long 10, 7, 2\n  .float 0.9, 0.2, 0.2\n  .long 7, 3, 5\n  .float 0.9, 0.2, 0.2\n  .long 3, 9, 5\n  .float 0.9, 0.2, 0.2\n  .long 11, 3, 7\n  .float 0.9, 0.2, 0.2\n  .long 4, 8, 9\n  .float 0.9, 0.2, 0.2\n  .long 5, 9, 8\n  .float 0.9, 0.2, 0.2\n  .long 11, 10, 6\n  .float 0.9, 0.2, 0.2\n  .long 10, 11, 7\n  .float 0.9, 0.2, 0.2\n\n  .long 0, 2, 8\n  .float 0.7, 0.5, 0.5\n  .long 10, 2, 0\n  .float 0.7, 0.5, 0.5\n  .long 0, 4, 6\n  .float 0.7, 0.5, 0.5\n  .long 8, 4, 0\n  .float 0.7, 0.5, 0.5\n  .long 0, 6, 10\n  .float 0.7, 0.5, 0.5\n  .long 1, 9, 3\n  .float 0.7, 0.5, 0.5\n  .long 11, 1, 3\n  .float 0.7, 0.5, 0.5\n  .long 4, 1, 6\n  .float 0.7, 0.5, 0.5\n  .long 9, 1, 4\n  .float 0.7, 0.5, 0.5\n  .long 6, 1, 11\n  .float 0.7, 0.5, 0.5\n  .long 2, 7, 5\n  .float 0.7, 0.5, 0.5\n  .long 5, 8, 2\n  .float 0.7, 0.5, 0.5\n  .long 10, 7, 2\n  .float 0.7, 0.5, 0.5\n  .long 7, 3, 5\n  .float 0.7, 0.5, 0.5\n  .long 3, 9, 5\n  .float 0.7, 0.5, 0.5\n  .long 11, 3, 7\n  .float 0.7, 0.5, 0.5\n  .long 4, 8, 9\n  .float 0.7, 0.5, 0.5\n  .long 5, 9, 8\n  .float 0.7, 0.5, 0.5\n  .long 11, 10, 6\n  .float 0.7, 0.5, 0.5\n  .long 10, 11, 7\n  .float 0.7, 0.5, 0.5\n\n  .long 0, 2, 8\n  .float 0.5, 0.5, 0.5\n  .long 10, 2, 0\n  .float 0.5, 0.5, 0.5\n  .long 0, 4, 6\n  .float 0.5, 0.5, 0.5\n  .long 8, 4, 0\n  .float 0.5, 0.5, 0.5\n  .long 0, 6, 10\n  .float 0.5, 0.5, 0.5\n  .long 1, 9, 3\n  .float 0.5, 0.5, 0.5\n  .long 11, 1, 3\n  .float 0.5, 0.5, 0.5\n  .long 4, 1, 6\n  .float 0.5, 0.5, 0.5\n  .long 9, 1, 4\n  .float 0.5, 0.5, 0.5\n  .long 6, 1, 11\n  .float 0.5, 0.5, 0.5\n  .long 2, 7, 5\n  .float 0.5, 0.5, 0.5\n  .long 5, 8, 2\n  .float 0.5, 0.5, 0.5\n  .long 10, 7, 2\n  .float 0.5, 0.5, 0.5\n  .long 7, 3, 5\n  .float 0.5, 0.5, 0.5\n  .long 3, 9, 5\n  .float 0.5, 0.5, 0.5\n  .long 11, 3, 7\n  .float 0.5, 0.5, 0.5\n  .long 4, 8, 9\n  .float 0.5, 0.5, 0.5\n  .long 5, 9, 8\n  .float 0.5, 0.5, 0.5\n  .long 11, 10, 6\n  .float 0.5, 0.5, 0.5\n  .long 10, 11, 7\n  .float 0.5, 0.5, 0.5\n"
  },
  {
    "path": "assets/rocket.s",
    "content": "@ This file is part of the Team 28 Project\n@ Licensing information can be found in the LICENSE file\n@ (C) 2014 The Team 28 Authors. All rights reserved.\n.global rocket_vtx\n.global rocket_idx\n\n@-------------------------------------------------------------------------------\n@ Rocket model\n@ X Y Z 1.0\n@-------------------------------------------------------------------------------\n.align 2\nrocket_vtx:\n  @ base\n  .float  0.2,   0.0,     0.5,  1.0  @b0\n  .float  0.06,  0.19,    0.5,  1.0  @b1\n  .float -0.16,  0.1174,  0.5,  1.0  @b2\n  .float -0.16, -0.1174,  0.5,  1.0  @b3\n  .float  0.06, -0.19,    0.5,  1.0  @b4\n  .float  0.0,   0.0,     0.5,  1.0  @b5\n\n  @ top\n  .float  0.2,   0.0,    -0.5,  1.0  @t0\n  .float  0.06,  0.19,   -0.5,  1.0  @t1\n  .float -0.16,  0.1174, -0.5,  1.0  @t2\n  .float -0.16, -0.1174, -0.5,  1.0  @t3\n  .float  0.06, -0.19,   -0.5,  1.0  @t4\n  .float  0.0,   0.0,    -1.5,  1.0  @t5\n\n  @ mid\n  .float  0.2,   0.0,     0.0,  1.0  @m0\n  .float  0.06,  0.19,    0.0,  1.0  @m1\n  .float -0.16,  0.1174,  0.0,  1.0  @m2\n  .float -0.16, -0.1174,  0.0,  1.0  @m3\n  .float  0.06, -0.19,    0.0,  1.0  @m4\n\n  @ wings\n  .float  0.4,   0.0,     0.5,  1.0  @w0\n  .float  0.12,  0.38,    0.5,  1.0  @w1\n  .float -0.32,  0.2348,  0.5,  1.0  @w2\n  .float -0.32, -0.2348,  0.5,  1.0  @w3\n  .float  0.12, -0.38,    0.5,  1.0  @w4\n\nrocket_idx:\n  @ base\n  .long 0, 5, 4\n  .float 1.0, 0.4, 0.0\n  .long 3, 4, 5\n  .float 1.0, 0.4, 0.0\n  .long 2, 3, 5\n  .float 1.0, 0.4, 0.0\n  .long 1, 2, 5\n  .float 1.0, 0.4, 0.0\n  .long 0, 1, 5\n  .float 1.0, 0.4, 0.0\n\n  @ sides\n  .long 0, 4, 10\n  .float 1.0, 0.0, 0.0\n  .long 0, 10, 6\n  .float 1.0, 0.0, 0.0\n\n  .long 4, 3, 9  \n  .float 1.0, 0.0, 0.0\n  .long 4, 9, 10  \n  .float 1.0, 0.0, 0.0\n\n  .long 3, 2, 8  \n  .float 1.0, 0.0, 0.0\n  .long 3, 8, 9  \n  .float 1.0, 0.0, 0.0\n\n  .long 2, 1, 7  \n  .float 1.0, 0.0, 0.0\n  .long 2, 7, 8  \n  .float 1.0, 0.0, 0.0\n\n  .long 1, 0, 6  \n  .float 1.0, 0.0, 0.0\n  .long 1, 6, 7  \n  .float 1.0, 0.0, 0.0\n\n  @ top\n  .long 6, 10, 11\n  .float 1.0, 1.0, 1.0\n  .long 10, 9, 11\n  .float 1.0, 1.0, 1.0  \n  .long 9, 8, 11\n  .float 1.0, 1.0, 1.0  \n  .long 8, 7, 11\n  .float 1.0, 1.0, 1.0  \n  .long 7, 6, 11\n  .float 1.0, 1.0, 1.0\n\n  @ wings\n  .long 0, 17, 12\n  .float 1.0, 1.0, 1.0\n  .long 1, 18, 13\n  .float 1.0, 1.0, 1.0\n  .long 2, 19, 14\n  .float 1.0, 1.0, 1.0\n  .long 3, 20, 15\n  .float 1.0, 1.0, 1.0\n  .long 4, 21, 16\n  .float 1.0, 1.0, 1.0\n\n  .long 17, 0, 12\n  .float 1.0, 1.0, 1.0\n  .long 18, 1, 13\n  .float 1.0, 1.0, 1.0\n  .long 19, 2, 14\n  .float 1.0, 1.0, 1.0\n  .long 20, 3, 15\n  .float 1.0, 1.0, 1.0\n  .long 21, 4, 16\n  .float 1.0, 1.0, 1.0\n"
  },
  {
    "path": "assets/ship.s",
    "content": "@ This file is part of the Team 28 Project\n@ Licensing information can be found in the LICENSE file\n@ (C) 2014 The Team 28 Authors. All rights reserved.\n.global ship_vtx\n.global ship_idx\n\n@ ------------------------------------------------------------------------------\n@ Cube model\n@ X Y Z 1.0\n@ ------------------------------------------------------------------------------\n.align 2\nship_vtx:\n  @ Center - backside\n  .float -0.4,  0.0,  0.0,  1.0\n  .float  0.0,  0.2,  0.0,  1.0\n  .float  0.4,  0.0,  0.0,  1.0\n  .float -0.0, -0.1,  0.0,  1.0\n  @ Left - backside\n  .float -0.8,  0.0,  0.0,  1.0\n  .float -0.6,  0.1,  0.0,  1.0\n  .float -0.6, -0.2,  0.0,  1.0\n  @ Right - backside\n  .float  0.6,  0.1,  0.0,  1.0\n  .float  0.8,  0.0,  0.0,  1.0\n  .float  0.6, -0.2,  0.0,  1.0\n  @ Left tip\n  .float -0.6,  0.0, -2.0, 1.0\n  @ Center tip\n  .float  0.0,  0.0, -3.0, 1.0\n  @ Right tip\n  .float  0.6,  0.0, -2.0, 1.0\n  @ Engine\n  .float  0.3,  0.0, -1.0,  1.0\n  .float  0.7,  0.5,  0.0,  1.0\n  .float -0.3,  0.0, -1.0,  1.0\n  .float -0.7,  0.5,  0.0,  1.0\n\nship_idx:\n  .long 1, 0, 2\n  .float 0.0, 0.0, 1.0\n  .long 0, 3, 2\n  .float 0.0, 0.0, 1.0\n\n  .long 5, 4, 0\n  .float 1.0, 1.0, 1.0\n  .long 0, 4, 6\n  .float 1.0, 1.0, 1.0\n\n  .long 7, 2, 8\n  .float 1.0, 1.0, 1.0\n  .long 8, 2, 9\n  .float 1.0, 1.0, 1.0\n\n  .long 10, 4, 5\n  .float 1.0, 0.0, 0.0\n  .long 10, 6, 4\n  .float 1.0, 0.0, 0.0\n  .long 10, 5, 0\n  .float 1.0, 0.0, 0.0\n  .long 10, 0, 6\n  .float 1.0, 0.0, 0.0\n\n  .long 11, 0, 1\n  .float 1.0, 1.0, 1.0\n  .long 11, 3, 0\n  .float 1.0, 1.0, 1.0\n  .long 11, 1, 2\n  .float 1.0, 1.0, 1.0\n  .long 11, 2, 3\n  .float 1.0, 1.0, 1.0\n\n  .long 12, 2, 7\n  .float 1.0, 0.0, 0.0\n  .long 12, 9, 2\n  .float 1.0, 0.0, 0.0\n  .long 12, 7, 8\n  .float 1.0, 0.0, 0.0\n  .long 12, 8, 9\n  .float 1.0, 0.0, 0.0\n\n  .long  14, 13, 2\n  .float 0.0, 0.0, 20.0\n  .long  14, 2, 13\n  .float 0.0, 0.0, 20.0\n  .long  16, 0, 15\n  .float 0.0, 0.0, 20.0\n  .long  16, 15, 0\n  .float 0.0, 0.0, 20.0\n"
  },
  {
    "path": "bullets.s",
    "content": "@ This file is part of the Team 28 Project\n@ Licensing information can be found in the LICENSE file\n@ (C) 2014 The Team 28 Authors. All rights reserved.\n.global draw_bullets\n.global collide_bullets\n.global reset_bullets\n\n.include \"ports.s\"\n\n.section .data\n@ ------------------------------------------------------------------------------\n@ List of bullets\n@ ------------------------------------------------------------------------------\n.equ          BULLET_COUNT, 20\nbullet_last:  .long 0\nbullet_list:\n  .rept BULLET_COUNT\n    .float 0.0, 0.0, 0.0, 1.0\n    .long  0\n  .endr\n\n.section .text\n@ ------------------------------------------------------------------------------\n@ Renders all bullets\n@ ------------------------------------------------------------------------------\ndraw_bullets:\n  stmfd       sp!, {lr}\n\n  @ Reset model matrix\n  ldr         r0, =mtx_id\n  vldm.f32    r0, {s0 - s15}\n  ldr         r0, =mtx_model\n  vstm.f32    r0, {s0 - s15}\n\n  @ Read system timer\n  ldr         r7, =STIMER_CLO\n  ldr         r7, [r7]\n\n  @ Loop through all bullets\n  ldr         r12, =BULLET_COUNT\n  ldr         r11, =bullet_list\n  ldr         r10, =bullet_last\n  ldr         r6, [r10]\n1:\n  vldmia.f32  r11!, {s3 - s6}\n  ldmia       r11!, {r9}\n\n  ldr         r0, =0x40400000\n  vmov.f32    s2, r0\n  vsub.f32    s5, s5, s2\n\n  tst         r9, r9\n  bne         2f\n\n  @ Check if sprite can be spawned\n  sub         r8, r7, r6\n  cmp         r8, #0x50000\n  blt         2f\n\n  ldr         r5, =button_pressed\n  ldr         r5, [r5]\n  tst         r5, #0x01\n  beq         2f\n\n  @ Play shot sound\n  bl          snd_play_bullet\n\n  @ Spawn a new sprite\n  add         r9, r7, #0x100000\n  mov         r6, r7\n  str         r7, [r10]\n\n  ldr         r0, =player_pos\n  vldm.f32    r0, {s3 - s6}\n  ldr         r1, =0xc0000000\n  vmov.f32    s7, r1\n  vsub.f32    s4, s4, s7\n  ldr         r1, =0xc1200000\n  vmov.f32    s5, r1\n  b           3f\n2:\n  cmp         r9, r7\n  movlt       r9, #0\n3:\n  stmdb       r11!, {r9}\n  vstmdb      r11!, {s3 - s6}\n\n  @ Check if bullet is active\n  tst         r9, r9\n  blne        draw_bullet\n\n2:\n  add         r11, r11, #20\n  subs        r12, r12, #1\n  bne         1b\n\n  ldmfd       sp!, {pc}\n\n@ ------------------------------------------------------------------------------\n@ Renders a single bullet\n@ ------------------------------------------------------------------------------\ndraw_bullet:\n  stmfd       sp!, {lr}\n\n  ldr         r0, =mtx_model\n  vmov.f32    s0, s3\n  vneg.f32    s1, s4\n  vmov.f32    s2, s5\n  bl          mat4_translate\n\n  ldr         r0, =mtx_vp\n  ldr         r1, =mtx_model\n  ldr         r2, =mtx_mvp\n  bl          mat4_mul_mat4\n\n  @ Draw a sprite\n  ldr         r0, =bullet\n  ldr         r1, =mtx_mvp\n  ldr         r2, =mtx_view\n  ldr         r3, =0x3e800000\n  vmov.f32    s0, r3\n  vmov.f32    s1, r3\n  bl          gfx_draw_sprite\n\n  ldmfd       sp!, {pc}\n\n@ ------------------------------------------------------------------------------\n@ Checks whether the bullet collided with something.\n@ In case of a collision, the bullet is destroyed\n@ Arguments:\n@   s0 - x\n@   s1 - y\n@   s2 - z\n@   s31 - radius\n@ Returns:\n@   r0 - 0 if collision happened\n@ Clobbers:\n@   none\n@ ------------------------------------------------------------------------------\ncollide_bullets:\n  stmfd       sp!, {r1 - r12, lr}\n  mov         r0, #1\n\n  ldr         r12, =BULLET_COUNT\n  ldr         r11, =bullet_list\n1:\n  vldmia.f32  r11!, {s27 - s30}\n  ldmia       r11!, {r9}\n\n  tst         r9, r9\n  beq         2f\n\n  vsub.f32    s26, s0, s27\n  vabs.f32    s26, s26\n  vcmp.f32    s26, s31\n  fmstat\n  bgt         2f            @ x\n\n  vsub.f32    s26, s1, s28\n  vabs.f32    s26, s26\n  vcmp.f32    s26, s31\n  fmstat\n  bgt         2f            @ y\n\n  vsub.f32    s26, s2, s29\n  vabs.f32    s26, s26\n  vcmp.f32    s26, s31\n  fmstat\n  bgt         2f            @ z\n\n  mov         r0, #0\n  str         r0, [r11, #-4]\n  b           3f\n2:\n  subs        r12, r12, #1\n  bne         1b\n3:\n\n  ldmfd       sp!, {r1 - r12, pc}\n\n@-------------------------------------------------------------------------------\n@ Resets bullets\n@-------------------------------------------------------------------------------\nreset_bullets:\n  stmfd       sp!, {r0 - r3, lr}\n  vstmdb.f32  sp!, {s0 - s4}\n\n  ldr         r3, =bullet_last\n  mov         r0, #0\n  str         r0, [r3]\n\n  ldr         r3, =BULLET_COUNT\n  ldr         r2, =bullet_list\n  ldr         r1, =0x3F800000      @ 1.0\n\n1:\n  vldm.f32    r2, {s0 -s4}\n\n  vmov.f32    s0, r0\n  vmov.f32    s1, r0\n  vmov.f32    s2, r0\n  vmov.f32    s3, r1\n  vmov.f32    s4, r0\n\n  vstm.f32    r2!, {s0 - s4}\n\n  subs        r3, #1\n  bne         1b\n\n  vldm.f32    sp!, {s0 - s4}\n  ldmfd       sp!, {r0 - r3, pc}\n"
  },
  {
    "path": "enemies.s",
    "content": "@ This file is part of the Team 28 Project\n@ Licensing information can be found in the LICENSE file\n@ (C) 2014 The Team 28 Authors. All rights reserved.\n.global setup_enemies\n.global draw_enemies\n.global reset_enemies\n.global reset_flares\n.global enemy_count\n.global enemies\n.global ENEMY_COUNT\n\n.section .data\n@ ------------------------------------------------------------------------------\n@ List of enemies\n@ ------------------------------------------------------------------------------\n.equ ENEMY_COUNT,    5\n.equ FLARE_COUNT,    30\n\nenemy_count:    .long 0\nenemy_counter:  .long 0\nenemy_timer:    .long 0\nenemies:\n  .rept ENEMY_COUNT\n    .float 0.0, 0.0, 0.0      @ x, y, z\n    .float 0.0                @ s3 - target z\n    .float 0.0                @ s4 - rot\n    .float 0.0                @ s5 - move dir\n    .long  0                  @ s6 - lives\n    .long  0                  @ s7 - bullet timer\n  .endr\n\nflares:\n  .rept FLARE_COUNT\n    .float 0.0, 0.0, -20.0    @ x, y, z\n    .float 0.0, 0.0,   0.0    @ dx, dy, dz\n    .long 0                   @ s6 - alive\n  .endr\n\n.section .text\n@ ------------------------------------------------------------------------------\n@ Resets counters\n@ ------------------------------------------------------------------------------\nsetup_enemies:\n  ldr         r0, =enemy_count\n  mov         r1, #0\n  str         r1, [r0]\n\n  ldr         r0, =enemy_counter\n  mov         r1, #0\n  str         r1, [r0]\n\n  ldr         r0, =enemy_timer\n  mov         r1, #1000\n  str         r1, [r0]\n\n  mov         pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Renders all enemies\n@ ------------------------------------------------------------------------------\ndraw_enemies:\n  stmfd       sp!, {lr}\n\n  ldr         r0, =enemy_count\n  ldr         r0, [r0]\n  tst         r0, r0\n  bne         2f\n\n  @ Test if enemies can be spawned\n  ldr         r0, =enemy_timer\n  ldr         r1, [r0]\n  subs        r1, r1, #1\n  moveq       r1, #1000\n  str         r1, [r0]\n  ldmnefd     sp!, {pc}\n\n  @ Pop-up the monkey\n  ldr         r0, =monkey_timer\n  mov         r1, #120\n  str         r1, [r0]\n\n  @ Play cant let you do that\n  bl          snd_play_cantlet\n\n  @ Increment number of enemies, clamp to 5\n  ldr         r0, =enemy_counter\n  ldr         r11, [r0]\n  add         r11, r11, #1\n  cmp         r11, #5\n  movgt       r11, #5\n  str         r11, [r0]\n  ldr         r0, =enemy_count\n  str         r11, [r0]\n\n  @ Initialise them\n  ldr         r12, =enemies\n  mov         r10, #0\n1:\n  bl          spawn_enemy\n  vstm.f32    r12!, {s0 - s7}\n  subs        r11, r11, #1\n  bne         1b\n\n2:\n  ldr         r12, =enemies\n  ldr         r11, =enemy_count\n  ldr         r11, [r11]\n  mov         r10, #0\n3:\n  @ Update & draw enemies\n  vldm.f32    r12, {s0 - s7}\n  vmov.f32    r0, s6\n  tst         r0, r0\n  addeq       r12, r12, #32\n  beq         4f\n  bl          update_enemy\n  vstm.f32    r12!, {s0 - s7}\n  vmov.f32    r0, s6\n  tst         r0, r0\n  blne        draw_enemy\n4:\n  subs        r11, r11, #1\n  bne         3b\n\n  tst         r10, r10\n  ldr         r11, =enemy_count\n  streq       r10, [r11]\n\n  @ Reset model matrix\n  ldr         r0, =mtx_id\n  vldm.f32    r0, {s0 - s15}\n  ldr         r0, =mtx_model\n  vstm.f32    r0, {s0 - s15}\n\n  @ Draw flares shot by enemies\n  ldr         r11, =FLARE_COUNT\n  ldr         r12, =flares\n1:\n  vldm.f32    r12, {s0 - s6}\n  vmov.f32    r0, s6\n  tst         r0, r0\n  addeq       r12, r12, #28\n  beq         2f\n  bl          update_flare\n  vstm.f32    r12!, {s0 - s6}\n  bl          draw_flare\n2:\n  subs        r11, r11, #1\n  bne         1b\n\n  ldmfd       sp!, {pc}\n\n@ ------------------------------------------------------------------------------\n@ Updates an enemy\n@ Arguments:\n@\n@ Returns:\n@\n@ Clobbers:\n@\n@ ------------------------------------------------------------------------------\nupdate_enemy:\n  stmfd       sp!, {lr}\n\n  @ Move down z axis up to target z\n  ldr         r0, =player_speed\n  vldr.f32    s8, [r0]\n  vadd.f32    s2, s2, s8\n  ldr         r0, =0x3f800000\n  vmov.f32    s9, r0\n  vadd.f32    s2, s2, s9\n  vcmp.f32    s2, s3\n  fmstat\n  vmovgt.f32  s2, s3\n\n  @ Lateral movement\n  vadd.f32    s0, s0, s5\n  ldr         r0, =0xc1080000\n  vmov.f32    s8, r0\n  vcmp.f32    s0, s8\n  fmstat\n  vmovlt.f32  s0, s8\n  vneglt.f32  s5, s5\n  vneg.f32    s8, s8\n  vcmp.f32    s0, s8\n  fmstat\n  vmovgt.f32  s0, s8\n  vneggt.f32  s5, s5\n\n  @ Rotation\n  ldr         r0, =0x3c23d70a\n  vmov.f32    s8, r0\n  vadd.f32    s4, s4, s8\n\n  @ Decrement bullet timeout\n  vmov.f32    r0, s7\n  subs        r0, r0, #1\n  moveq       r0, #40\n  vmov.f32    s7, r0\n  bne         2f\n\n  @ Fire a flare\n  vcmp.f32    s2, s3\n  fmstat\n  blge        fire_flare\n\n2:\n  @ Test for collision with bullets\n  ldr         r0, =0x40000000\n  vmov.f32    s31, r0\n  bl          collide_bullets\n  tst         r0, r0\n  vmoveq.f32  r0, s6\n  subeq       r0, r0, #1\n  vmoveq.f32  s6, r0\n\n  @ Increment score\n  ldreq       r0, =player_score     @ Add to score\n  ldreq       r1, [r0]\n  addeq       r1, r1, #50\n  streq       r1, [r0]\n\n  @ Increment live enemy count\n  add         r10, r10, #1\n\n  ldmfd       sp!, {pc}\n\n@ ------------------------------------------------------------------------------\n@ Renders an enemy\n@ Arguments:\n@   none\n@ Returns:\n@   none\n@ Clobbers:\n@   s0 - s31\n@ ------------------------------------------------------------------------------\ndraw_enemy:\n  stmfd       sp!, {lr}\n\n  ldr         r0, =mtx_id\n  vldm.f32    r0, {s16 - s31}\n  ldr         r0, =mtx_model\n  vstm.f32    r0, {s16 - s31}\n  ldr         r0, =mtx_temp\n  vstm.f32    r0, {s16 - s31}\n\n  @ Damage\n  vmov.f32    r5, s6\n  subs        r5, r5, #1\n  mov         r6, #4\n  mov         r7, #3\n  mla         r5, r7, r5, r6\n\n  @ Translate & rotate\n  vneg.f32    s1, s1\n  ldr         r0, =mtx_model\n  bl          mat4_translate\n  vmov.f32    s0, s4\n  ldr         r0, =mtx_temp\n  bl          mat4_rot_z\n  ldr         r0, =mtx_model\n  ldr         r1, =mtx_temp\n  ldr         r2, =mtx_model\n  bl          mat4_mul_mat4\n\n  @ Compute MVP matrix\n  ldr         r0, =mtx_vp\n  ldr         r1, =mtx_model\n  ldr         r2, =mtx_mvp\n  bl          mat4_mul_mat4\n\n  @ Draw the enemy\n  ldr         r0, =enemy_vtx\n  ldr         r1, =enemy_idx\n  mov         r2, r5\n  ldr         r3, =mtx_mvp\n  ldr         r4, =light_dir\n  bl          gfx_draw_trgs\n\n  ldmfd       sp!, {pc}\n\n@ ------------------------------------------------------------------------------\n@ Creates a randomized enemy\n@ Arguments:\n@   r10 - index of enemy\n@ Returns:\n@   s0 - s5: enemy data\n@ Clobbers:\n@   Increments r10\n@ ------------------------------------------------------------------------------\nspawn_enemy:\n  stmfd       sp!, {lr}\n\n  @ Randomize x in range [-8.5, 8.5]\n  bl          random\n  and         r1, r0, #0xFF\n  sub         r1, r1, #0x7F\n  vmov.f32    s8, r1\n  fsitos      s8, s8\n  ldr         r1, =0x41400000\n  vmov.f32    s9, r1\n  vdiv.f32    s0, s8, s9\n\n  @ Randomize y in range [-2.8, 5.2]\n  bl          random\n  and         r1, r0, #0xFF\n  sub         r1, r1, #0x7F\n  vmov.f32    s8, r1\n  fsitos      s8, s8\n  ldr         r1, =0x42700000\n  vmov.f32    s9, r1\n  vdiv.f32    s1, s8, s9\n\n  @ Set z to -300.0\n  ldr         r0, =0xc3960000\n  vmov.f32    s2, r0\n\n  vmov.f32    s8, r10\n  fsitos      s8, s8\n  ldr         r0, =0x40a00000\n  vmov.f32    s9, r0\n  vmul.f32    s8, s8, s9\n  ldr         r0, =0xc2480000\n  vmov.f32    s9, r0\n  vsub.f32    s3, s9, s8\n\n  @ Rotation\n  ldr         r0, =0\n  vmov.f32    s4, r0\n\n  @ Random lateral movement\n  ldr         r0, =0x3e4ccccd\n  vmov.f32    s5, r0\n  bl          random\n  tst         r0, #1\n  vnegne.f32  s5, s5\n  and         r0, #1\n  add         r0, #1\n  vmov.f32    s8, r0\n  fsitos      s8, s8\n  vmul.f32    s5, s5, s8\n\n  @ Lives\n  mov         r0, #5\n  vmov.f32    s6, r0\n\n  @ Bullet timer\n  mov         r1, #15\n  add         r10, r10, #1\n  mul         r0, r1, r10\n  vmov.f32    s7, r0\n\n  ldmfd       sp!, {pc}\n\n@ ------------------------------------------------------------------------------\n@ Updates a flare\n@ Arguments:\n@   none\n@ Returns:\n@   none\n@ Clobers:\n@   none\n@ ------------------------------------------------------------------------------\nupdate_flare:\n  stmfd       sp!, {lr}\n\n  vadd.f32    s0, s0, s3\n  vadd.f32    s1, s1, s4\n  vadd.f32    s2, s2, s5\n\n  @ Check whether bullet is still active\n  ldr         r0, =0xc1200000\n  vmov.f32    s31, r0\n  vcmp.f32    s2, s31\n  fmstat\n  ldmltfd     sp!, {pc}\n\n  @ Despawn bullet and damage player\n  mov         r0, #0\n  vmov.f32    s6, r0\n\n  ldr         r0, =player_pos\n  vldm.f32    r0, {s30 - s31}\n  vsub.f32    s7, s0, s30\n  vabs.f32    s7, s7\n  vsub.f32    s8, s1, s31\n  vabs.f32    s8, s8\n\n  ldr         r0, =0x3fe00000\n  vmov.f32    s9, r0\n\n  vcmp.f32    s7, s9\n  fmstat\n  ldmgtfd     sp!, {pc}\n  vcmp.f32    s8, s9\n  fmstat\n  ldmgtfd     sp!, {pc}\n\n  ldr         r0, =player_rolling\n  ldr         r0, [r0]\n  tst         r0, r0\n  ldmnefd     sp!, {pc}\n\n  mov         r0, #20\n  bl          player_damage\n1:\n  ldmfd       sp!, {pc}\n\n@ ------------------------------------------------------------------------------\n@ Draws a flare\n@ Arguments:\n@   s0 - s2: position\n@ Returns:\n@   none\n@ Clobers:\n@   none\n@ ------------------------------------------------------------------------------\ndraw_flare:\n  stmfd       sp!, {lr}\n\n  ldr         r0, =mtx_model\n  vneg.f32    s1, s1\n  bl          mat4_translate\n\n  ldr         r0, =mtx_vp\n  ldr         r1, =mtx_model\n  ldr         r2, =mtx_mvp\n  bl          mat4_mul_mat4\n\n  @ Draw a sprite\n  ldr         r0, =flare\n  ldr         r1, =mtx_mvp\n  ldr         r2, =mtx_view\n  ldr         r3, =0x3e800000\n  vmov.f32    s0, r3\n  vmov.f32    s1, r3\n  bl          gfx_draw_sprite\n\n  ldmfd       sp!, {pc}\n\n@ ------------------------------------------------------------------------------\n@ Fires a flare\n@ Arguments:\n@   none\n@ Returns:\n@   none\n@ Clobers:\n@   none\n@ ------------------------------------------------------------------------------\nfire_flare:\n  stmfd       sp!, {r11 - r12, lr}\n\n  @ Load player position\n  ldr         r11, =player_pos\n  vldm.f32    r11, {s22 - s24}\n\n  @ Draw flares shot by enemies\n  ldr         r11, =FLARE_COUNT\n  ldr         r12, =flares\n1:\n  vldm.f32    r12, {s25 - s31}\n  vmov.f32    r0, s31\n  tst         r0, r0\n  addne       r12, r12, #28\n  beq         2f\n  subs        r11, r11, #1\n  bne         1b\n\n2:\n  @ Position\n  vmov.f32    s25, s0\n  vmov.f32    s26, s1\n  vmov.f32    s27, s2\n  vabs.f32    s21, s27\n\n  @ Direction\n  vsub.f32    s28, s22, s25\n  vsub.f32    s29, s23, s26\n  vsub.f32    s30, s24, s27\n\n  vdiv.f32    s28, s28, s21\n  vdiv.f32    s29, s29, s21\n  vdiv.f32    s30, s30, s21\n\n  @ Live flag\n  mov         r0, #1\n  vmov.f32    s31, r0\n\n  vstm.f32    r12!, {s25 - s31}\n\n  ldmfd       sp!, {r11 - r12, pc}\n\n@-------------------------------------------------------------------------------\n@ Resets enemies\n@-------------------------------------------------------------------------------\nreset_enemies:\n  stmfd       sp!, {r0 - r2, lr}\n  vstmdb.f32  sp!, {s0 - s7}\n\n  ldr         r2, =ENEMY_COUNT\n  ldr         r1, =enemies\n  mov         r0, #0\n\n1:\n  vldm.f32    r1, {s0 - s7}\n\n  vmov.f32    s0, r0\n  vmov.f32    s1, r0\n  vmov.f32    s2, r0\n  vmov.f32    s3, r0\n  vmov.f32    s4, r0\n  vmov.f32    s5, r0\n  vmov.f32    s6, r0\n  vmov.f32    s7, r0\n\n  vstm.f32    r1!, {s0 - s7}\n\n  subs        r2, #1\n  bne         1b\n\n  vldmia.f32  sp!, {s0 - s7}\n  ldmfd       sp!, {r0 - r2, pc}\n\n@-------------------------------------------------------------------------------\n@ Resets flares\n@-------------------------------------------------------------------------------\nreset_flares:\n  stmfd       sp!, {r0 - r3, lr}\n  vstmdb.f32  sp!, {s0 - s6}\n\n  ldr         r3, =FLARE_COUNT\n  ldr         r2, =flares\n  ldr         r1, =0xC1A00000      @ r1 = -20\n  mov         r0, #0\n\n1:\n  vldm.f32    r2, {s0 - s6}\n\n  vmov.f32    s0, r0\n  vmov.f32    s1, r0\n  vmov.f32    s2, r1\n  vmov.f32    s3, r0\n  vmov.f32    s4, r0\n  vmov.f32    s5, r0\n  vmov.f32    s6, r0\n\n  vstm.f32    r2!, {s0 - s6}\n\n  subs        r3, #1\n  bne         1b\n\n  vldmia.f32  sp!, {s0 - s6}\n  ldmfd       sp!, {r0 - r3, pc}\n"
  },
  {
    "path": "game.s",
    "content": "@ This file is part of the Team 28 Project\n@ Licensing information can be found in the LICENSE file\n@ (C) 2014 The Team 28 Authors. All rights reserved.\n.global setup_game\n.global mtx_proj\n.global mtx_model\n.global mtx_view\n.global mtx_temp\n.global mtx_vp\n.global mtx_mvp\n.global mtx_mp\n.global mtx_id\n.global player_pos\n.global light_dir\n.global wrench\n.global rocket\n.global bullet\n.global flare\n.global score\n.global building_small\n.global building_medium\n.global building_large\n.global mountains\n.global tristan\n.global monkey\n\n.include \"ports.s\"\n\n.section .data\n@ ------------------------------------------------------------------------------\n@ Common assets\n@ ------------------------------------------------------------------------------\nbullet:          .incbin  \"assets/bullet.bin\"\nrocket:          .incbin  \"assets/rocket.bin\"\nwrench:          .incbin  \"assets/wrench.bin\"\nflare:           .incbin  \"assets/flare.bin\"\nmountains:       .incbin  \"assets/mountains.bin\"\ntristan:         .incbin  \"assets/tristan.bin\"\nmonkey:          .incbin  \"assets/monkey.bin\"\npixfox:          .incbin  \"assets/pifox.bin\"\n\n@ ------------------------------------------------------------------------------\n@ Pad ascii to a fixed width\n@ ------------------------------------------------------------------------------\n.macro death_msg x, string\n8:\n  .long \\x\n  .ascii \"\\string\"\n9:\n  .iflt 64 - (9b - 8b)\n    .error \"String too long\"\n  .endif\n  .ifgt 64 - (9b - 8b)\n    .zero 64 - (9b - 8b)\n  .endif\n.endm\n\n@ ------------------------------------------------------------------------------\n@ Transformation matrices\n@ ------------------------------------------------------------------------------\nmtx_proj:        .float 1.810660, 0.0,        0.0,        0.0\n                 .float 0.0,      2.4142136,  0.0,        0.0\n                 .float 0.0,      0.0,       -1.0040080, -1.0\n                 .float 0.0,      0.0,       -2.0040080,  0.0\nmtx_model:       .float 1.0,      0.0,        0.0,        0.0\n                 .float 0.0,      1.0,        0.0,        0.0\n                 .float 0.0,      0.0,        1.0,        0.0\n                 .float 0.0,      0.0,        0.0,        1.0\nmtx_view:        .float 1.0,      0.0,        0.0,        0.0\n                 .float 0.0,      1.0,        0.0,        0.0\n                 .float 0.0,      0.0,        1.0,        0.0\n                 .float 0.0,      0.0,        0.0,        1.0\nmtx_temp:        .space 64, 0\nmtx_vp:          .space 64, 0\nmtx_mvp:         .space 64, 0\nmtx_mp:          .space 64, 0\nmtx_id:          .float 1.0, 0.0, 0.0, 0.0\n                 .float 0.0, 1.0, 0.0, 0.0\n                 .float 0.0, 0.0, 1.0, 0.0\n                 .float 0.0, 0.0, 0.0, 1.0\n\n@ ------------------------------------------------------------------------------\n@ Light direction\n@ ------------------------------------------------------------------------------\nlight_dir:       .float 0.3, -0.57, -0.57, 0.0\n\n.section .text\n@ ------------------------------------------------------------------------------\n@ Enables interrupts & starts the game\n@ ------------------------------------------------------------------------------\nsetup_game:\n  mov         r0, #0xDF\n  msr         cpsr, r0\n  b           start_loop\n\n@ ------------------------------------------------------------------------------\n@ Start screen displayed on boot\n@ ------------------------------------------------------------------------------\nstart_loop:\n  ldr         r0, =0xFF441111\n  bl          gfx_clear\n\n  @ Draw pifox title card\n  ldr         r0, =pixfox\n  mov         r1, #203\n  mov         r2, #30\n  bl          gfx_draw_image\n\n  bl          draw_sprites\n  bl          draw_start\n  bl          gfx_swap\n\n  bl          update_sound\n  bl          update_input\n\n  @ Loop until start is pressed\n  ldr         r0, =button_pressed\n  ldr         r0, [r0]\n  tst         r0, #0x08\n  beq         start_loop\n  b           game_loop\n\n\n@ ------------------------------------------------------------------------------\n@ Death screen\n@ ------------------------------------------------------------------------------\ndeath_loop:\n\n  @ Clear sounds \n  bl          snd_stop_roll\n  bl          snd_stop_bullet\n  bl          snd_stop_rock\n  bl          snd_stop_crash\n  bl          snd_stop_rocket\n  bl          snd_stop_cantlet\n  bl          snd_stop_pickup\n\n  @ Play fail sound\n  bl          snd_play_fail\n\n  @ Record high score\n  ldr         r1, =player_score\n  ldr         r1, [r1]\n  ldr         r0, =player_high_score\n  ldr         r0, [r0]\n  cmp         r1, r0\n  ldrgt       r0, =player_high_score\n  strgt       r1, [r0]\n\n  @ Generate random death message index\n  bl          random\n  and         r1, r0, #0x3\n1:\n  ldr         r0, =0xFF0044ff\n  bl          gfx_clear\n  bl          draw_death\n  bl          draw_sprites\n  bl          draw_start\n  bl          gfx_swap\n\n  bl          update_sound\n  bl          update_input\n\n  @ Loop until start is pressed\n  ldr         r0, =button_pressed\n  ldr         r0, [r0]\n  tst         r0, #0x08\n  beq         1b\n\n  bl          snd_stop_fail\n  bl          reset_enemies\n  bl          reset_flares\n  bl          reset_rockets \n  bl          reset_objects\n  bl          reset_bullets\n  bl          reset_player_mov\n\n  b           game_loop\n\n@-------------------------------------------------------------------------------\n@ Pause loop\n@-------------------------------------------------------------------------------\npause_loop:\n  stmfd       sp!, {lr}\n\n1:\n  bl          update_input  \n  bl          update_sound\n\n  @ Loop until select is pressed\n  ldr         r0, =button_clicked\n  ldr         r0, [r0]\n  tst         r0, #0x04\n  beq         1b\n\n  ldmfd       sp!, {pc}  \n\n@ ------------------------------------------------------------------------------\n@ Main game loop\n@ ------------------------------------------------------------------------------\ngame_loop:\n  bl          setup_player\n  bl          setup_enemies\n  bl          snd_play_rock\n\n1:\n  bl          gfx_swap\n  bl          update_input\n  \n  ldr         r0, =button_clicked\n  ldr         r0, [r0]\n  tst         r0, #0x04\n  blne        pause_loop\n\n  bl          update_player\n  bl          update_sound\n  bl          draw_pillars\n  bl          draw_enemies\n  bl          draw_rocks\n  bl          draw_bullets\n  bl          draw_rockets\n  bl          draw_player\n  bl          draw_fps\n  bl          draw_high_score\n\n  ldr         r0, =player_health\n  ldr         r0, [r0]\n  cmp         r0, #0\n  bgt         1b\n\n  b           death_loop\n\n.section .data\n@ ------------------------------------------------------------------------------\n@ FPS counter\n@ ------------------------------------------------------------------------------\nframe_counter:\n  .long 0\nlast_frame:\n  .long 0\nfps:\n  .long 0\n\n.section .text\n@ ------------------------------------------------------------------------------\n@ Renders the FPS counter on screen\n@ ------------------------------------------------------------------------------\ndraw_fps:\n  stmfd       sp!, {lr}\n\n  @ Updates the FPS counter\n  ldr         r0, =last_frame\n  ldr         r1, [r0]\n  ldr         r2, =1000000\n  add         r1, r1, r2            @ Update fps once every second\n\n  ldr         r2, =STIMER_CLO       @ Read system timer\n  ldr         r2, [r2]\n\n  ldr         r3, =frame_counter    @ Increment frame count\n  ldr         r4, [r3]\n  add         r4, r4, #1\n  str         r4, [r3]\n\n  cmp         r1, r2\n  bgt         1f                    @ If 1s passed, update fps\n  ldr         r1, =fps\n  str         r4, [r1]\n  str         r2, [r0]\n  mov         r4, #0\n1:\n  str         r4, [r3]\n\n  @ Renders the FPS on screen\n  ldr         r0, =1f\n  mov         r1, #15\n  mov         r2, #10\n  ldr         r3, =0xFFFFFFFF\n  ldr         r4, =fps\n  ldr         r4, [r4]\n  push        {r4}\n  ldr         r4, =player_score\n  ldr         r4, [r4]\n  push        {r4}\n  bl          printf\n  add         sp, sp, #8\n\n  ldmfd       sp!, {pc}\n1:\n  .ascii \"Score: %5d\\nFPS: %2d\"\n  .byte  0x0\n  .align 2\n\n@ ------------------------------------------------------------------------------\n@ Renders the high score for this session\n@ ------------------------------------------------------------------------------\ndraw_high_score:\n  stmfd       sp!, {lr}\n  \n  ldr         r0, =1f\n  mov         r1, #512\n  sub         r1, r1, #23\n  mov         r2, #10\n  ldr         r3, =0xFFFFFFFF\n  ldr         r4, =player_high_score\n  ldr         r4, [r4]\n  push        {r4}\n  bl          printf\n  add         sp, sp, #4\n  \n  ldmfd       sp!, {pc}\n1:\n  .ascii \"High Score: %5d\\n\"\n  .byte 0x0\n  .align 2\n\n\n@ ------------------------------------------------------------------------------\n@ Renders the welcome message\n@ ------------------------------------------------------------------------------\ndraw_start:\n  stmfd       sp!, {r0 - r3, lr}\n\n  ldr         r0, =1f\n  mov         r1, #240\n  mov         r2, #400\n  ldr         r3, =0xFFFFFFFF\n  bl          printf\n\n  ldmfd       sp!, {r0 - r3, pc}\n1:\n  .ascii \"Press START to begin\"\n  .byte  0x0\n  .align 2\n\n@ ------------------------------------------------------------------------------\n@ Prints the death message\n@ Arguments:\n@   r0 - Random number between 0 and number of strings\n@ Returns:\n@   Nothing\n@ ------------------------------------------------------------------------------\ndraw_death:\n  stmfd       sp!, {r0 - r4, lr}\n\n  @ Draw death message text\n  ldr         r0, =2f\n  add         r0, r0, r1, lsl #6\n  ldr         r1, [r0], #4\n  mov         r2, #170\n  ldr         r3, =0xFFFFFFFF\n  bl          printf\n\n  @ Draw score\n  ldr         r0, =1f\n  mov         r1, #272\n  mov         r2, #300\n  ldr         r3, =0xFFFFFFFF\n  ldr         r4, =player_score\n  ldr         r4, [r4]\n  push        {r4}\n  bl          printf\n\n  add         sp, sp, #4\n\n  ldmfd       sp!, {r0 - r4, pc}\n1:\n  .ascii \"Score: %5d\\0\"\n  .align 2\n2:\n  death_msg 200, \"You have died, what a tragedy!\\0\"\n  death_msg 172, \"You have died, better luck next time!\\0\"\n  death_msg 124, \"You have died, maybe you should go back to Mario?\\0\"\n  death_msg 184, \"You have died, give it another go?\\0\"\n\n.section .text\n@ ------------------------------------------------------------------------------\n@ Prints rotating sprites\n@ Arguments:\n@   none\n@ Returns:\n@   none\n@ Clobbers:\n@   s0 - s31\n@ ------------------------------------------------------------------------------\ndraw_sprites:\n  stmfd       sp!, {r0 - r4, lr}\n\n  @ Clear model matrix\n  ldr         r0, =mtx_id\n  vldm.f32    r0, {s0 - s15}\n  ldr         r0, =mtx_model\n  vstm.f32    r0, {s0 - s15}\n  ldr         r0, =mtx_temp\n  vstm.f32    r0, {s0 - s15}\n\n  @ Compute the proj - view matrix\n  ldr         r0, =0\n  vmov.f32    s0, r0\n  ldr         r0, =0\n  vmov.f32    s1, r0\n  ldr         r0, =0xc0e00000\n  vmov.f32    s2, r0\n  ldr         r0, =mtx_view\n  bl          mat4_translate\n\n  ldr         r0, =mtx_proj\n  ldr         r1, =mtx_view\n  ldr         r2, =mtx_vp\n  bl          mat4_mul_mat4\n\n  @ Prepare the model matrix\n  ldr         r0, =0x3f800000     @ 1.0\n  vmov.f32    s0, r0\n  ldr         r0, =0\n  vmov.f32    s1, r0\n  ldr         r0, =0\n  vmov.f32    s2, r0\n  ldr         r0, =mtx_model\n  bl          mat4_translate\n\n  @ Update rotation around y\n  ldr         r0, =1f\n  vldr.f32    s0, [r0]\n  ldr         r1, =0x3d000000     @ 0.03125\n  vmov.f32    s1, r1\n  vadd.f32    s0, s1\n  vstr.f32    s0, [r0]\n  ldr         r0, =mtx_temp\n  bl          mat4_rot_y\n  ldr         r0, =mtx_temp\n  ldr         r1, =mtx_model\n  ldr         r2, =mtx_model\n  bl          mat4_mul_mat4\n\n  @ Rotate around y by 120 degrees\n  ldr         r0, =0x40060a92     @ 2 * PI / 3\n  vmov.f32    s0, r0\n  ldr         r0, =mtx_temp\n  bl          mat4_rot_y\n\n  @ Draw a bullet\n  ldr         r0, =mtx_vp\n  ldr         r1, =mtx_model\n  ldr         r2, =mtx_mvp\n  bl          mat4_mul_mat4\n  ldr         r0, =bullet\n  ldr         r1, =mtx_mvp\n  ldr         r2, =mtx_model      @ don't ask me why\n  ldr         r3, =0x3e800000\n  vmov.f32    s0, r3\n  vmov.f32    s1, r3\n  bl          gfx_draw_sprite\n\n  @ Draw a rocket\n  ldr         r0, =mtx_temp\n  ldr         r1, =mtx_model\n  ldr         r2, =mtx_model\n  bl          mat4_mul_mat4\n  ldr         r0, =mtx_vp\n  ldr         r1, =mtx_model\n  ldr         r2, =mtx_mvp\n  bl          mat4_mul_mat4\n  ldr         r0, =rocket\n  ldr         r1, =mtx_mvp\n  ldr         r2, =mtx_model\n  ldr         r3, =0x3e800000\n  vmov.f32    s0, r3\n  vmov.f32    s1, r3\n  bl          gfx_draw_sprite\n\n  @ Draw a wrench\n  ldr         r0, =mtx_temp\n  ldr         r1, =mtx_model\n  ldr         r2, =mtx_model\n  bl          mat4_mul_mat4\n  ldr         r0, =mtx_vp\n  ldr         r1, =mtx_model\n  ldr         r2, =mtx_mvp\n  bl          mat4_mul_mat4\n  ldr         r0, =wrench\n  ldr         r1, =mtx_mvp\n  ldr         r2, =mtx_model\n  ldr         r3, =0x3e800000\n  vmov.f32    s0, r3\n  vmov.f32    s1, r3\n  bl          gfx_draw_sprite\n\n  ldmfd       sp!, {r0 - r4, pc}\n1:\n  .float      0.0\n"
  },
  {
    "path": "gfx.s",
    "content": "@ This file is part of the Team 28 Project\n@ Licensing information can be found in the LICENSE file\n@ (C) 2014 The Team 28 Authors. All rights reserved.\n.global setup_gfx\n.global gfx_fb\n.global gfx_swap\n.global gfx_clear\n.global gfx_draw_trgs\n.global gfx_draw_char\n.global gfx_draw_text\n.global gfx_draw_sprite\n.global gfx_draw_image\n.global gfx_draw_rect\n.global gfx_draw_frame\n\n.include \"ports.s\"\n\n@ ------------------------------------------------------------------------------\n@ Useful macros\n@ ------------------------------------------------------------------------------\n.macro vswap a, b, c\n  vmov.f32    \\c, \\a\n  vmov.f32    \\a, \\b\n  vmov.f32    \\b, \\c\n.endm\n\n.macro swap a, b, c\n  mov         \\c, \\a\n  mov         \\a, \\b\n  mov         \\b, \\c\n.endm\n\n.section .data\n@ ------------------------------------------------------------------------------\n@ Framebuffer structure\n@ ------------------------------------------------------------------------------\n.align 4\ngfx_fb:\n  .int 640    @ +0x00: Physical width\n  .int 480    @ +0x04: Physical height\n  .int 640    @ +0x08: Virtual width\n  .int 480    @ +0x0C: Virtual height\n  .int 0      @ +0x10: Pitch\n  .int 32     @ +0x14: Bit depth\n  .int 0      @ +0x18: X\n  .int 0      @ +0x1C: Y\n  .int 0      @ +0x20: Address\n  .int 0      @ +0x24: Size\n.align 2\n\n@-------------------------------------------------------------------------------\n@ Font bitmap\n@ Uses 8x16 bits per character, stored left to right top to bottom\n@ 1 - white pixel\n@ 0 - black pixel\n@-------------------------------------------------------------------------------\n.align 4\nfont:\n  .incbin \"assets/font.bin\"\n.align 2\n\n.section .text\n@ ------------------------------------------------------------------------------\n@ Initialises the framebuffer, retrieving its address\n@ ------------------------------------------------------------------------------\nsetup_gfx:\n  stmfd     sp!, {lr}\n\n  @ Request a framebuffer config\n  ldr       r0, =0x1\n  ldr       r1, =gfx_fb\n  orr       r1, #0x40000000\n  bl        mbox_write\n  bl        mbox_read\n\n  ldmfd     sp!, {pc}\n\n@ ------------------------------------------------------------------------------\n@ Clears the screen and depth buffer, setting depth to -1.0f and filling the\n@ colour buffer to a given value\n@\n@ Arguments:\n@   r0 - colour\n@ Returns:\n@   none\n@ Clobbers:\n@   s0 - s16\n@ ------------------------------------------------------------------------------\ngfx_clear:\n  stmfd     sp!, {r0 - r3}\n  ldr       r3, =0x3f800000\n\n  @ Clear registers\n  vmov.f32  s0,  r0\n  vmov.f32  s1,  r0\n  vmov.f32  s2,  r0\n  vmov.f32  s3,  r0\n  vmov.f32  s4,  r0\n  vmov.f32  s5,  r0\n  vmov.f32  s6,  r0\n  vmov.f32  s7,  r0\n  vmov.f32  s8,  r0\n  vmov.f32  s9,  r0\n  vmov.f32  s10, r0\n  vmov.f32  s11, r0\n  vmov.f32  s12, r0\n  vmov.f32  s13, r0\n  vmov.f32  s14, r0\n  vmov.f32  s15, r0\n\n  @ Clear 8 pixels at once\n  ldr       r0, =gfx_buffer\n  ldr       r2, =640 * 480\n1:\n  vstm.f32  r0!, {s0 - s15}\n  subs      r2, r2, #16\n  bne       1b\n\n  ldmfd     sp!, {r0 - r3}\n  mov       pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Copies color data from back buffer to framebuffer (color data is interleaved\n@ with depth data, so it must be extracted). Sets back buffer to the default\n@ colour and depth. Every iteration of the loop processes 8 pixels. pld is used\n@ to hint the CPU to prefetch data\n@ Arguments:\n@   none\n@ Returns:\n@   none\n@ Clobbers:\n@   s0 - s31\n@ ------------------------------------------------------------------------------\ngfx_swap:\n  stmfd     sp!, {r0 - r12, lr}\n\n  @ Compute addreses\n  ldr       r0, =gfx_fb\n  ldr       r0, [r0, #0x20]\n  ldr       r1, =gfx_buffer\n\n  @ Top half of the screen - blue gradient\n  ldr       r12, =0xffffee00\n  ldr       r11, =240\n1:\n  ldr       r2, =640 * 4\n  ldr       r4, =0x00020200\n  sub       r12, r12, r4\n  vmov.f32  s0, r12\n  vmov.f32  s1, r12\n  vmov.f32  s2, r12\n  vmov.f32  s3, r12\n  vmov.f32  s4, r12\n  vmov.f32  s5, r12\n  vmov.f32  s6, r12\n  vmov.f32  s7, r12\n  vmov.f32  s8, r12\n  vmov.f32  s9, r12\n  vmov.f32  s10, r12\n  vmov.f32  s11, r12\n  vmov.f32  s12, r12\n  vmov.f32  s13, r12\n  vmov.f32  s14, r12\n  vmov.f32  s15, r12\n\n  @ Fill 4 lines with one colour\n2:\n  pld       [r1, #0x100]\n\n  vldm.f32  r1, {s16 - s31}\n  vstm.f32  r0!, {s16 - s31}\n  vstm.f32  r1!, {s0 - s15}\n\n  subs      r2, r2, #16\n  bne       2b\n\n  subs      r11, r11, #4\n  bne       1b\n\n  @ Bottom half of the screen - green gradient\n  ldr       r12, =0xFF8C9C63\n  ldr       r11, =240\n\n3:\n  ldr       r2, =640 * 4\n  vmov.f32  s0, r12\n  vmov.f32  s1, r12\n  vmov.f32  s2, r12\n  vmov.f32  s3, r12\n  vmov.f32  s4, r12\n  vmov.f32  s5, r12\n  vmov.f32  s6, r12\n  vmov.f32  s7, r12\n  vmov.f32  s8, r12\n  vmov.f32  s9, r12\n  vmov.f32  s10, r12\n  vmov.f32  s11, r12\n  vmov.f32  s12, r12\n  vmov.f32  s13, r12\n  vmov.f32  s14, r12\n  vmov.f32  s15, r12\n\n  ldr       r4, =0x00010101\n  sub       r12, r12, r4\n\n  @ Fill 4 lines\n4:\n  pld       [r1, #0x100]\n\n  vldm.f32  r1, {s16 - s31}\n  vstm.f32  r0!, {s16 - s31}\n  vstm.f32  r1!, {s0 - s15}\n\n  subs      r2, r2, #16\n  bne       4b\n\n  subs      r11, r11, #4\n  bne       3b\n\n  @ Draw mountains\n  ldr          r0, =mountains\n  mov          r1, #0\n  mov          r2, #110\n  bl           gfx_draw_image\n\n  ldmfd     sp!, {r0 - r12, pc}\n\n@-------------------------------------------------------------------------------\n@ Renders a character to the screen\n@ Arguments:\n@   r0 - Character\n@   r1 - x coordinate\n@   r2 - y coordinate\n@   r3 - RGBA\n@ Returns:\n@   none\n@ Clobbers:\n@   r0 - r12\n@-------------------------------------------------------------------------------\ngfx_draw_char:\n  cmp       r0, #127              @ guard against invalid character inputs\n  movgt     pc, lr\n  stmfd     sp!, {r0 - r10}\n\n  @ calculate start address of the character\n  ldr       r9, =font\n  add       r9, r9, r0, lsl #4    @ r3 = font + ASCII value * 16\n\n  @ Store address of the buffer & size of the pitch\n  ldr       r6, =gfx_buffer\n  ldr       r7, =gfx_fb\n  ldr       r7, [r7, #0x10]       @ r7 = pitch\n\n  @ loop through the rows\n1:\n  ldrb      r4, [r9]              @ load byte\n  @ loop through the columns\n  mov       r5, #0\n2:\n  tst       r4, #1\n  beq       3f\n\n  @ draw pixel at (x + r5, y)\n  add       r10, r1, r5\n  mla       r8, r7, r2, r6        @ r8 = gfx_buffer + y * pitch\n  add       r8, r8, r10, lsl #2   @ r8 = gfx_buffer + y * pitch + (x + r5) * 8\n\n  str       r3, [r8]\n3:\n  add       r5, #1\n  lsr       r4, #1\n  cmp       r5, #8\n  blt       2b\n\n  add       r2, #1                @ y = y + 1\n  add       r9, #1                @ process next byte\n  tst       r9, #15               @ check if address of the next char reached\n  bne       1b\n\n  ldmfd     sp!, {r0 - r10}\n  mov       pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Renders text on screen\n@ Arguments:\n@   r0 - Address of null terminated string\n@   r1 - X position\n@   r2 - Y position\n@   r3 - RGBA\n@ Returns:\n@   none\n@ Clobbers:\n@   none\n@ ------------------------------------------------------------------------------\ngfx_draw_text:\n  stmfd     sp!, {r0 - r5, lr}\n  mov       r4, r0\n  mov       r5, r1                @ save intial x coordinate\n\n1:\n  ldrb      r0, [r4]              @ load next character\n  add       r4, #1\n  cmp       r0, #0                @ check if '\\0' reached\n  beq       2f\n\n  cmp       r0, #9                @ check if '\\t'\n  addeq     r1, #64               @ move 8 characters horizontally\n  beq       1b\n\n  cmp       r0, #10               @ check if '\\n'\n  moveq     r1, r5\n  addeq     r2, #16               @ go to the new line\n  beq       1b\n\n  bl        gfx_draw_char\n  add       r1, #8\n  b         1b\n2:\n  ldmfd     sp!, {r0 - r5, pc}\n  mov       pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Renders a textured sprite on screen\n@ Arguments:\n@   r0 - address of the texture\n@   r1 - Projection * view matrix\n@   r2 - View matrix\n@   s0 - width of the quad\n@   s1 - height of the quad\n@ Returns:\n@   none\n@ Clobbers:\n@   s0 - s31\n@ ------------------------------------------------------------------------------\ngfx_draw_sprite:\n  stmfd       sp!, {r0 - r12, lr}\n\n  @ Get right vector\n  vldr.f32    s25, [r2]\n  vldr.f32    s26, [r2, #0x10]\n  vldr.f32    s27, [r2, #0x20]\n  vmul.f32    s25, s25, s0\n  vmul.f32    s26, s26, s0\n  vmul.f32    s27, s27, s0\n\n  @ Get up vector\n  vldr.f32    s28, [r2, #0x04]\n  vldr.f32    s29, [r2, #0x14]\n  vldr.f32    s30, [r2, #0x24]\n  vmla.f32    s25, s28, s1\n  vmla.f32    s26, s29, s1\n  vmla.f32    s27, s30, s1\n\n  vldm.f32    r1, {s0 - s16}\n\n  @ Top left\n  ldr         r3, =0x3f800000\n  vmov.f32    s31, r3\n  vmov.f32    s16, s25\n  vmov.f32    s17, s26\n  vmov.f32    s18, s27\n  vmov.f32    s19, s31\n  bl          mat4_fmul_vec4\n  bl          transform_vertex\n\n  @ Bottom right\n  vneg.f32    s16, s25\n  vneg.f32    s17, s26\n  vneg.f32    s18, s27\n  vmov.f32    s19, s31\n  vmov.f32    s28, s20\n  vmov.f32    s26, s21\n  vmov.f32    s30, s22\n  bl          mat4_fmul_vec4\n  bl          transform_vertex\n  vmov.f32    s29, s20\n  vmov.f32    s25, s21\n\n  @ Check depth range\n  ldr         r5, =0xbf800000\n  vmov.f32    s21, r5\n  vcmp.f32    s30, s21\n  fmstat\n  ldmltfd     sp!, {r0 -r12, pc}\n\n  vneg.f32    s21, s21\n  vcmp.f32    s30, s21\n  fmstat\n  ldmgtfd     sp!, {r0 -r12, pc}\n\n  mov         r7, #0\n  vmov.f32    s2, r7                  @ pixelY\n  vmov.f32    s3, r7                  @ pixelX\n\n  ldr         r5, =479\n  ftosizs     s24, s26\n  vmov.f32    r1, s24\n  cmp         r1, #0\n  movlt       r1, #0\n  vneglt.f32  s2, s26\n  cmp         r1, r5\n  movgt       r1, r5                  @ y0\n\n  ftosizs     s24, s25\n  vmov.f32    r2, s24\n  cmp         r2, #0\n  movlt       r2, #0\n  cmp         r2, r5\n  movgt       r2, r5                  @ y1\n\n  ldr         r5, =639\n  ftosizs     s24, s29\n  vmov.f32    r3, s24\n  cmp         r3, #0\n  movlt       r3, #0\n  vneglt.f32  s3, s29\n  cmp         r3, r5\n  movgt       r3, r5                  @ x0\n\n  ftosizs     s24, s28\n  vmov.f32    r4, s24\n  cmp         r4, #0\n  movlt       r4, #0\n  cmp         r4, r5\n  movgt       r4, r5                  @ x1\n\n  ldr         r5, =gfx_fb\n  ldr         r5, [r5, #0x10]         @ r5 = pitch\n\n  ldr         r6, =gfx_buffer\n  mla         r6, r5, r1, r6\n  add         r6, r6, r3, lsl #2\n\n  @ Check bounds\n  subs        r2, r2, r1\n  ble         3f\n  cmp         r4, r3\n  ble         3f\n\n  ldr         r8, [r0], #4\n  vmov.f32    s0, r8\n  fsitos      s0, s0\n  vsub.f32    s6, s25, s26            @ height\n  vdiv.f32    s0, s0, s6\n\n  ldr         r9, [r0], #4\n  vmov.f32    s1, r9\n  fsitos      s1, s1\n  vsub.f32    s6, s28, s29            @ width\n  vdiv.f32    s1, s1, s6\n  lsl         r9, r9, #2\n\n  ldr         r7, =0x3f800000         @ 1.0f\n  vmov.f32    s4, r7\n\n  @ Loop over scanline\n1:\n  mov         r12, r6\n  subs        r7, r4, r3\n\n  vmul.f32    s6, s2, s0\n  ftosizs     s6, s6\n  vmov.f32    r1, s6\n  vmov.f32    s7, s3\n  mla         r8, r1, r9, r0\n2:\n  vmul.f32    s6, s7, s1\n  ftosizs     s6, s6\n  vmov.f32    r1, s6\n\n  @ Texture lookup\n  ldr         r11, [r8, r1, lsl #2]\n  lsrs        r1, r11, #24\n  strne       r11, [r6]\n  add         r6, #4\n  vadd.f32    s7, s7, s4\n  subs        r7, r7, #1\n  bgt         2b\n\n  add         r6, r12, r5\n  vadd.f32    s2, s2, s4\n  subs        r2, r2, #1\n  bgt         1b\n3:\n  ldmfd       sp!, {r0 -r12, pc}\n\n@ ------------------------------------------------------------------------------\n@ Draws an image on screen\n@ Arguments:\n@   r0 - image\n@   r1 - x on screen\n@   r2 - y on screen\n@ ------------------------------------------------------------------------------\ngfx_draw_image:\n  cmp         r1, #640\n  movge       pc, lr\n  cmp         r2, #480\n  movge       pc, lr\n\n  stmfd       sp!, {r0 - r12, lr}\n\n  ldr         r4, [r0], #4           @ Width\n  ldr         r3, [r0], #4           @ Height\n\n  cmn         r0, r3\n  stmmifd     sp!, {r0 - r12, pc}\n  cmn         r1, r4\n  stmmifd     sp!, {r0 - r12, pc}\n\n  ldr         r10, =gfx_fb\n  ldr         r10, [r10, #0x10]       @ r10 = pitch\n  lsl         r12, r3, #2             @ image pitch\n  ldr         r11, =gfx_buffer        @ buffer\n\n  tst         r1, r1\n  addmi       r3, r3, r1\n  submi       r0, r0, r1, lsl #2      @ Clamp left\n  movmi       r1, #0\n\n  tst         r2, r2\n  addmi       r4, r4, r2\n  negmi       r2, r2\n  mlami       r0, r12, r2, r0\n  movmi       r2, #0                  @ Clamp top\n\n  add         r6, r1, r3\n  cmp         r6, #640\n  subge       r6, #640\n  subge       r3, r3, r6\n\n  add         r6, r2, r4\n  cmp         r6, #480\n  subge       r6, #480\n  subge       r4, r4, r6\n\n  mla         r11, r2, r10, r11\n  add         r11, r11, r1, lsl #2\n\n  tst         r1, r1\n  addmi       r3, r3, r1\n  negmi       r1, r1\n1:\n  mov         r7, r0\n  mov         r8, r11\n  mov         r6, r3\n2:\n  ldr         r9, [r0], #4\n  tst         r9, #0xFF000000\n  strne       r9, [r11], #4\n  addeq       r11, r11, #4\n\n  subs        r6, r6, #1\n  bne         2b\n\n  add         r0, r7, r12\n  add         r11, r8, r10\n  subs        r4, r4, #1\n  bne         1b\n\n  ldmfd       sp!, {r0 - r12, pc}\n\n@ ------------------------------------------------------------------------------\n@ Draws a line using Bresenham's algorithm\n@   r0 - x0\n@   r1 - y0\n@   r2 - x1\n@   r3 - y1\n@   r4 - colour\n@ Returns:\n@   none\n@ Clobbers:\n@   none\n@ ------------------------------------------------------------------------------\ngfx_draw_line:\n  stmfd       sp!, {r0 - r12, lr}\n\n  subs        r5, r2, r0\n  neglt       r5, r5                  @ r5 = dx = abs(x1 - x0)\n  subs        r6, r3, r1\n  neggt       r6, r6                  @ r6 = -dy = -abs(y1 - y0)\n\n  cmp         r0, r2\n  movle       r7, #1\n  movgt       r7, #-1                 @ r7 = x0 < x1 ? 1 : -1\n  cmp         r1, r3\n  movle       r8, #1\n  movgt       r8, #-1                 @ r8 = y0 < y1 ? 1 : -1\n\n  adds        r9, r5, r6              @ err = dx - dy\n\n  ldr         r10, =gfx_fb\n  ldr         r10, [r10, #0x10]       @ r10 = pitch\n\n  ldr         r11, =gfx_buffer\n1:\n  cmp         r0, #0\n  blt         2f\n  cmp         r1, #0\n  blt         2f\n\n  ldr         r12, =639\n  cmp         r0, r12\n  bge         2f\n  ldr         r12, =479\n  cmp         r1, r12\n  bge         2f\n\n  mla         r12, r10, r1, r11\n  add         r12, r12, r0, lsl #3    @ emit (x0, y0)\n  str         r4, [r12]\n2:\n  teq         r0, r2\n  teqeq       r1, r3                  @ bail if x0 == x1 && y0 == y1\n  beq         3f\n\n  lsl         r12, r9, #1\n  cmp         r12, r6\n  addgt       r9, r9, r6\n  addgt       r0, r0, r7\n\n  cmp         r12, r5\n  addlt       r9, r9, r5\n  addlt       r1, r1, r8\n\n  b           1b\n3:\n  ldmfd       sp!, {r0 - r12, pc}\n\n@ ------------------------------------------------------------------------------\n@ Renders a list of triangles\n@ Arguments:\n@   r0 - Vertex data\n@   r1 - Index data\n@   r2 - Number of triangles\n@   r3 - MVP matrix\n@   r4 - Light direction\n@ Returns:\n@   none\n@ Clobbers:\n@   s0 - s31\n@ ------------------------------------------------------------------------------\ngfx_draw_trgs:\n  stmfd       sp!, {r0 - r12, lr}\n\n1:\n  subs        r2, r2, #1\n  blt         3f\n\n  ldm         r1!, {r10, r11, r12}  @ Indices\n  vldm.f32    r3, {s0 - s15}        @ MVP matrix\n  eor         r5, r5, r5            @ Number of visible vertices\n  add         r1, #12\n\n  add         r10, r0, r10, lsl #4\n  vldm.f32    r10, {s16 - s19}      @ r10 = &v0.xyz\n  bl          mat4_fmul_vec4\n  bl          transform_vertex\n  vmov.f32    s30, s22\n  vmov.f32    s29, s21\n  vmov.f32    s28, s20              @ v0\n\n  add         r11, r0, r11, lsl #4\n  vldm.f32    r11, {s16 - s19}      @ r11 = &v1.xyz\n  bl          mat4_fmul_vec4\n  bl          transform_vertex\n  vmov.f32    s27, s22\n  vmov.f32    s26, s21\n  vmov.f32    s25, s20              @ v1\n\n  add         r12, r0, r12, lsl #4\n  vldm.f32    r12, {s16 - s19}      @ r12 = &v2.xyz\n  bl          mat4_fmul_vec4\n  bl          transform_vertex\n  vmov.f32    s24, s22\n  vmov.f32    s23, s21\n  vmov.f32    s22, s20              @ v2\n\n  @ If at least one vertex is not clipped, continue\n  tst         r5, r5\n  bne         2f\n\n  @ Check whether triangle intersects the viewport\n  vcmp.f32    s22, #0\n  fmstat\n  vcmplt.f32  s25, #0\n  fmstat\n  vcmplt.f32  s28, #0\n  fmstat\n  blt         1b\n\n  vcmp.f32    s23, #0\n  fmstat\n  vcmplt.f32  s26, #0\n  fmstat\n  vcmplt.f32  s29, #0\n  fmstat\n  blt         1b\n\n  ldr         r5, =0xbf800000\n  vmov.f32    s21, r5\n  vcmp.f32    s24, s21\n  fmstat\n  vcmplt.f32  s27, s21\n  fmstat\n  vcmplt.f32  s30, s21\n  fmstat\n  blt         1b\n\n  vneg.f32    s21, s21\n  vcmp.f32    s24, s21\n  fmstat\n  vcmpgt.f32  s27, s21\n  fmstat\n  vcmpgt.f32  s30, s21\n  fmstat\n  bgt         1b\n\n  ldr         r5, =0x43ef8000\n  vmov.f32    s21, r5\n  vcmp.f32    s23, s21\n  fmstat\n  vcmpgt.f32  s26, s21\n  fmstat\n  vcmpgt.f32  s29, s21\n  fmstat\n  bgt         1b\n\n  ldr         r5, =0x441fc000\n  vmov.f32    s21, r5\n  vcmp.f32    s22, s21\n  fmstat\n  vcmpgt.f32  s25, s21\n  fmstat\n  vcmpgt.f32  s28, s21\n  fmstat\n  bgt         1b\n\n  @ Cull back faces\n2:\n  vmul.f32    s0, s28, s26          @ Check if vertices are in ccw order\n  vmla.f32    s0, s22, s29          @ (note: y coordinates are flipped)\n  vmla.f32    s0, s25, s23          @ | x0 y0 1 |\n  vmls.f32    s0, s22, s26          @ | x1 y1 1 | < 0\n  vmls.f32    s0, s28, s23          @ | x2 y2 1 |\n  vmls.f32    s0, s25, s29\n  vmov.f32    r5, s0\n  tst         r5, r5\n\n  beq         1b\n  bpl         1b\n\n  bl          shade_triangle\n  bl          draw_triangle\n  b           1b\n3:\n\n  ldmfd       sp!, {r0 - r12, pc}\n\n@ ------------------------------------------------------------------------------\n@ Computes window coordinates from normalised device coordinates by performing\n@ perspective division. Also checks if the vertex is visble on the screen.\n@ If the vertex is not clipped, r5 is incremented.\n@ Arguments:\n@   s16 - s19: Vector\n@ Returns:\n@   s20 - s23: (x, y, z, w)\n@ Clobbers:\n@   s20 - s24, r5, r6\n@ ------------------------------------------------------------------------------\ntransform_vertex:\n  vcmp.f32    s23, #0\n  fmstat\n  ble         1f                @ w <= 0.0f\n\n  vcmp.f32    s20, s23\n  fmstat\n  vcmple.f32  s21, s23\n  fmstat\n  vcmple.f32  s22, s23\n  fmstat\n  vneg.f32    s23, s23\n  bgt         1f                @ x > w || y > w || z > w\n\n  vcmp.f32    s23, s20\n  fmstat\n  vcmple.f32  s23, s21\n  fmstat\n  vcmple.f32  s23, s22\n  fmstat\n  addle       r5, #1            @ -w <= x || -w <= y || -w <= z\n1:\n  ldr         r6, =0x3f800000\n  vmov.f32    s31, r6           @ 1.0f\n\n  vdiv.f32    s20, s20, s23     @ x = (1.0f - x) * 320\n  vsub.f32    s20, s31, s20\n  ldr         r6, =0x43a00000\n  vmov.f32    s24, r6           @ s24 = 320.0f\n  vmul.f32    s20, s20, s24\n\n  vdiv.f32    s21, s21, s23     @ y = (1.0f + y) * 240\n  vadd.f32    s21, s31, s21\n  ldr         r6, =0x43700000\n  vmov.f32    s24, r6           @ s24 = 320.0f\n  vmul.f32    s21, s21, s24\n\n  vdiv.f32    s22, s22, s23     @ w = -w\n  vneg.f32    s22, s22\n\n  mov         pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Performs per-polygon shading, computing a colour value for the entire\n@ triangle\n@ Arguments:\n@   r10, r11, r12 - triangle indices\n@ Returns:\n@   r12 - colour value\n@ Clobbers:\n@   s0 - s15\n@ ------------------------------------------------------------------------------\nshade_triangle:\n  vldm.f32      r10, {s0 - s2}      @ r10 = &v0.rgb\n  vldm.f32      r11, {s3 - s5}      @ r11 = &v1.rgb\n  vldm.f32      r12, {s6 - s8}      @ r12 = &v2.rgb\n\n  @ Compute the normal vector\n  vsub.f32      s0, s0, s3\n  vsub.f32      s1, s1, s4\n  vsub.f32      s2, s2, s5\n  vsub.f32      s6, s6, s3\n  vsub.f32      s7, s7, s4\n  vsub.f32      s8, s8, s5\n\n  vmul.f32      s3, s1, s8\n  vmls.f32      s3, s7, s2\n  vmul.f32      s4, s6, s2\n  vmls.f32      s4, s0, s8\n  vmul.f32      s5, s0, s7\n  vmls.f32      s5, s1, s6\n\n  @ Normalize it\n  vmul.f32      s0, s3, s3\n  vmla.f32      s0, s4, s4\n  vmla.f32      s0, s5, s5\n  vsqrt.f32     s0, s0\n\n  vdiv.f32      s3, s3, s0\n  vdiv.f32      s4, s4, s0\n  vdiv.f32      s5, s5, s0\n\n  @ Compute the dot product between the normal\n  @ and the light direction\n  vldm.f32      r4, {s0 - s2}\n  vmul.f32      s0, s0, s3\n  vmla.f32      s0, s1, s4\n  vmla.f32      s0, s2, s5\n\n  @ Compute light intensity: ambient + diffuse\n  ldr           r5, =0x3e4ccccd\n  ldr           r6, =0x3f800000\n  vmov.f32      s1, r5\n  vmov.f32      s2, r6\n\n  vcmp.f32      s0, #0\n  fmstat\n  vmovlt.f32    s0, s1\n  vaddgt.f32    s0, s1\n\n  ldr           r5, =0x437f0000\n  vmov.f32      s1, r5\n  vmul.f32      s0, s1\n\n  sub           r1, #12\n  vldm.f32      r1, {s3 - s5}\n  add           r1, #12\n  vmul.f32      s3, s3, s0\n  vmul.f32      s4, s4, s0\n  vmul.f32      s5, s5, s0\n\n  ldr           r12, =0xff000000\n\n  ftosizs       s3, s3\n  vmov.f32      r11, s3\n  cmp           r11, #0\n  movlt         r11, #0\n  andgt         r11, r11, #0xFF\n  orr           r12, r12, r11, lsl #0\n\n  ftosizs       s4, s4\n  vmov.f32      r11, s4\n  cmp           r11, #0\n  movlt         r11, #0\n  andgt         r11, r11, #0xFF\n  orr           r12, r12, r11, lsl #8\n\n  ftosizs       s5, s5\n  vmov.f32      r11, s5\n  cmp           r11, #0\n  movlt         r11, #0\n  andgt         r11, r11, #0xFF\n  orr           r12, r12, r11, lsl #16\n\n  mov           pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Rasterises a triangle with colour interpolation\n@ Arguments:\n@   r10: v0 data\n@   s28 - s30: v0(x, y, z)\n@   r11: v1 data\n@   s25 - s27: v1(x, y, z)\n@   r12: v2 data\n@   s22 - s24: v2(x, y, z)\n@ Returns:\n@   none\n@ Clobers:\n@   s0 - s31, r0 - r12\n@ ------------------------------------------------------------------------------\ndraw_triangle:\n  stmfd         sp!, {r0 - r4, lr}\n\n  @ Sort the points: v0.y < v1.y < v2.y\n  vcmp.f32      s29, s26\n  fmstat\n  ble           1f\n  vswap         s28, s25, s16\n  vswap         s29, s26, s16\n  vswap         s30, s27, s16\n1:\n  vcmp.f32      s29, s23\n  fmstat\n  ble           1f\n  vswap         s28, s22, s16\n  vswap         s29, s23, s16\n  vswap         s30, s24, s16\n1:\n  vcmp.f32      s26, s23\n  fmstat\n  ble           1f\n  vswap         s25, s22, s16\n  vswap         s26, s23, s16\n  vswap         s27, s24, s16\n1:\n\n  @ Convert y coordinates to integers and clamp them to range [0, 480)\n  ldr           r3, =479\n\n  ftosizs       s0, s29\n  vmov.s32      r0, s0\n  cmp           r0, #0\n  movlt         r0, #0\n  cmp           r0, r3\n  movgt         r0, r3              @ r0 = clamp(v0.y, 0, 479)\n  ftosizs       s0, s26\n  vmov.s32      r1, s0\n  cmp           r1, #0\n  movlt         r1, #0\n  cmp           r1, r3\n  movgt         r1, r3              @ r1 = clamp(v1.y, 0, 479)\n  ftosizs       s0, s23\n  vmov.s32      r2, s0\n  cmp           r2, #0\n  movlt         r2, #0\n  cmp           r2, r3\n  movgt         r2, r3              @ r2 = clamp(v2.y, 0, 479)\n\n  @ Compute bounds on x axis\n  vcmp.f32      s25, s22\n  fmstat\n  vmovgt.f32    s1, s25\n  vmovgt.f32    s0, s22\n  vmovle.f32    s1, s22\n  vmovle.f32    s0, s25\n  vcmp.f32      s28, s0\n  fmstat\n  vmovle.f32    s0, s28             @ s0 = min(v0.x, v1.x, v2.x)\n  vcmp.f32      s28, s1\n  fmstat\n  vmovgt.f32    s1, s28             @ s1 = max(v0.x, v1.x, v2.x)\n\n  ldr           r3, =0\n  vmov.f32      s21, r3\n  vcmp.f32      s0, s21\n  fmstat\n  vmovlt.f32    s0, s21\n  vcmp.f32      s1, s21\n  fmstat\n  vmovlt.f32    s1, s21\n\n  ldr           r3, =0x441fc000     @ r3 = 639.0f\n  vmov.f32      s21, r3\n  vcmp.f32      s0, s21\n  fmstat\n  vmovgt.f32    s0, s21             @ s0 = clamp(s0, 0, 639)\n  vcmp.f32      s1, s21\n  fmstat\n  vmovgt.f32    s1, s21             @ s1 = clamp(s1, 0, 639)\n\n  @ Compute scanline length\n  ldr           r3, =gfx_fb\n  ldr           r3, [r3, #0x10]     @ r3 = pitch\n\n@ ------------------------------------------------------------------------------\n@ Rasterizes the top triangle\n@ ------------------------------------------------------------------------------\nraster_top:\n  stmfd         sp!, {r0, r1, r2}\n  vstmdb.f32    sp!, {s22 - s30}\n\n  @ Gradient for v2 - v0\n  vsub.f32      s31, s23, s29\n  vsub.f32      s2, s22, s28\n  vdiv.f32      s2, s2, s31       @ gradLeftX\n\n  @ Gradient for v1 - v0\n  vsub.f32      s22, s26, s29\n  vsub.f32      s7, s25, s28\n  vdiv.f32      s7, s7, s22       @ gradRightX\n\n  @ If gradient of v1 - v0 is larger than the gradient\n  @ of v2 - v0, the gradients must be swapped\n  vcmp.f32      s7, s2\n  fmstat\n  blt           1f\n  vswap         s7, s2, s4\n  vswap         s3, s8, s4\n  vswap         s31, s22, s4\n1:\n\n  @ Loop through all scanlines and fill triangles line by line\n  ldr           r5, =0x3f800000\n  vmov.f32      s22, r5\n\n  ftosis        s31, s29\n  vmov.f32      r5, s31\n  cmp           r5, #0\n  neglt         r5, r5\n  movgt         r5, #0\n\n  subs          r1, r1, r0\n  ble           1f\n\n  ldr           r4, =gfx_buffer\n  mla           r4, r0, r3, r4    @ r4 = first row\n2:\n  vmov.f32      s31, r5\n  fsitos        s31, s31\n\n  bl            draw_span\n\n  add           r4, r3\n  add           r5, #1\n  subs          r1, #1\n  bge           2b\n1:\n  vldmia.f32    sp!, {s22 - s30}\n  ldmfd         sp!, {r0, r1, r2}\n\n@ ------------------------------------------------------------------------------\n@ Rasterizes the bottom triangle\n@ ------------------------------------------------------------------------------\nraster_bottom:\n  @ Gradient for v0 - v2\n  vsub.f32      s2, s28, s22\n  vsub.f32      s31, s23, s29\n  vsub.f32      s3, s30, s24\n  vdiv.f32      s2, s2, s31       @ gradLeftX\n\n  @ Gradient for v1 - v2\n  vsub.f32      s7, s25, s22\n  vsub.f32      s29, s23, s26\n  vsub.f32      s8, s27, s24\n  vdiv.f32      s7, s7, s29       @ gradRightX\n\n  @ If gradient of v1 - v0 is larger than the gradient\n  @ of v2 - v0, the gradients must be swapped\n  vcmp.f32      s7, s2\n  fmstat\n  blt           1f\n  vswap         s2, s7, s4\n  vswap         s3, s8, s4\n  vswap         s4, s9, s4\n  vswap         s29, s31, s4\n1:\n\n  @ Setup origins\n  vmov.f32      s28, s22\n  vmov.f32      s30, s24\n\n  @ Loop through all scanlines and fill triangles line by line\n  ldr           r4, =gfx_buffer\n  mla           r4, r2, r3, r4    @ r4 = first row\n\n  subs          r2, r1\n  ble           1f\n\n  ftosis        s24, s23\n  vmov.f32      r6, s24\n  ldr           r7, =479\n  cmp           r6, r7\n  subge         r5, r6, r7\n  movlt         r5, #0\n\n2:\n  vmov.f32      s31, r5\n  fsitos        s31, s31\n\n  bl            draw_span\n\n  sub           r4, r3\n  add           r5, #1\n  subs          r2, #1\n  bge           2b\n1:\n  ldmfd         sp!, {r0 - r4, pc}\n\n@ ------------------------------------------------------------------------------\n@ Draws a span between two points on a scanline, interpolating colour and\n@ depth values and writing data into the back buffer. Note that instructions\n@ are arranged in order to make full use of the CPUs ability to place up to\n@ 8 instructions in the pipeline\n@\n@ Arguments:\n@   r4 - address of scanline\n@   s0 - min X\n@   s1 - max X\n@   s2 - s6   - right edge gradient (x, d, r, g, b)\n@   s7 - s11  - left edge gradient (x, d, r, g, b)\n@ Returns:\n@   none\n@ Clobbers:\n@   r6 - r12, s12 - s27\n@ ------------------------------------------------------------------------------\ndraw_span:\n  mov           r8, #0\n  vmov.f32      s12, s28\n  vmla.f32      s12, s7, s31          @ x0\n  ftosizs       s12, s12\n  fsitos        s12, s12\n  vmov.f32      s16, s28\n  vmla.f32      s16, s2, s31          @ x1\n\n  vsub.f32      s20, s16, s12         @ length of span\n\n  vcmp.f32      s0, s12\n  fmstat\n  vsubgt.f32    s26, s0, s12\n  ftosizsgt     s26, s26\n  vmovgt.f32    r8, s26               @ x0'\n  vmovgt.f32    s12, s0\n  vcmp.f32      s1, s12\n  fmstat\n  vmovlt.f32    s12, s1               @ clamp(x0, s0, s1)\n  vcmp.f32      s1, s16\n  fmstat\n  vmovlt.f32    s16, s1\n  vcmp.f32      s0, s16\n  fmstat\n  vmovgt.f32    s16, s0               @ clamp(x1, s0, s1)\n\n  ftosis        s12, s12\n  vmov.f32      r6, s12               @ x0\n  ftosis        s16, s16\n  vmov.f32      r7, s16               @ x1\n  subs          r7, r6\n  movle         pc, lr                @ x0 < x1\n\n  add           r6, r4, r6, lsl #2    @ r6 - first pixel in scanline\n  ldr           r10, =0x437f0000\n  vmov.f32      s22, r10              @ 255.0f\n1:\n  vmov.f32      s26, r8\n  fsitos        s26, s26\n\n  @ Interpolate colour\n  str           r12, [r6], #4\n  add           r8, #1\n  subs          r7, #1\n  bge           1b\n\n  mov           pc, lr\n\n@-------------------------------------------------------------------------------\n@ Renders a rectangle of size r2xr3 and colour r4 starting at (r0, r1)\n@ Arguments:\n@   r0 - x coordinate\n@   r1 - y coordinate\n@   r2 - width\n@   r3 - height\n@   r4 - colour\n@ Returns:\n@   none\n@ Clobbers:\n@   none\n@-------------------------------------------------------------------------------\ngfx_draw_rect:\n  cmp       r2, #0\n  moveq     pc, lr\n\n  stmfd     sp!, {r0 - r10}\n\n  ldr       r6, =gfx_buffer\n  ldr       r7, =gfx_fb\n  ldr       r7, [r7, #0x10]       @ r7 = pitch\n\n  add       r10, r1, r3           @ r10 = y + height\n1:\n  mov       r5, #0\n2:\n  add       r9, r0, r5            @ r9 = x + r5\n  mla       r8, r7, r1, r6        @ r8 = gfx_buffer + y * pitch\n  add       r8, r8, r9, lsl #2    @ r8 = gfx_buffer + y * pitch + (x + r5) * 4\n\n  str       r4, [r8]\n\n  add       r5, #1\n  cmp       r5, r2\n  ble       2b\n\n  add       r1, #1\n  cmp       r1, r10\n  ble       1b\n3:\n  ldmfd     sp!, {r0 - r10}\n  mov       pc, lr\n\n@-------------------------------------------------------------------------------\n@ Renders a 2px frame of size r2xr3 and colour r4 starting at (r0, r1)\n@ Arguments:\n@   r0 - x coordinate\n@   r1 - y coordinate\n@   r2 - width\n@   r3 - height\n@   r4 - colour\n@ Returns:\n@   none\n@ Clobbers:\n@   none\n@-------------------------------------------------------------------------------\ngfx_draw_frame:\n  cmp       r2, #0\n  moveq     pc, lr\n\n  stmfd     sp!, {r0 - r12}\n\n  ldr       r6, =gfx_buffer\n  ldr       r7, =gfx_fb\n  ldr       r7, [r7, #0x10]\n\n  @ Draw horizontal lines\n  add       r10, r1, #1\n  add       r11, r1, r3\n  sub       r12, r11, #1\n  mov       r5, #0\n\n1:\n  add       r9, r0, r5\n\n  mla       r8, r7, r1, r6\n  add       r8, r8, r9, lsl #2\n  str       r4, [r8]\n\n  mla       r8, r7, r10, r6\n  add       r8, r8, r9, lsl #2\n  str       r4, [r8]\n\n  mla       r8, r7, r11, r6\n  add       r8, r8, r9, lsl #2\n  str       r4, [r8]\n\n  mla       r8, r7, r12, r6\n  add       r8, r8, r9, lsl #2\n  str       r4, [r8]\n\n  add       r5, #1\n  cmp       r5, r2\n  ble       1b\n\n  @ Draw vertical lines\n  add       r10, r0, #1\n  add       r11, r0, r2\n  sub       r5, r11, #1\n  add       r1, r1, #2\n\n2:\n  mla       r2, r7, r1, r6\n\n  add       r8, r2, r0, lsl #2\n  str       r4, [r8]      \n\n  add       r8, r2, r10, lsl #2\n  str       r4, [r8]\n\n  add       r8, r2, r11, lsl #2\n  str       r4, [r8]\n\n  add       r8, r2, r5, lsl #2\n  str       r4, [r8]\n\n  add       r1, #1\n  cmp       r1, r12\n  blt       2b\n\n  ldmfd     sp!, {r0 - r12}\n  mov       pc, lr\n"
  },
  {
    "path": "imager.py",
    "content": "#!/usr/bin/python2\n\n\"\"\"\nThis file is part of the Team 28 Project\nLicensing information can be found in the LICENSE file\n(C) 2014 The Team 28 Authors. All rights reserved.\n\"\"\"\n\nfrom PIL import Image\nimport struct\nimport sys\nimport os\nimport argparse\n\n\ndef main():\n    # Parse arguments\n    parser = argparse.ArgumentParser(description='Converts an image to binary')\n    parser.add_argument('file', metavar='N', type=str, nargs=1,\n                        help='Input file')\n    parser.add_argument('-o', '--out', help='output .bin file')\n    parser.add_argument('-d', '--add-depth', action='store_true')\n\n    # Get file names\n    args = parser.parse_args()\n    in_path = args.file[0]\n    root, ext = os.path.splitext(in_path)\n    out_path = args.out if args.out is not None else root + \".bmap\"\n\n    # Read image\n    image = Image.open(in_path)\n    f = open(out_path, 'wb')\n\n    # Write size\n    width, height = image.size\n    f.write(struct.pack('<II', height, width))\n\n    # Write data\n    for y in xrange(height):\n        for x in xrange(width):\n            r, g, b, a = image.getpixel((x, y))\n\n            assert 0 <= r < 256\n            assert 0 <= g < 256\n            assert 0 <= b < 256\n            assert 0 <= a < 256\n\n            f.write(struct.pack('<BBBB', r, g, b, a))\n            if args.add_depth:\n                f.write(struct.pack('<f', 0x38f00000))\n\n    f.flush()\n    f.close()\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "input.s",
    "content": "@ This file is part of the Team 28 Project\n@ Licensing information can be found in the LICENSE file\n@ (C) 2014 The Team 28 Authors. All rights reserved.\n.global setup_input\n.global update_input\n.global button_pressed\n.global button_clicked\n.global button_dclicked\n.include \"ports.s\"\n\n@ ------------------------------------------------------------------------------\n@ Macros used to wait for a while\n@ ------------------------------------------------------------------------------\n.macro wait reg, x\n  mov     \\reg, \\x\n9:\n  subs    \\reg, \\reg, #1\n  bne     9b\n.endm\n\n@ ------------------------------------------------------------------------------\n@ Global variable storing the state of buttons\n@ ------------------------------------------------------------------------------\n.section .data\nbutton_pressed:  .long 0  @ button is held down\nbutton_clicked:  .long 0  @ button pressed during frame\nbutton_hclicked: .long 0  @ button pressed during last 30 frames\nbutton_dclicked: .long 0  @ button pressed twice\nbutton_lclicked: .long 0  @ Last time button was clicked\n\n.section .text\n@ ------------------------------------------------------------------------------\n@ Initialises the input module\n@ ------------------------------------------------------------------------------\nsetup_input:\n  stmfd     sp!, {r0 - r2}\n\n  @ Setup GPIO ports 10 and 11 as outputs\n  ldr       r0, =GPIO_FSEL1\n  ldr       r1, [r0]\n  ldr       r2, =0xFFFFFFC0\n  and       r1, r1, r2\n  mov       r2, #0x00000009\n  orr       r1, r1, r2\n  str       r1, [r0]\n\n  ldmfd     sp!, {r0 - r2}\n  mov       pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Updates the state machine on receipt of an interrupt\n@   GPIO 4 - data in\n@   GPIO 10 - pulse\n@   GPIO 11 - latch\n@ ------------------------------------------------------------------------------\nupdate_input:\n  stmfd     sp!, {r0 - r9, lr}\n\n  ldr       r0, =GPIO_SET0\n  ldr       r1, =GPIO_CLR0\n  ldr       r2, =GPIO_LEV0\n\n  ldr       r3, =button_pressed\n  ldr       r3, [r3]\n  ldr       r4, =button_hclicked\n  ldr       r4, [r4]\n\n  ldr       r5, =button_lclicked\n  ldr       r6, [r5]\n  tst       r4, r4\n  moveq     r6, #0\n  addne     r6, r6, #1\n  cmp       r6, #15\n  movge     r6, #0\n  movge     r7, r4\n  movlt     r7, #0\n  movge     r4, #0\n  str       r6, [r5]\n\n  ldr       r5, =button_clicked\n  str       r7, [r5]\n\n  ldr       r5, =button_dclicked\n  ldr       r5, [r5]\n  mov       r5, #0\n\n  @ Latch\n  mov       r6, #0x800\n  str       r6, [r0]\n  wait      r12, #128\n  str       r6, [r1]\n  wait      r12, #128\n\n  mov       r7, #0\n  mov       r8, #8\n  mov       r9, #1\n1:\n  @ Read button state\n  ldr       r6, [r2]\n  tst       r6, #0x10\n  bne       3f\n  orr       r7, r7, r9\n  tst       r3, r9\n  bne       3f\n  tst       r4, r9\n  orreq     r4, r4, r9        @ Click: up -> down\n  biceq     r5, r5, r9\n  bicne     r4, r4, r9\n  orrne     r5, r5, r9        @ Double click: up -> down -> up -> down\n3:\n\n  @ Pulse\n  mov       r6, #0x400\n  str       r6, [r0]\n  wait      r12, #128\n  str       r6, [r1]\n  wait      r12, #128\n\n  lsl       r9, r9, #1\n  subs      r8, r8, #1\n  bgt       1b\n\n  teq       r7, #0xFF\n  moveq     r7, #0\n\n  ldr       r0, =button_pressed\n  str       r7, [r0]\n  ldr       r0, =button_hclicked\n  str       r4, [r0]\n  ldr       r0, =button_dclicked\n  str       r5, [r0]\n\n  ldmfd     sp!, {r0 - r9, pc}\n"
  },
  {
    "path": "kernel.ld",
    "content": "SECTIONS\n{\n  /**\n   * Start address of the kernel.\n   *\n   * In QEMU, this is hardcoded to 0x100000 (64Kb).\n   * On the actual device, it can be modified, but it defaults to 0x8000 (32Kb).\n   */\n  . = 0x10000;\n\n  /**\n   * Executable code. \n   * \n   * All text segments are copied here. The first file in the object file\n   * is kernel.s and the first function in kernel.s is the kernel function\n   * which initializes everything, so it gets placed at the start address\n   * by the bootstrap code. After the text segment, padding is added in\n   * order to align the next segment to a page boundary.\n   */\n  .text :\n  {\n    *(.text)\n  }\n  . = ALIGN(0x1000);\n\n  /**\n   * Program data, all .data segments concatenated after each other. Padding\n   * is added afterwards to align the next segment to page boundary.\n   */\n  .data :\n  {\n    *(.data)\n  }\n  . = ALIGN(0x1000);\n\n  /**\n   * Stack spaces. These come after the data from the binary file,\n   * thus they are not actually present in it. They are not loaded,\n   * but the addresses are set up for them after the file. If the\n   * length of the file is x, then the stack addresses are located\n   * at the page boundary after x + 64Kb.\n   */\n  . = . + 0x800;\n  stack_svc = .;\n  . = . + 0x800;\n  stack_und = .;\n  . = . + 0x800;\n  stack_abt = .;\n  . = . + 0x800;\n  stack_irq = .;\n  . = . + 0x800;\n  stack_fiq = .;\n  . = . + 0x400000;\n  stack_sys = .;\n\n  /**\n   * Front buffer. Since this buffer is quite large, around 2Mb in size,\n   * it should not appear in the binary file since it would increase the\n   * time it takes to load the kernel. Thus, the address space it requires\n   * is only defined in the linker script and placed at the end of the\n   * kernel, after all data that is loaded from the binary file.\n   */\n  . = . + 640 * 480 * 8;\n  gfx_buffer = .;\n}\n"
  },
  {
    "path": "kernel.s",
    "content": "@ This file is part of the Team 28 Project\n@ Licensing information can be found in the LICENSE file\n@ (C) 2014 The Team 28 Authors. All rights reserved.\n.global start\n\n.include \"ports.s\"\n\n.section .text\n@ ------------------------------------------------------------------------------\n@ Entry point of the application\n@ ------------------------------------------------------------------------------\nkernel:\n  bl        setup_stack\n  bl        setup_ivt\n  bl        setup_vfp\n  bl        setup_gfx\n  bl        setup_cache\n  bl        setup_input\n  bl        setup_sound\n  b         setup_game\n\n@ ------------------------------------------------------------------------------\n@ Sets up stacks for all operating modes\n@ ------------------------------------------------------------------------------\nsetup_stack:\n  mov       r0, #0xD1       @ FIQ\n  msr       cpsr, r0\n  ldr       sp, =stack_fiq\n  mov       r0, #0xD2       @ IRQ\n  msr       cpsr, r0\n  ldr       sp, =stack_irq\n  mov       r0, #0xD7       @ ABT\n  msr       cpsr, r0\n  ldr       sp, =stack_abt\n  mov       r0, #0xDB       @ UND\n  msr       cpsr, r0\n  ldr       sp, =stack_und\n  mov       r0, #0xDF       @ SYS\n  msr       cpsr, r0\n  ldr       sp, =stack_sys\n  mov       r0, #0xD3       @ SVC\n  msr       cpsr, r0\n  ldr       sp, =stack_svc\n  mov       pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Relocates the interrupt vector table\n@ ------------------------------------------------------------------------------\nsetup_ivt:\n  ldr       r10, =ivt_start\n  ldr       r11, =0x00000000\n  ldm       r10!, {r0 - r7}\n  stm       r11!, {r0 - r7}\n  ldm       r10,  {r0 - r7}\n  stm       r11,  {r0 - r7}\n  mov       pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Enables the L1 cache\n@ ------------------------------------------------------------------------------\nsetup_cache:\n  mov       r0, #0\n  mcr       p15, 0, r0, c7, c7, 0     @ Invalidate caches\n  mcr       p15, 0, r0, c8, c7, 0     @ Invalidate TLB\n  mrc       p15, 0, r0, c1, c0, 0\n  ldr       r1, =0x1004\n  orr       r0, r0, r1                @ Set L1 enable bit\n  mcr       p15, 0, r0, c1, c0, 0\n  mov       pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Enables the vectored floating point unit\n@ ------------------------------------------------------------------------------\nsetup_vfp:\n  mrc       p15, #0, r0, c1, c0, #2\n  orr       r0, r0, #0xF00000         @ Single + double precision\n  mcr       p15, #0, r0, c1, c0, #2\n  mov       r0, #0x40000000           @ Set VFP enable bit\n  fmxr      fpexc, r0\n  mov       pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Interrupt vector table\n@\n@ On startup, this table has to be relocated to the start of memory.\n@ It contains jump to interrupt handlers.\n@ ------------------------------------------------------------------------------\nivt_start:\n.rept 8\n  ldr pc, [pc, #0x18]\n.endr\n.word handler_hang\n.word handler_undef\n.word handler_hang\n.word handler_hang\n.word handler_hang\n.word .\n.word handler_hang\n.word handler_hang\n\n@ ------------------------------------------------------------------------------\n@ Hang when something bad happens\n@ ------------------------------------------------------------------------------\nhandler_hang:\n  b         .\n\n@ ------------------------------------------------------------------------------\n@ Undefined instructions - clears FP exception bit\n@ Like pro windows devs, we put a shitton of effort\n@ into making an awesome, blue panic screeen\n@ ------------------------------------------------------------------------------\nhandler_undef:\n  @ Reset VFP\n  mov         r0, #0x40000000\n  fmxr        fpexc, r0\n\n  @ Arguments for printf\n  vstm.f32    sp!, {s0 - s31}\n  stmfd       sp!, {r0 - r12}\n  stmfd       sp!, {lr}\n\n  @ Nice blue background\n  ldr         r0, =0xFFFF0000\n  bl          gfx_clear\n\n  @ Print address\n  ldr         r0, =1f\n  mov         r1, #100\n  mov         r2, #100\n  ldr         r3, =0xFFFFFFFF\n  bl          printf\n  add         sp, sp, #4\n\n  @ Present error message\n  bl          gfx_swap\n\n  @ Hang\n  b           .\n\n1:\n  .ascii      \"VFP crashed:\\n\"\n  .ascii      \" PC: %8x\\n\"\n  .ascii      \" r0: %8x   r1: %8x   r2: %8x   r3: %8x\\n\"\n  .ascii      \" r4: %8x   r5: %8x   r6: %8x   r7: %8x\\n\"\n  .ascii      \" r8: %8x   r9: %8x  r10: %8x  r11: %8x\\n\"\n  .ascii      \" s0: %8x   s1: %8x   s2: %8x   s3: %8x\\n\"\n  .ascii      \" s4: %8x   s5: %8x   s6: %8x   s7: %8x\\n\"\n  .ascii      \" s8: %8x   s9: %8x  s10: %8x  s11: %8x\\n\"\n  .ascii      \"s12: %8x  s13: %8x  s14: %8x  s15: %8x\\n\"\n  .ascii      \"s16: %8x  s17: %8x  s18: %8x  s19: %8x\\n\"\n  .ascii      \"s20: %8x  s21: %8x  s22: %8x  s23: %8x\\n\"\n  .ascii      \"s24: %8x  s25: %8x  s26: %8x  s27: %8x\\n\"\n  .ascii      \"s28: %8x  s29: %8x  s30: %8x  s31: %8x\\n\"\n  .ascii      \"\\0\"\n  .align 2\n"
  },
  {
    "path": "math.s",
    "content": "@ This file is part of the Team 28 Project\n@ Licensing information can be found in the LICENSE file\n@ (C) 2014 The Team 28 Authors. All rights reserved.\n.global sin\n.global cos\n.global extract_frustum\n.global mat4_mul_mat4\n.global mat4_mul_vec4\n.global mat4_fmul_vec4\n.global mat4_view\n.global mat4_translate\n.global mat4_scale\n.global mat4_rot_x\n.global mat4_rot_y\n.global mat4_rot_z\n.global vec4_add\n.global vec4_sub\n.global vec4_len\n.global vec4_norm\n.global vec4_dot\n.global vec4_cross\n.global random\n.global fmod\n\n.section .text\n@ ------------------------------------------------------------------------------\n@ s1 = sin(s0)\n@ Approximation of sine\n@ Arguments:\n@   s0 - angle in radians\n@ Returns:\n@   s1 - sine of angle\n@ Clobbers:\n@   None\n@ ------------------------------------------------------------------------------\nsin:\n  stmfd         sp!, {r0}\n  vstmdb.f32    sp!, {s2 - s6}\n\n  ldr           r0, =0x40490FDB\n  vmov.f32      s4, r0            @ s4 = pi\n  ldr           r0, =0x40C90FDB\n  vadd.f32      s2, s0, s4        @ s2 = angle + pi = x\n  vmov.f32      s3, r0            @ s3 = 2 * pi = y\n\n  @ compute (angle + pi) % 2pi;\n  vdiv.f32      s5, s2, s3        @ s5 = x / y\n  vcvt.s32.f32  s5, s5\n  vcvt.f32.s32  s5, s5            @ s5 = floor(x/y)\n  vmls.f32      s2, s3, s5        @ s2 =  x - y * floor(x/y) = m\n  mov           r0, #0\n\n  vcmp.f32      s2, s3\n  fmstat\n  vmovge.f32    s2, r0\n  bge           2f\n1:@ m < y\n  vcmp.f32      s2, #0\n  fmstat\n  bge           2f                @ s2 = m\n  @ m < 0\n  vadd.f32      s2, s2, s3        @ m = m + y\n  vcmp.f32      s2, s3\n  fmstat\n  vmoveq.f32    s2, r0\n2:\n  vsub.f32      s6, s2, s4        @ s6 = ((angle + pi) % 2pi) - pi\n  ldr           r0, =0x3fa2f983   @ 4 / pi\n  vmov.f32      s1, r0\n  vmul.f32      s1, s6            @ s1 = 4 / pi * x\n\n  vcmp.f32      s6, #0            @ sin(0) = 0\n  fmstat\n  beq           3f\n\n  ldr           r0, =0x3ecf817b   @ 4 / pi ^ 2\n  vmov.f32      s2, r0\n  vmul.f32      s2, s2, s6\n  vmul.f32      s2, s2, s6\n  vmul.f32      s2, s2, s6        @ s2 = (4 * x * x * x) / pi ^ 2\n  vabs.f32      s3, s6\n  vdiv.f32      s2, s2, s3\n  vsub.f32      s1, s1, s2\n3:\n  vldmia.f32    sp!, {s2 - s6}\n  ldmfd         sp!, {r0}\n  mov           pc, lr\n\n@ ------------------------------------------------------------------------------\n@ s1 = cos(s0)\n@ Approximation of cos using sin(x) = cos(pi/2 - x)\n@ Arguments:\n@   s0 - angle in radians\n@ Returns:\n@   s1 - sine of angle\n@ Clobbers:\n@   None\n@ ------------------------------------------------------------------------------\ncos:\n  stmfd         sp!, {r0}\n  vstmdb.f32    sp!, {s2 - s6}\n\n  ldr           r0, =0x3FC90FDB\n  vmov.f32      s4, r0            @ s4 = pi/2\n  vsub.f32      s6, s4, s0        @ angle = pi/2 - angle\n\n  ldr           r0, =0x40490FDB\n  vmov.f32      s4, r0            @ s4 = pi\n  ldr           r0, =0x40C90FDB\n  vadd.f32      s2, s6, s4        @ s2 = angle + pi = x\n  vmov.f32      s3, r0            @ s3 = 2 * pi = y\n\n  @ compute (angle + pi) % 2pi;\n  vdiv.f32      s5, s2, s3        @ s5 = x / y\n  vcvt.s32.f32  s5, s5\n  vcvt.f32.s32  s5, s5            @ s5 = floor(x/y)\n  vmls.f32      s2, s3, s5        @ s2 =  x - y * floor(x/y) = m\n  mov           r0, #0\n\n  vcmp.f32      s2, s3\n  fmstat\n  blt           1f\n  vmov.f32      s2, r0            @ s2 = 0\n  b             2f\n1: @ m < y\n  vcmp.f32      s2, #0\n  fmstat\n  bge           2f                @ s2 = m\n  @ m < 0\n  vadd.f32      s2, s2, s3        @ m = m + y\n  vcmp.f32      s2, s3\n  fmstat\n  vmoveq.f32    s2, r0\n2:\n  vsub.f32      s6, s2, s4        @ s6 = ((angle + pi) % 2pi) - pi\n  ldr           r0, =0x3fa2f983   @ 4 / pi\n  vmov.f32      s1, r0\n  vmul.f32      s1, s6            @ s1 = 4 / pi * x\n\n  vcmp.f32      s6, #0\n  fmstat\n  beq           3f\n\n  ldr           r0, =0x3ecf817b   @ 4 / pi ^ 2\n  vmov.f32      s2, r0\n  vmul.f32      s2, s2, s6\n  vmul.f32      s2, s2, s6\n  vmul.f32      s2, s2, s6        @ s2 = (4 * x * x * x) / pi ^ 2\n  vabs.f32      s3, s6\n  vdiv.f32      s2, s2, s3\n  vsub.f32      s1, s1, s2\n3:\n  vldmia.f32    sp!, {s2 - s6}\n  ldmfd         sp!, {r0}\n  mov           pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Multiplies two matrices together\n@ r2 = r1 * r0\n@ Arguments:\n@   r0 - location of first matrix\n@   r1 - location of second matrix\n@   r2 - output matrix address\n@ Return values:\n@   none\n@ Clobbers:\n@   s0 - s23\n@ ------------------------------------------------------------------------------\nmat4_mul_mat4:\n  stmfd     sp!, {r3, r4}\n\n  vldm.f32  r0, {s0 - s15}\n\n  mov       r4, #4\n1:\n  vldm.f32  r1!, {s16 - s19}\n\n  vmul.f32  s20,  s0, s16\n  vmla.f32  s20,  s4, s17\n  vmla.f32  s20,  s8, s18\n  vmla.f32  s20, s12, s19\n\n  vmul.f32  s21,  s1, s16\n  vmla.f32  s21,  s5, s17\n  vmla.f32  s21,  s9, s18\n  vmla.f32  s21, s13, s19\n\n  vmul.f32  s22,  s2, s16\n  vmla.f32  s22,  s6, s17\n  vmla.f32  s22, s10, s18\n  vmla.f32  s22, s14, s19\n\n  vmul.f32  s23,  s3, s16\n  vmla.f32  s23,  s7, s17\n  vmla.f32  s23, s11, s18\n  vmla.f32  s23, s15, s19\n\n  vstm.f32  r2!, {s20 - s23}\n\n  subs      r4, #1\n  bne       1b\n\n  @ Restore pointers\n  sub       r1, #64\n  sub       r2, #64\n\n  ldmfd     sp!, {r3, r4}\n  mov       pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Multiplies a matrix with a vector\n@ Arguments:\n@   r0 - location of the matrix\n@   r1 - location of the vector\n@   r2 - output vector address\n@ Returns:\n@   none\n@ Clobbers:\n@   s0 - s19\n@ ------------------------------------------------------------------------------\nmat4_mul_vec4:\n  vldm.f32  r0, {s0 - s15}\n  vldm.f32  r1, {s16 - s19}\n\n  vmul.f32  s20,  s0, s16\n  vmul.f32  s21,  s1, s16\n  vmul.f32  s22,  s2, s16\n  vmul.f32  s23,  s3, s16\n  vmla.f32  s20,  s4, s17\n  vmla.f32  s21,  s5, s17\n  vmla.f32  s22,  s6, s17\n  vmla.f32  s23,  s7, s17\n  vmla.f32  s20,  s8, s18\n  vmla.f32  s21,  s9, s18\n  vmla.f32  s22, s10, s18\n  vmla.f32  s23, s11, s18\n  vmla.f32  s20, s12, s19\n  vmla.f32  s21, s13, s19\n  vmla.f32  s22, s14, s19\n  vmla.f32  s23, s15, s19\n\n  vstm.f32  r2, {s20 - s23}\n\n  mov       pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Multiplies a matrix with a vector in registers\n@ Arguments:\n@    s0 - s15: matrix\n@   s16 - s19: vector\n@   s20 - s23: output\n@ Returns:\n@   none\n@ Clobbers:\n@   s0 - s19\n@ ------------------------------------------------------------------------------\nmat4_fmul_vec4:\n  vmul.f32  s20,  s0, s16\n  vmul.f32  s21,  s1, s16\n  vmul.f32  s22,  s2, s16\n  vmul.f32  s23,  s3, s16\n  vmla.f32  s20,  s4, s17\n  vmla.f32  s21,  s5, s17\n  vmla.f32  s22,  s6, s17\n  vmla.f32  s23,  s7, s17\n  vmla.f32  s20,  s8, s18\n  vmla.f32  s21,  s9, s18\n  vmla.f32  s22, s10, s18\n  vmla.f32  s23, s11, s18\n  vmla.f32  s20, s12, s19\n  vmla.f32  s21, s13, s19\n  vmla.f32  s22, s14, s19\n  vmla.f32  s23, s15, s19\n  mov       pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Computes a view matrix\n@ Arguments:\n@   r0 - eye\n@   r1 - at\n@   r2 - up\n@   r3 - destination matrix\n@ Returns:\n@   none\n@ Clobbers:\n@   s0 - s15\n@ ------------------------------------------------------------------------------\nmat4_view:\n  stmfd     sp!, {r4}\n\n  vldm.f32  r0, {s0 - s3}   @ eye{s0, s1, s2}\n  vldm.f32  r1, {s3 - s6}   @ at{s3, s4, s5}\n  vldm.f32  r2, {s6 - s9}   @ up{s6, s7, s8}\n\n  @ z{s9, s10, s11} = norm(eye - at)\n  vsub.f32  s9, s0, s3\n  vsub.f32  s10, s1, s4\n  vsub.f32  s11, s2, s5\n  vmul.f32  s12, s9, s9\n  vmla.f32  s12, s10, s10\n  vmla.f32  s12, s11, s11\n  vsqrt.f32 s12, s12\n  vdiv.f32  s9, s9, s12\n  vdiv.f32  s10, s10, s12\n  vdiv.f32  s11, s11, s12\n\n  @ x{s3, s4, s5} = norm(cross(up, z))\n  vmul.f32  s3, s7, s11\n  vmls.f32  s3, s8, s10\n  vmul.f32  s4, s8, s9\n  vmls.f32  s4, s6, s11\n  vmul.f32  s5, s6, s10\n  vmls.f32  s5, s7, s9\n  vmul.f32  s12, s3, s3\n  vmla.f32  s12, s4, s4\n  vmla.f32  s12, s5, s5\n  vsqrt.f32 s12, s12\n  vdiv.f32  s3, s3, s12\n  vdiv.f32  s4, s4, s12\n  vdiv.f32  s5, s5, s12\n\n  @ y{s6, s7, s8} = cross(z, x)\n  vmul.f32  s6, s10, s5\n  vmls.f32  s6, s11, s4\n  vmul.f32  s7, s11, s3\n  vmls.f32  s7, s9, s5\n  vmul.f32  s8, s9, s4\n  vmls.f32  s8, s10, s3\n\n  mov       r4, #0\n  vmov.f32  s15, r4\n\n  @ First column\n  vmov.f32  s12, s3\n  vmov.f32  s13, s6\n  vmov.f32  s14, s9\n  vstm.f32  r3!, {s12 - s15}\n\n  @ Second column\n  vmov.f32  s12, s4\n  vmov.f32  s13, s7\n  vmov.f32  s14, s10\n  vstm.f32  r3!, {s12 - s15}\n\n  @ Third column\n  vmov.f32  s12, s5\n  vmov.f32  s13, s8\n  vmov.f32  s14, s11\n  vstm.f32  r3!, {s12 - s15}\n\n  @ Fourth column\n  vmov.f32  s12, s15\n  vmls.f32  s12, s0, s3\n  vmls.f32  s12, s1, s4\n  vmls.f32  s12, s2, s5\n  vmov.f32  s13, s15\n  vmls.f32  s13, s0, s6\n  vmls.f32  s13, s1, s7\n  vmls.f32  s13, s2, s8\n  vmov.f32  s14, s15\n  vmls.f32  s14, s0, s9\n  vmls.f32  s14, s1, s10\n  vmls.f32  s14, s2, s11\n  mov       r4, #0x3f800000\n  vmov.f32  s15, r4\n\n  vstm.f32  r3, {s12 - s15}\n\n  sub       r3, r3, #48\n  ldmfd     sp!, {r4}\n  mov       pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Builds a translation matrix\n@ Arguments:\n@   r0 - matrix\n@   s0 - s3: translation\n@ Returns:\n@   none\n@ Clobbers:\n@   none\n@ ------------------------------------------------------------------------------\nmat4_translate:\n  vstr.f32    s0, [r0, #48]\n  vstr.f32    s1, [r0, #52]\n  vstr.f32    s2, [r0, #56]\n  mov         pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Builds a scaling matrix\n@ Arguments:\n@   r0 - matrix\n@   s0 - s3: translation\n@ Returns:\n@   none\n@ Clobbers:\n@   none\n@ ------------------------------------------------------------------------------\nmat4_scale:\n  vstr.f32    s0, [r0]\n  vstr.f32    s1, [r0, #20]\n  vstr.f32    s2, [r0, #40]\n  mov         pc, lr\n\n\n@ ------------------------------------------------------------------------------\n@ Creates a rotation matrix around X\n@ Arguments:\n@   r0 - matrix\n@   s0 - angle\n@ Returns:\n@   none\n@ Clobbers:\n@   none\n@ ------------------------------------------------------------------------------\nmat4_rot_x:\n  stmfd       sp!, {lr}\n\n  bl          sin\n  vstr.f32    s1, [r0, #24]\n  vneg.f32    s1, s1\n  vstr.f32    s1, [r0, #36]\n  bl          cos\n  vstr.f32    s1, [r0, #20]\n  vstr.f32    s1, [r0, #40]\n\n  ldmfd       sp!, {pc}\n\n@ ------------------------------------------------------------------------------\n@ Creates a rotation matrix\n@ Arguments:\n@   r0 - matrix\n@   s0 - angle\n@ Returns:\n@   none\n@ Clobbers:\n@   none\n@ ------------------------------------------------------------------------------\nmat4_rot_y:\n  stmfd       sp!, {lr}\n\n  bl          sin\n  vstr.f32    s1, [r0, #32]\n  vneg.f32    s1, s1\n  vstr.f32    s1, [r0, #8]\n  bl          cos\n  vstr.f32    s1, [r0, #0]\n  vstr.f32    s1, [r0, #40]\n\n  ldmfd       sp!, {pc}\n\n@ ------------------------------------------------------------------------------\n@ Creates a rotation matrix around Z\n@ Arguments:\n@   r0 - matrix\n@   s0 - angle\n@ Returns:\n@   none\n@ Clobbers:\n@   none\n@ ------------------------------------------------------------------------------\nmat4_rot_z:\n  stmfd       sp!, {lr}\n\n  bl          sin\n  vstr.f32    s1, [r0, #4]\n  vneg.f32    s1, s1\n  vstr.f32    s1, [r0, #16]\n  bl          cos\n  vstr.f32    s1, [r0, #0]\n  vstr.f32    s1, [r0, #20]\n\n  ldmfd       sp!, {pc}\n\n@ ------------------------------------------------------------------------------\n@ Computes a 3x3 determinant\n@ Arguments:\n@   s23 - s31: coefficients\n@ Returns:\n@   s22 - determinant\n@ Clobbers:\n@   s21\n@ ------------------------------------------------------------------------------\nmat3_fdet:\n  vmul.f32    s21, s27, s31\n  vmls.f32    s21, s28, s30\n  vmul.f32    s22, s23, s21\n\n  vmul.f32    s21, s28, s29\n  vmls.f32    s21, s26, s31\n  vmla.f32    s22, s24, s21\n\n  vmul.f32    s21, s26, s30\n  vmls.f32    s21, s27, s29\n  vmla.f32    s22, s25, s21\n\n  mov         pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Adds two 4D vectors\n@ Arguments:\n@   r0 - location of first vector\n@   r1 - location of second vector\n@   r2 - location of destination\n@ Return values:\n@   None\n@ Clobbers:\n@   s0 - s11\n@ ------------------------------------------------------------------------------\nvec4_add:\n  vldm.f32  r0, {s0 - s3}\n  vldm.f32  r1, {s4 - s7}\n\n  vadd.f32  s8, s0, s4\n  vadd.f32  s9, s1, s5\n  vadd.f32  s10, s2, s6\n  vadd.f32  s11, s3, s7\n\n  vstm.f32  r2, {s8 - s11}\n  mov       pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Subtracts a vector from another\n@ Arguments:\n@   r0 - location of first vector\n@   r1 - location of second vector\n@   r2 - location of destination\n@ Return values:\n@   None\n@ Clobbers\n@   s0 - s11\n@ ------------------------------------------------------------------------------\nvec4_sub:\n  vldm.f32  r0, {s0 - s3}\n  vldm.f32  r1, {s4 - s7}\n\n  vsub.f32  s8, s0, s4\n  vsub.f32  s9, s1, s5\n  vsub.f32  s10, s2, s6\n  vsub.f32  s11, s3, s7\n\n  vstm.f32  r2, {s8 - s11}\n  mov       pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Computes the length of a vector\n@ Arguments:\n@   r0 - location of first vector\n@ Return values:\n@   s0 - length of the vector\n@ Clobers:\n@   s1 - s3\n@ ------------------------------------------------------------------------------\nvec4_len:\n  vldm.f32  r0, {s0 - s3}\n\n  vmul.f32  s0, s0, s0\n  vmla.f32  s0, s1, s1\n  vmla.f32  s0, s2, s2\n  vsqrt.f32 s0, s0\n\n  mov       pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Computes the normalised vector(unit vector) of the given vector\n@ Arguments:\n@   r0 - location of the vector\n@   r1 - location of the destination\n@ Return values:\n@   None\n@ Clobbers\n@   s0 - s4\n@ ------------------------------------------------------------------------------\nvec4_norm:\n  vldm.f32  r0, {s0 - s3}\n\n  vmul.f32  s4, s0, s0\n  vmla.f32  s4, s1, s2\n  vmla.f32  s4, s2, s2\n  vsqrt.f32 s4, s4      @ s4 = |v|\n\n  vdiv.f32  s0, s0, s4\n  vdiv.f32  s1, s1, s4\n  vdiv.f32  s2, s2, s4\n\n  vstm.f32  r1, {s0 - s3}\n  mov       pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Computes the dot product of two vectors\n@ Arguments:\n@   r0 - location of the first vector\n@   r1 - location of the second vector\n@ Return values:\n@   s0 - dot product\n@ Clobbers\n@   s0 - s6\n@ ------------------------------------------------------------------------------\nvec4_dot:\n  vldm.f32  r0, {s1 - s3}\n  vldm.f32  r1, {s4 - s6}\n\n  vmul.f32  s0, s1, s4\n  vmla.f32  s0, s2, s5\n  vmla.f32  s0, s3, s6\n\n  mov       pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Computes the cross product of two vectors\n@ Arguments:\n@   r0 - location of the first vector\n@   r1 - location of the second vector\n@   r2 - location of the destination\n@ Return values:\n@   None\n@ Clobbers:\n@   s0 - s10\n@ ------------------------------------------------------------------------------\nvec4_cross:\n  stmfd     sp!, {r3}\n\n  vldm.f32  r0, {s0 - s3}        @ s0 = x1; s1 = y1; s2 = z1\n  vldm.f32  r1, {s3 - s6}        @ s3 = x2; s4 = y2; s5 = z2\n\n  vmul.f32  s6, s1, s5           @ s6 = y1 * z2\n  vmls.f32  s6, s4, s2           @ s6 = s6 - (y2 * z1)\n  vmul.f32  s7, s3, s2           @ s7 = x2 * z1\n  vmls.f32  s7, s0, s5           @ s7 = s7 - (x1 * z2)\n  vmul.f32  s8, s0, s4           @ s8 = x1 * y2\n  vmls.f32  s8, s1, s3           @ s8 = s8 - (x2 * y1)\n\n  mov       r3, #0\n  vmov.f32  s9, r3\n\n  vstm.f32  r2, {s6 - s9}\n\n  ldmfd     sp!, {r3}\n  mov       pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Floating point modulo\n@ Arguments:\n@   s0 - x\n@   s1 - y\n@ Returns:\n@   s2 - x % y\n@ Clobbers:\n@   None\n@ ------------------------------------------------------------------------------\nfmod:\n  stmfd         sp!, {r0}\n  vstmdb.f32    sp!, {s3}\n\n  vcmp.f32      s1, #0\n  fmstat\n  beq           4f\n\n  mov           r0, #0\n  vdiv.f32      s3, s0, s1        @ s3 = x / y\n  vcvt.s32.f32  s3, s3\n  vcvt.f32.s32  s3, s3            @ s3 = floor(x/y)\n  vmls.f32      s0, s1, s3        @ s0 = x - y * floor(x/y) = m\n\n  vcmp.f32      s1, #0\n  fmstat\n  ble           2f\n  vcmp.f32      s0, s1\n  fmstat\n  blt           1f\n  vmov.f32      s0, r0\n  b             4f                @ s0 = 0\n1:\n  vcmp.f32      s0, #0\n  fmstat\n  bge           4f                @ s0 = m\n  vadd.f32      s0, s0, s1        @ s0 = m + y\n  vcmp.f32      s0, s1\n  vmoveq.f32    s0, r0            @ s0 = 0\n  b             4f\n2:\n  vcmp.f32      s0, s1\n  fmstat\n  bgt           3f\n  vmov.f32      s0, r0\n  b             4f                @ s0 = 0\n3:\n  vcmp.f32      s0, #0\n  fmstat\n  ble           4f                @ s0 = m\n  vadd.f32      s0, s0, s1        @ s0 = m + y\n  vcmp.f32      s0, s1\n  fmstat\n  vmoveq.f32    s0, r0            @ s0 = 0\n4:\n  vmov.f32      s2, s0            @ s2 = s0\n\n  vldmia.f32    sp!, {s3}\n  ldmfd         sp!, {r0}\n  mov           pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Computes the intersection point of three planes using Kramer's rule\n@ Arguments:\n@   s0 - s3: (a1, b1, c1, d1)\n@   s4 - s7: (a1, b1, c1, d1)\n@   s8 - s11: (a1, b1, c1, d1)\n@ Returns:\n@   s12 - s14: (x, y, z)\n@ Clobbers:\n@   s15, s22 - s31\n@ ------------------------------------------------------------------------------\ninsersect_planes:\n  mov       r11, lr\n\n  vmov.f32  s23, s0\n  vmov.f32  s24, s4\n  vmov.f32  s25, s8\n  vmov.f32  s26, s1\n  vmov.f32  s27, s5\n  vmov.f32  s28, s9\n  vmov.f32  s29, s2\n  vmov.f32  s30, s6\n  vmov.f32  s31, s10\n  bl        mat3_fdet\n  vmov.f32  s15, s22          @ det\n\n  vmov.f32  s23, s3\n  vmov.f32  s24, s7\n  vmov.f32  s25, s11\n  bl        mat3_fdet\n  vdiv.f32  s12, s22, s15     @ x\n  vneg.f32  s12, s12\n\n  vmov.f32  s23, s0\n  vmov.f32  s24, s4\n  vmov.f32  s25, s8\n  vmov.f32  s26, s3\n  vmov.f32  s27, s7\n  vmov.f32  s28, s11\n  bl        mat3_fdet\n  vdiv.f32  s13, s22, s15     @ y\n  vneg.f32  s13, s13\n\n  vmov.f32  s26, s1\n  vmov.f32  s27, s5\n  vmov.f32  s28, s9\n  vmov.f32  s29, s3\n  vmov.f32  s30, s7\n  vmov.f32  s31, s11\n  bl        mat3_fdet\n  vdiv.f32  s14, s22, s15    @ z\n  vneg.f32  s14, s14\n\n  mov       pc, r11\n\n@ ------------------------------------------------------------------------------\n@ Extracts clip planes from a view-projection matrix\n@ Arguments:\n@   r0 - matrix\n@   r1 - frustum\n@ Returns:\n@   8 vertices on the stack\n@ Clobbers:\n@   s0 - s31\n@ ------------------------------------------------------------------------------\nextract_frustum:\n  mov           r12, lr\n  add           r2, r1, #96\n\n  vldr.f32      s16, [r0, #12]\n  vldr.f32      s17, [r0, #28]\n  vldr.f32      s18, [r0, #44]\n  vldr.f32      s19, [r0, #60]\n\n  bl            load_near\n  vstmia.f32    r2!, {s0 - s3}\n  bl            load_left\n  vstmia.f32    r2!, {s8 - s11}\n  bl            load_bottom\n  vstmia.f32    r2!, {s4 - s7}\n\n  bl            insersect_planes\n  vstmia.f32    r1!, {s12 - s14}    @ near-left-bottom\n  bl            load_top\n  bl            insersect_planes\n  vstmia.f32    r1!, {s12 - s14}    @ near-left-top\n  bl            load_right\n  bl            insersect_planes\n  vstmia.f32    r1!, {s12 - s14}    @ near-right-top\n  bl            load_bottom\n  bl            insersect_planes\n  vstmia.f32    r1!, {s12 - s14}    @ near-right-bottom\n  bl            load_far\n  vstmia.f32    r2!, {s0 - s3}\n  bl            insersect_planes\n  vstmia.f32    r1!, {s12 - s14}    @ far-right-bottom\n  bl            load_left\n  bl            insersect_planes\n  vstmia.f32    r1!, {s12 - s14}    @ far-left-bottom\n  bl            load_top\n  vstmia.f32    r2!, {s4 - s7}\n  bl            insersect_planes\n  vstmia.f32    r1!, {s12 - s14}    @ far-left-top\n  bl            load_right\n  vstmia.f32    r2!, {s8 - s11}\n  bl            insersect_planes\n  vstmia.f32    r1!, {s12 - s14}    @ far-right-top\n\n  mov           pc, r12\n\n@ ------------------------------------------------------------------------------\n@ Loads near plane into registers\n@ ------------------------------------------------------------------------------\nload_near:\n  vldr.f32      s12, [r0, #8]\n  vldr.f32      s13, [r0, #24]\n  vldr.f32      s14, [r0, #40]\n  vldr.f32      s15, [r0, #56]\n  vadd.f32      s0, s16, s12\n  vadd.f32      s1, s17, s13\n  vadd.f32      s2, s18, s14\n  vadd.f32      s3, s19, s15\n  mov           pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Loads far plane into registers\n@ ------------------------------------------------------------------------------\nload_far:\n  vldr.f32      s12, [r0, #8]\n  vldr.f32      s13, [r0, #24]\n  vldr.f32      s14, [r0, #40]\n  vldr.f32      s15, [r0, #56]\n  vsub.f32      s0, s16, s12\n  vsub.f32      s1, s17, s13\n  vsub.f32      s2, s18, s14\n  vsub.f32      s3, s19, s15\n  mov           pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Loads bottom plane into registers\n@ ------------------------------------------------------------------------------\nload_bottom:\n  vldr.f32      s12, [r0, #4]\n  vldr.f32      s13, [r0, #20]\n  vldr.f32      s14, [r0, #36]\n  vldr.f32      s15, [r0, #52]\n  vadd.f32      s4, s16, s12\n  vadd.f32      s5, s17, s13\n  vadd.f32      s6, s18, s14\n  vadd.f32      s7, s19, s15\n  mov           pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Loads top plane into registers\n@ ------------------------------------------------------------------------------\nload_top:\n  vldr.f32      s12, [r0, #4]\n  vldr.f32      s13, [r0, #20]\n  vldr.f32      s14, [r0, #36]\n  vldr.f32      s15, [r0, #52]\n  vsub.f32      s4, s16, s12\n  vsub.f32      s5, s17, s13\n  vsub.f32      s6, s18, s14\n  vsub.f32      s7, s19, s15\n  mov           pc, lr\n\n\n@ ------------------------------------------------------------------------------\n@ Loads top plane into registers\n@ ------------------------------------------------------------------------------\nload_left:\n  vldr.f32      s12, [r0, #0]\n  vldr.f32      s13, [r0, #16]\n  vldr.f32      s14, [r0, #32]\n  vldr.f32      s15, [r0, #48]\n  vadd.f32      s8, s16, s12\n  vadd.f32      s9, s17, s13\n  vadd.f32      s10, s18, s14\n  vadd.f32      s11, s19, s15\n  mov           pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Loads top plane into registers\n@ ------------------------------------------------------------------------------\nload_right:\n  vldr.f32      s12, [r0, #0]\n  vldr.f32      s13, [r0, #16]\n  vldr.f32      s14, [r0, #32]\n  vldr.f32      s15, [r0, #48]\n  vsub.f32      s8, s16, s12\n  vsub.f32      s9, s17, s13\n  vsub.f32      s10, s18, s14\n  vsub.f32      s11, s19, s15\n  mov           pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Generates a random number using a linear shift register\n@ Arguments:\n@   none\n@ Returns:\n@   r0 - random number\n@ Clobbers:\n@   none\n@ ------------------------------------------------------------------------------\nrandom:\n  stmfd         sp!, {r1 - r2}\n\n  ldr           r1, =1f\n  ldr           r0, [r1]\n\n  mov           r2, r0\n  eor           r2, r2, r0, lsr #2\n  eor           r2, r2, r0, lsr #3\n  eor           r2, r2, r0, lsr #5\n  and           r2, r2, #1\n  lsr           r0, r0, #1\n  orr           r0, r0, r2, lsl #15\n\n  str           r0, [r1]\n\n  ldmfd         sp!, {r1 - r2}\n  mov           pc, lr\n1:\n  .long         0xACE1\n"
  },
  {
    "path": "mbox.s",
    "content": "@ This file is part of the Team 28 Project\n@ Licensing information can be found in the LICENSE file\n@ (C) 2014 The Team 28 Authors. All rights reserved.\n.global mbox_read\n.global mbox_write\n\n.include \"ports.s\"\n\n.section .text\n@ ------------------------------------------------------------------------------\n@ Reads a value from the mailbox\n@\n@ Arguments:\n@   r0 - Channel\n@ Returns:\n@   none\n@ Clobbers:\n@   r1 - Return data\n@ ------------------------------------------------------------------------------\nmbox_read:\n  stmfd     sp!, {r2 - r4}\n  ldr       r2, =MBOX_BASE\n  eor       r4, r4, r4\n\n1:\n  @ Timeout\n  add       r4, #1\n  tst       r4, #0x80000\n  mvnne     r1, #1\n  bne       2f\n\n  @ Flush cache\n  mcr       p15, #0, r1, c7, c14, #0\n\n  @ Check for ready flag\n  ldr       r3, [r2, #0x18]\n  tst       r3, #0x40000000\n  bne       1b\n\n  @ Read in data (dmb first)\n  mcr       p15, #0, r1, c7, c10, #5\n  ldr       r3, [r2, #0x00]\n\n  @ Check if the channel is right\n  and       r1, r3, #0x0F\n  teq       r0, r1\n  bne       1b\n\n  @ Extract data\n  bic       r1, r3, #0xF\n2:\n  ldmfd     sp!, {r2 - r4}\n  mov       pc, lr\n\n\n@ ------------------------------------------------------------------------------\n@ Writes a value to the mailbox\n@\n@ Arguments:\n@   r0 - channel\n@   r1 - data\n@ Returns:\n@   none\n@ Clobbers:\n@   none\n@ ------------------------------------------------------------------------------\nmbox_write:\n  stmfd     sp!, {r1 - r4}\n  ldr       r2, =MBOX_BASE\n  eor       r4, r4\n\n  @ Wait until mailbox is ready\n1:\n  add       r4, #1\n  tst       r4, #0x80000\n  bne       2f\n\n  @ Flush cache\n  mcr       p15, #0, r3, c7, c14, #0\n\n  ldr       r3, [r2, #0x18]\n  tst       r3, #0x80000000\n  bne       1b\n\n  @ Send message (dmb first)\n  mcr       p15, #0, r3, c7, c10, #5\n  orr       r1, r0, r1\n  str       r1, [r2, #0x20]\n\n2:\n  ldmfd     sp!, {r1 - r4}\n  mov       pc, lr\n"
  },
  {
    "path": "objects.s",
    "content": "@ This file is part of the Team 28 Project\n@ Licensing information can be found in the LICENSE file\n@ (C) 2014 The Team 28 Authors. All rights reserved.\n.global draw_rocks\n.global reset_objects\n.global OBJECT_COUNT\n.global object_list\n\n.include \"ports.s\"\n\n.section .data\n@ ------------------------------------------------------------------------------\n@ Obstacles\n@ ------------------------------------------------------------------------------\n.equ             OBJECT_COUNT, 35\n.equ             ROCK_LIVES, 3\nobject_spawn:      .long 0xfffff  @ Frame number of the last spawned rock\nobject_list:\n  .rept OBJECT_COUNT\n    .float 0.0, 0.0, 0.0        @ Position (x, y, z)\n    .float 1.5                  @ Movement speed\n    .float 0.0                  @ Rotation\n    .long  0                    @ Type\n    .long  ROCK_LIVES           @ Lives\n  .endr\n\n.section .text\n@ ------------------------------------------------------------------------------\n@ Renders the rocks on the sides\n@ ------------------------------------------------------------------------------\ndraw_rocks:\n  stmfd       sp!, {lr}\n\n  bl          update_rocks\n  bl          sort_objects\n\n  ldr         r12, =OBJECT_COUNT\n  ldr         r11, =object_list\n1:\n  vldm.f32    r11!, {s0 - s6}\n  ldr         r0, =0xc1200000     @ -7.0\n  vmov.f32    s7, r0\n  vcmp.f32    s2, s7\n  fmstat\n  bllt        draw_object\n  subs        r12, r12, #1\n  bne         1b\n\n  ldmfd       sp!, {pc}\n\n@ ------------------------------------------------------------------------------\n@ Updates the position of the rocks\n@ ------------------------------------------------------------------------------\nupdate_rocks:\n  stmfd       sp!, {lr}\n\n  ldr         r12, =OBJECT_COUNT\n  ldr         r11, =object_list\n\n1:\n  vldm.f32    r11, {s0 - s6}\n\n  @ Check whether rock is 'live'\n  ldr         r0, =0xc1200000\n  vmov.f32    s7, r0\n  vcmp.f32    s2, s7\n  fmstat\n  blt         4f\n\n  @ Rock moving out of bound\n  ldr         r2, [r11, #8]\n  tst         r2, r2\n  beq         5f\n\n  @ Clear depth\n  mov         r1, #0\n  vmov.f32    s2, r1\n\n  @ Test for collision with player\n  ldr         r0, =player_pos\n  vldm.f32    r0, {s30 - s31}\n  vsub.f32    s7, s0, s30\n  vabs.f32    s7, s7\n  vsub.f32    s8, s1, s31\n  ldr         r0, =0x40000000\n  vmov.f32    s9, r0\n  vsub.f32    s8, s8, s9\n  vabs.f32    s8, s8\n  ldr         r0, =0x3fe00000\n  vmov.f32    s9, r0\n  vcmp.f32    s7, s9\n  fmstat\n  bgt         3f\n  vcmp.f32    s8, s9\n  fmstat\n  bgt         3f\n\n  vmov.f32    r0, s6\n  tst         r0, #0x1E\n  beq         2f\n\n  @ Decrease health\n  ldr         r0, =player_rolling\n  ldr         r0, [r0]\n  tst         r0, r0\n  bne         5f\n\n  mov         r0, #20\n  bl          player_damage\n  b           5f\n2:\n  tst         r0, #1\n  ldreq       r0, =player_wrenches\n  ldrne       r0, =player_rockets\n  ldr         r1, [r0]\n  add         r1, r1, #1\n  cmp         r1, #4\n  movge       r1, #3\n  str         r1, [r0]\n  bllt        snd_play_pickup\n  b           5f\n3:\n  ldr         r0, =player_score     @ Add to score\n  ldr         r1, [r0]\n  add         r1, r1, #5\n  str         r1, [r0]\n5:\n  @ Spawn a new rock once every 30 frames\n  ldr         r0, =object_spawn\n  ldr         r1, [r0]\n  add         r1, r1, #1\n  cmp         r1, #0x20\n  movge       r1, #0\n  blge        spawn_object\n  str         r1, [r0]\n\n  ldr         r0, =enemy_count\n  ldr         r0, [r0]\n  tst         r0, r0\n  movne       r0, #0\n  vmovne.f32  s2, r0\n\n  vstm.f32    r11!, {s0 - s6}\n  b           5f\n4:\n  @ Check whether object collided with a bullet\n  ldr         r0, =0x40000000\n  vmov.f32    s31, r0\n  bl          collide_bullets\n  tst         r0, r0\n  bne         6f\n\n  vmov.f32    r0, s5\n  subs        r0, r0, #1\n  vmov.f32    s5, r0\n  vmoveq      s2, r0\n  beq         3b\n\n6:\n  @ Updates position\n  ldr         r0, =player_speed\n  vldr.f32    s9, [r0]\n  ldr         r0, =0x3dcccccd\n  vmov.f32    s8, r0\n  vadd.f32    s2, s2, s3\n  vadd.f32    s2, s2, s9\n  vmov.f32    r0, s6\n  tst         r0, #0x1E\n  vaddne.f32  s4, s4, s8\n  vstm.f32    r11!, {s0 - s6}\n5:\n  subs        r12, r12, #1\n  bne         1b\n\n  ldmfd       sp!, {pc}\n\n@ ------------------------------------------------------------------------------\n@ Sorts rocks by their z coordinate\n@ ------------------------------------------------------------------------------\nsort_objects:\n  ldr         r12, =OBJECT_COUNT\n  sub         r10, r12, #1\n  ldr         r11, =object_list\n  ldr         r4,  =28 @ size of rock in bytes\n\n  ldr         r5, =0x0 @ i\n1:\n  @ outer loop start\n  ldr         r6, =0x0 @ j\n2:\n  @ inner loop start\n  @ Calculate address of j and j+1\n  mla         r7, r6, r4, r11\n  add         r8, r7, r4\n\n  @ Compare Z coordinates\n  ldr         r0, [r7, #8]\n  vmov.f32    s0, r0\n  ldr         r1, [r8, #8]\n  vmov.f32    s1, r1\n  vcmp.f32    s0, s1\n  fmstat\n  ble         3f\n\n  @ Swap\n  vldm.f32    r7, {s18 - s24}\n  vldm.f32    r8, {s25 - s31}\n  vstm.f32    r8, {s18 - s24}\n  vstm.f32    r7, {s25 - s31}\n\n3: @ inner loop end\n  add         r6, r6, #1\n  cmp         r6, r10\n  blt         2b\n\n4: @ outer loop end\n  add         r5, r5, #1\n  sub         r10, r10, #1\n  cmp         r5, r12\n  blt         1b\n\n  mov         pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Spawns a new rock\n@ Arguments:\n@   none\n@ Returns:\n@   s0 - s4: rock attributes\n@ Clobbers:\n@   none\n@ ------------------------------------------------------------------------------\nspawn_object:\n  stmfd       sp!, {r0 - r1, lr}\n\n  @ Randomize x in range [-8.5, 8.5]\n  bl          random\n  and         r1, r0, #0xFF\n  sub         r1, r1, #0x7F\n  vmov.f32    s8, r1\n  fsitos      s8, s8\n  ldr         r1, =0x41400000\n  vmov.f32    s9, r1\n  vdiv.f32    s0, s8, s9\n\n  @ Randomize y in range [-2.8, 5.2]\n  bl          random\n  and         r1, r0, #0xFF\n  sub         r1, r1, #0x7F\n  vmov.f32    s8, r1\n  fsitos      s8, s8\n  ldr         r1, =0x41f00000\n  vmov.f32    s9, r1\n  vdiv.f32    s1, s8, s9\n\n  @ Set z to -300.0\n  ldr         r0, =0xc3960000\n  vmov.f32    s2, r0\n\n  @ Reset rotation\n  ldr         r0, =0x00000000\n  vmov.f32    s4, r0\n\n  @ Randomize type\n  bl          random\n  and         r0, #0x1F\n  vmov.f32    s6, r0\n\n  @ Lives for rocks\n  ldr         r0, =ROCK_LIVES\n  vmov.f32    s5, r0\n\n  ldmfd       sp!, {r0 - r1, pc}\n\n@ ------------------------------------------------------------------------------\n@ Draws an object\n@\n@ Arguments:\n@   s0 - s4: Rock attributes\n@ Returns:\n@   none\n@ Clobbers:\n@  s0 - s31\n@ Remarks:\n@   tail call - called function pops return address from stack\n@ ------------------------------------------------------------------------------\ndraw_object:\n  stmfd       sp!, {lr}\n  vstmdb.f32  sp!, {s5 - s6}\n\n  @ Reset model matrix\n  ldr         r0, =mtx_id\n  vldm.f32    r0, {s16 - s31}\n  ldr         r0, =mtx_model\n  vstm.f32    r0, {s16 - s31}\n  ldr         r0, =mtx_temp\n  vstm.f32    r0, {s16 - s31}\n\n  @ Translate & rotate\n  vneg.f32    s1, s1\n  ldr         r0, =mtx_model\n  bl          mat4_translate\n  vmov.f32    s0, s4\n  ldr         r0, =mtx_temp\n  bl          mat4_rot_y\n  ldr         r0, =mtx_model\n  ldr         r1, =mtx_temp\n  ldr         r2, =mtx_model\n  bl          mat4_mul_mat4\n\n  @ Render the cube\n  ldr         r0, =mtx_vp\n  ldr         r1, =mtx_model\n  ldr         r2, =mtx_mvp\n  bl          mat4_mul_mat4\n\n  vldmia.f32  sp!, {s5 - s6}\n  vmov.f32    r0, s6\n  teq         r0, #0\n  beq         draw_wrench_sprite\n  teq         r0, #1\n  beq         draw_rocket_sprite\n  b           draw_rock\n\n@ ------------------------------------------------------------------------------\n@ Draws a single rock\n@ Arguments:\n@   s0 - s4: Rock attributes\n@ Returns:\n@   none\n@ Clobbers:\n@  s0 - s31\n@ ------------------------------------------------------------------------------\ndraw_rock:\n  vmov.f32    r5, s5\n  sub         r5, r5, #1\n  ldr         r6, =480\n\n  ldr         r0, =rock_vtx\n  ldr         r1, =rock_idx\n  mla         r1, r5, r6, r1\n  ldr         r2, =20\n  ldr         r3, =mtx_mvp\n  ldr         r4, =light_dir\n  bl          gfx_draw_trgs\n\n  ldmfd       sp!, {pc}\n\n@ ------------------------------------------------------------------------------\n@ Draws a wrench sprite\n@ Arguments:\n@   s0 - s4: Rock attributes\n@ Returns:\n@   none\n@ Clobbers:\n@  s0 - s31\n@ ------------------------------------------------------------------------------\ndraw_wrench_sprite:\n  ldr         r0, =wrench\n  ldr         r1, =mtx_mvp\n  ldr         r2, =mtx_view\n  ldr         r3, =0x3f800000\n  vmov.f32    s0, r3\n  vmov.f32    s1, r3\n  bl          gfx_draw_sprite\n\n  ldmfd       sp!, {pc}\n\n@ ------------------------------------------------------------------------------\n@ Draws a rocket sprite\n@ Arguments:\n@   s0 - s4: Rock attributes\n@ Returns:\n@   none\n@ Clobbers:\n@  s0 - s31\n@ ------------------------------------------------------------------------------\ndraw_rocket_sprite:\n  ldr         r0, =rocket\n  ldr         r1, =mtx_mvp\n  ldr         r2, =mtx_view\n  ldr         r3, =0x3f800000\n  vmov.f32    s0, r3\n  vmov.f32    s1, r3\n  bl          gfx_draw_sprite\n\n  ldmfd       sp!, {pc}\n\n@-------------------------------------------------------------------------------\n@ Resets objects\n@-------------------------------------------------------------------------------\nreset_objects:\n  stmfd       sp!, {r0 - r4, lr}\n  vstmdb.f32  sp!, {s0 - s6}\n\n  ldr         r4, =OBJECT_COUNT\n  ldr         r3, =object_list\n  ldr         r2, =ROCK_LIVES\n  ldr         r1, =0x3FC00000    @ 1.5\n  mov         r0, #0\n\n1:\n  vldm.f32    r3, {s0 - s6}\n\n  vmov.f32    s0, r0\n  vmov.f32    s1, r0\n  vmov.f32    s2, r0\n  vmov.f32    s3, r1\n  vmov.f32    s4, r0\n  vmov.f32    s5, r0\n  vmov.f32    s6, r2\n\n  vstm.f32    r3!, {s0 - s6}\n  \n  subs        r4, #1\n  bne         1b\n\n  vldmia.f32  sp!, {s0 - s6}\n  ldmfd       sp!, {r0 - r4, pc}\n"
  },
  {
    "path": "pillars.s",
    "content": "@ This file is part of the Team 28 Project\n@ Licensing information can be found in the LICENSE file\n@ (C) 2014 The Team 28 Authors. All rights reserved.\n.global draw_pillars\n.global pillar_pos\n\n.section .data\n.include \"assets/pillar.s\"\n\n.section .text\n@ ------------------------------------------------------------------------------\n@ Cubes on the sides\n@ ------------------------------------------------------------------------------\n.equ             PILLAR_COUNT, 24\npillar_pos:     .float 0.0\npillar_list:\n  .float        -10.0,  0.0, -142.0\n  .float          1.0,  6.0,    1.0\n  .float        -10.0,  0.0, -130.0\n  .float          1.0,  6.0,    1.0\n  .float        -10.0,  0.0, -118.0\n  .float          1.0,  6.0,    1.0\n  .float        -10.0,  0.0, -106.0\n  .float          1.0,  6.0,    1.0\n  .float        -10.0,  0.0,  -94.0\n  .float          1.0,  6.0,    1.0\n  .float        -10.0,  0.0,  -82.0\n  .float          1.0,  6.0,    1.0\n  .float        -10.0,  0.0,  -70.0\n  .float          1.0,  6.0,    1.0\n  .float        -10.0,  0.0,  -58.0\n  .float          1.0,  6.0,    1.0\n  .float        -10.0,  0.0,  -46.0\n  .float          1.0,  6.0,    1.0\n  .float        -10.0,  0.0,  -34.0\n  .float          1.0,  6.0,    1.0\n  .float        -10.0,  0.0,  -22.0\n  .float          1.0,  6.0,    1.0\n  .float        -10.0,  0.0,  -10.0\n  .float          1.0,  6.0,    1.0\n  .float         10.0,  0.0, -142.0\n  .float          1.0,  6.0,    1.0\n  .float         10.0,  0.0, -130.0\n  .float          1.0,  6.0,    1.0\n  .float         10.0,  0.0, -118.0\n  .float          1.0,  6.0,    1.0\n  .float         10.0,  0.0, -106.0\n  .float          1.0,  6.0,    1.0\n  .float         10.0,  0.0,  -94.0\n  .float          1.0,  6.0,    1.0\n  .float         10.0,  0.0,  -82.0\n  .float          1.0,  6.0,    1.0\n  .float         10.0,  0.0,  -70.0\n  .float          1.0,  6.0,    1.0\n  .float         10.0,  0.0,  -58.0\n  .float          1.0,  6.0,    1.0\n  .float         10.0,  0.0,  -46.0\n  .float          1.0,  6.0,    1.0\n  .float         10.0,  0.0,  -34.0\n  .float          1.0,  6.0,    1.0\n  .float         10.0,  0.0,  -22.0\n  .float          1.0,  6.0,    1.0\n  .float         10.0,  0.0,  -10.0\n  .float          1.0,  6.0,    1.0\n\n@ ------------------------------------------------------------------------------\n@ Renders the pillars on the sides\n@ ------------------------------------------------------------------------------\ndraw_pillars:\n  stmfd       sp!, {lr}\n  ldr         r12, =PILLAR_COUNT\n  ldr         r11, =pillar_list\n\n  @ Reset model matrix\n  ldr         r0, =mtx_id\n  vldm.f32    r0, {s0 - s15}\n  ldr         r0, =mtx_model\n  vstm.f32    r0, {s0 - s15}\n\n  @ Get player position\n  ldr         r0, =player_speed\n  vldr.f32    s3, [r0]\n  ldr         r0, =pillar_pos\n  vldr.f32    s4, [r0]\n  vadd.f32    s4, s4, s3\n  ldr         r1, =0x41400000\n  vmov.f32    s5, r1\n  vcmp.f32    s4, s5\n  fmstat\n  ldr         r1, =0x00000000\n  vmovgt.f32  s4, r1\n  vstr.f32    s4, [r0]\n\n1:\n  vldm.f32    r11!, {s0 - s2}\n  vstmdb.f32  sp!, {s4}\n  vadd.f32    s2, s2, s4\n  bl          draw_pillar\n  vldmia.f32  sp!, {s4}\n  subs        r12, r12, #1\n  bne         1b\n\n  ldmfd       sp!, {pc}\n\n@ ------------------------------------------------------------------------------\n@ Draws a single pillar\n@ ------------------------------------------------------------------------------\ndraw_pillar:\n  stmfd       sp!, {lr}\n\n  ldr         r0, =mtx_model\n  bl          mat4_translate\n  vldm.f32    r11!, {s0 - s2}\n  bl          mat4_scale\n\n  ldr         r0, =mtx_vp\n  ldr         r1, =mtx_model\n  ldr         r2, =mtx_mvp\n  bl          mat4_mul_mat4\n\n  ldr         r0, =pillar_vtx\n  ldr         r1, =pillar_idx\n  ldr         r2, =10\n  ldr         r3, =mtx_mvp\n  ldr         r4, =light_dir\n  bl          gfx_draw_trgs\n\n  ldmfd       sp!, {pc}\n"
  },
  {
    "path": "player.s",
    "content": "@ This file is part of the Team 28 Project\n@ Licensing information can be found in the LICENSE file\n@ (C) 2014 The Team 28 Authors. All rights reserved.\n.global player_pos\n.global player_health\n.global player_rolling\n.global player_speed\n.global player_shake\n.global player_score\n.global player_high_score\n.global player_wrenches\n.global player_rockets\n.global draw_player\n.global player_damage\n.global update_player\n.global setup_player\n.global reset_player_mov\n.global monkey_timer\n.global rock_timer\n\n.section .data\n@ ------------------------------------------------------------------------------\n@ Player resources\n@ ------------------------------------------------------------------------------\nplayer_charge:      .long 0\nplayer_health:      .long 200\nplayer_wrenches:    .long 3\nplayer_rockets:     .long 3\ntristan_timer:      .long 0\nmonkey_timer:       .long 0\nrock_timer:         .long 0\n\n@ ------------------------------------------------------------------------------\n@ Player movement\n@ ------------------------------------------------------------------------------\nplayer_tilt_z:      .float 0.0\nplayer_tilt_x:      .float 0.0\nplayer_rolling:     .long 0\nplayer_shake:       .long 0\nplayer_score:       .long 0\nplayer_high_score:  .long 0\nplayer_roll_dir:    .float 0.15\nplayer_pos:         .float 0.0, 0.0, 0.0\nplayer_speed:       .float 0.0\nplayer_speed_mod:   .long 0\n\n.section .text\n@ ------------------------------------------------------------------------------\n@ Initialises the player\n@ ------------------------------------------------------------------------------\nsetup_player:\n  stmfd       sp!, {r0 - r1, lr}\n\n  ldr         r0, =player_charge\n  ldr         r1, =0\n  str         r1, [r0]\n\n  ldr         r0, =player_health\n  ldr         r1, =200\n  str         r1, [r0]\n\n  ldr         r0, =player_wrenches\n  ldr         r1, =3\n  str         r1, [r0]\n\n  ldr         r0, =player_rockets\n  ldr         r1, =3\n  str         r1, [r0]\n\n  ldr         r0, =player_score\n  mov         r1, #0\n  str         r1, [r0]\n\n  ldr         r0, =player_speed_mod\n  mov         r1, #0\n  str         r1, [r0]\n\n  ldr         r0, =tristan_timer\n  mov         r1, #0\n  str         r1, [r0]\n\n  ldr         r0, =monkey_timer\n  mov         r1, #0\n  str         r1, [r0]\n\n  ldr         r0, =rock_timer\n  mov         r1, #130\n  str         r1, [r0]\n\n  ldr         r0, =player_pos\n  mov         r1, #0\n  vmov.f32    s0, r1\n  vmov.f32    s1, r1\n  vmov.f32    s2, r1\n  vstm.f32    r0, {s0 - s2}\n\n  ldmfd       sp!, {r0 - r1, pc}\n\n@ ------------------------------------------------------------------------------\n@ Renders the player's plane\n@ ------------------------------------------------------------------------------\ndraw_player:\n  stmfd       sp!, {lr}\n\n  @ Reset model matrix\n  ldr         r0, =mtx_id\n  vldm.f32    r0, {s0 - s15}\n  ldr         r0, =mtx_model\n  vstm.f32    r0, {s0 - s15}\n  mov         r1, #0\n  vmov.f32    s0, r1\n  ldr         r1, =0xc0000000\n  vmov.f32    s1, r1\n  ldr         r1, =0xc0e00000\n  vmov.f32    s2, r1\n  bl          mat4_translate\n\n  @ Tilt around Z\n  ldr         r0, =mtx_id\n  vldm.f32    r0, {s0 - s15}\n  ldr         r0, =mtx_temp\n  vstm.f32    r0, {s0 - s15}\n  ldr         r0, =player_tilt_z\n  vldr.f32    s0, [r0]\n  ldr         r0, =mtx_temp\n  bl          mat4_rot_z\n  ldr         r0, =mtx_model\n  ldr         r1, =mtx_temp\n  ldr         r2, =mtx_model\n  bl          mat4_mul_mat4\n\n  @ Tilt around X\n  ldr         r0, =mtx_id\n  vldm.f32    r0, {s0 - s15}\n  ldr         r0, =mtx_temp\n  vstm.f32    r0, {s0 - s15}\n  ldr         r0, =player_tilt_x\n  vldr.f32    s0, [r0]\n  ldr         r0, =mtx_temp\n  bl          mat4_rot_x\n  ldr         r0, =mtx_model\n  ldr         r1, =mtx_temp\n  ldr         r2, =mtx_model\n  bl          mat4_mul_mat4\n\n  @ Compute proj * model\n  ldr         r0, =mtx_proj\n  ldr         r1, =mtx_model\n  ldr         r2, =mtx_mp\n  bl          mat4_mul_mat4\n\n  @ Draw the plane\n  ldr         r0, =ship_vtx\n  ldr         r1, =ship_idx\n  ldr         r2, =22\n  ldr         r3, =mtx_mp\n  ldr         r4, =light_dir\n  bl          gfx_draw_trgs\n\n  @ Draw wrenches\n  ldr         r3, =player_wrenches\n  ldr         r3, [r3]\n  ldr         r1, =582\n  ldr         r2, =410\n  ldr         r0, =wrench\n\n  tst         r3, r3\n  beq         2f\n1:\n  bl          gfx_draw_image\n  sub         r1, r1, #20\n  subs        r3, r3, #1\n  bne         1b\n2:\n\n  @ Draw rockets\n  ldr         r3, =player_rockets\n  ldr         r3, [r3]\n  mov         r1, #34\n  ldr         r2, =410\n  ldr         r0, =rocket\n\n  tst         r3, r3\n  beq         2f\n1:\n  bl          gfx_draw_image\n  add         r1, r1, #20\n  subs        r3, r3, #1\n  bne         1b\n2:\n\n  @ Draw health bar\n  ldr         r0, =522\n  ldr         r1, =450\n  ldr         r5, =player_health\n  ldr         r6, =0xFF0000cc\n  bl          draw_bar\n\n  @ Draw charge bar\n  mov         r0, #10\n  ldr         r1, =450\n  ldr         r5, =player_charge\n  ldr         r6, =0xFFFF4400\n  bl          draw_bar\n\n  @ Test if monkey should pop-up\n  ldr         r0, =monkey_timer\n  ldr         r1, [r0]\n  subs        r1, r1, #1\n  str         r1, [r0]\n\n  ble         2f\n\n  @ Draw monkey\n  ldr         r0, =124\n  ldr         r1, =420\n  ldr         r5, =monkey\n  ldr         r6, =5f\n  bl          draw_pop_up\n\n  ldmfd       sp!, {pc}\n\n2:\n\n  @ Test if Tristan should pop-up\n  ldr         r0, =tristan_timer\n  ldr         r1, [r0]\n  subs        r1, r1, #1\n  str         r1, [r0]\n\n  ble         3f\n\n  @ Draw Tristan barrel roll\n  ldr         r0, =124\n  ldr         r1, =420\n  ldr         r5, =tristan\n  ldr         r6, =4f\n  bl          draw_pop_up\n\n  ldmfd       sp!, {pc}\n\n3:\n\n  @ Test if Tristan should pop-up\n  ldr         r0, =rock_timer\n  ldr         r1, [r0]\n  subs        r1, r1, #1\n  str         r1, [r0]\n\n  ldmlefd     sp!, {pc}\n\n  @ Draw Tristan rock-and-roll\n  ldr         r0, =124\n  ldr         r1, =420\n  ldr         r5, =tristan\n  ldr         r6, =6f\n  bl          draw_pop_up\n\n  ldmfd       sp!, {pc}\n\n4:\n  .ascii \"\\nDo a barrel roll!\"\n  .byte  0x0\n  .align 2\n\n5:\n  .ascii \"\\nCan't let you do that PiFox!\"\n  .byte  0x0\n  .align 2\n\n6:\n  .ascii \"I see 'em up ahead.\\nLet's Rock and Roll!\"\n  .byte  0x0\n  .align 2\n\n@ ------------------------------------------------------------------------------\n@ Rotates the camera around origin\n@ ------------------------------------------------------------------------------\nupdate_player:\n  stmfd       sp!, {lr}\n\n  bl          do_barrel_roll\n  bl          do_speed\n  bl          do_movement\n  bl          do_repair\n  bl          do_rocket\n  bl          do_charge\n  bl          do_matrices\n\n  bl          do_speed_inc\n\n  ldmfd       sp!, {pc}\n\n@ ------------------------------------------------------------------------------\n@ Continues a barrell roll\n@ ------------------------------------------------------------------------------\ndo_barrel_roll:\n  stmfd       sp!, {lr}\n\n  @ If we are already rolling, continue\n  ldr         r0, =player_rolling\n  ldr         r1, [r0]\n  tst         r1, r1\n  bne         1f\n\n  @ Roll when left/right is double clicked\n  ldr         r2, =button_dclicked\n  ldr         r2, [r2]\n  tst         r2, #0xC0\n  ldmeqfd     sp!, {pc}\n\n  @ Charge must be full\n  ldr         r3, =player_charge\n  ldr         r4, [r3]\n  cmp         r4, #200\n  ldmltfd     sp!, {pc}\n  mov         r4, #0\n  str         r4, [r3]\n\n  @ Play sounds\n  bl          snd_play_boost\n\n  @ Start the roll\n  ldr         r3, =player_roll_dir\n  vldr.f32    s0, [r3]\n  vabs.f32    s0, s0\n  tst         r2, #0x80\n  vnegne.f32  s0, s0\n  vstr.f32    s0, [r3]\n  mov         r1, #1\n  str         r1, [r0]\n  ldmfd       sp!, {pc}\n1:\n  @ Update rotation\n  ldr         r2, =player_roll_dir\n  vldr.f32    s0, [r2]\n  ldr         r2, =player_tilt_z\n  vldr.f32    s1, [r2]\n  vadd.f32    s1, s1, s0\n\n  vcmp.f32    s0, #0\n  fmstat\n  bgt         2f\n  ldr         r3, =0xc0c90fdb\n  vmov.f32    s2, r3\n  vcmp.f32    s1, s2\n  fmstat\n  movlt       r1, #0\n  vmovlt.f32  s1, r1\n  b           3f\n2:\n  ldr         r3, =0x40c90fdb\n  vmov.f32    s2, r3\n  vcmp.f32    s1, s2\n  fmstat\n  movgt       r1, #0\n  vmovgt.f32  s1, r1\n3:\n  str         r1, [r0]\n  vstr.f32    s1, [r2]\n  ldr         r0, =0x3f800000        @ 1.0\n\n  ldmfd       sp!, {pc}\n\n@ ------------------------------------------------------------------------------\n@ Updates the movement speed of the player\n@ ------------------------------------------------------------------------------\ndo_speed:\n  ldr         r0, =player_speed_mod\n  vldr.f32    s0, [r0]\n  fsitos      s0, s0\n\n  ldr         r0, =0x3a378034        @ 0.0007\n  vmov.f32    s1, r0\n  vmul.f32    s0, s0, s1\n\n  ldr         r0, =0x3f800000\n  vmov.f32    s1, r0\n  vadd.f32    s0, s0, s1\n\n  ldr         r0, =0x40600000         @ 3.5\n  vmov.f32    s1, r0\n  ldr         r0, =player_rolling\n  ldr         r0, [r0]\n  tst         r0, r0\n  vmulne.f32  s0, s0, s1\n\n  ldr         r0, =0x40a00000\n  vmov.f32    s1, r0\n  vcmp.f32    s0, s1\n  fmstat\n  vmovgt.f32  s0, s1\n\n  ldr         r0, =player_speed\n  vstr.f32    s0, [r0]\n\n  mov         pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Increase player's speed modifier\n@ ------------------------------------------------------------------------------\ndo_speed_inc:\n  stmfd       sp!, {r0, r1}\n  ldr         r0, =player_speed_mod\n  ldr         r1, [r0]\n  add         r1, r1, #1\n  str         r1, [r0]\n  ldmfd       sp!, {r0, r1}\n  mov         pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Updates the position of the player\n@ ------------------------------------------------------------------------------\ndo_movement:\n  @ Normal speed\n  ldr         r0, =player_rolling\n  ldr         r0, [r0]\n  tst         r0, r0\n  movne       pc, lr\n\n  stmfd       sp!, {lr}\n\n  @ Get button state\n  ldr         r2, =button_pressed\n  ldr         r2, [r2]\n\n  @ Move player forward\n  ldr         r0, =player_pos\n  vldm.f32    r0, {s0 - s2}\n  ldr         r3, =0x3f800000       @ 1.0\n  vmov.f32    s4, r3\n  tst         r2, #0x80\n  vaddne.f32  s0, s4                @ right\n  tst         r2, #0x40\n  vsubne.f32  s0, s4                @ left\n  tst         r2, #0x10\n  vsubne.f32  s1, s4                @ up\n  tst         r2, #0x20\n  vaddne.f32  s1, s4                @ down\n  bl          clamp\n\n  vstm.f32    r0, {s0 - s2}\n\n  @ Tilt left/right\n  ldr         r3, =player_tilt_z\n  vldr.f32    s0, [r3]\n  ldr         r0, =0x3d23d70a       @ 0.04\n  vmov.f32    s1, r0\n\n  tst         r2, #0x80\n  beq         1f\n  vsub.f32    s0, s1\n  ldr         r0, =0xbecccccd       @ -0.4\n  vmov.f32    s2, r0\n  vcmp.f32    s0, s2\n  fmstat\n  vmovlt.f32  s0, s2\n  b           4f\n1:\n  tst         r2, #0x40\n  beq         2f\n  vadd.f32    s0, s1\n  ldr         r0, =0x3ecccccd       @ 0.4\n  vmov.f32    s2, r0\n  vcmp.f32    s0, s2\n  fmstat\n  vmovgt.f32  s0, s2\n  b           4f\n2:\n  vcmp.f32    s0, #0\n  fmstat\n  blt         3f\n  vsub.f32    s0, s1\n  ldr         r0, =0\n  vmov.f32    s2, r0\n  vcmp.f32    s0, s2\n  fmstat\n  vmovlt.f32  s0, s2\n  b           4f\n3:\n  vadd.f32    s0, s1\n  ldr         r0, =0\n  vmov.f32    s2, r0\n  vcmp.f32    s0, s2\n  fmstat\n  vmovgt.f32  s0, s2\n4:\n  vstr.f32    s0, [r3]\n\n  @ Tilt up/down\n  ldr         r3, =player_tilt_x\n  vldr.f32    s0, [r3]\n  ldr         r0, =0x3d23d70a       @ 0.04\n  vmov.f32    s1, r0\n\n  tst         r2, #0x20\n  beq         1f\n  vsub.f32    s0, s1\n  ldr         r0, =0xbecccccd       @ -0.4\n  vmov.f32    s2, r0\n  vcmp.f32    s0, s2\n  fmstat\n  vmovlt.f32  s0, s2\n  b           4f\n1:\n  tst         r2, #0x10\n  beq         2f\n  vadd.f32    s0, s1\n  ldr         r0, =0x3dcccccd       @ 0.1\n  vmov.f32    s2, r0\n  vcmp.f32    s0, s2\n  fmstat\n  vmovgt.f32  s0, s2\n  b           4f\n2:\n  vcmp.f32    s0, #0\n  fmstat\n  blt         3f\n  vsub.f32    s0, s1\n  ldr         r0, =0\n  vmov.f32    s2, r0\n  vcmp.f32    s0, s2\n  fmstat\n  vmovlt.f32  s0, s2\n  b           4f\n3:\n  vadd.f32    s0, s1\n  ldr         r0, =0\n  vmov.f32    s2, r0\n  vcmp.f32    s0, s2\n  fmstat\n  vmovgt.f32  s0, s2\n4:\n  vstr.f32    s0, [r3]\n\n  ldmfd       sp!, {pc}\n\n@-------------------------------------------------------------------------------\n@ Handles repairs\n@-------------------------------------------------------------------------------\ndo_repair:\n  @ Repair when B was double clicked\n  ldr         r0, =button_dclicked\n  ldr         r0, [r0]\n  tst         r0, #0x02\n  moveq       pc, lr\n\n  @ Check number of repairs left\n  ldr         r0, =player_wrenches\n  ldr         r1, [r0]\n  tst         r1, r1\n  moveq       pc, lr\n  sub         r1, #1\n  str         r1, [r0]\n\n  @ Update health\n  ldr         r0, =player_health\n  ldr         r1, [r0]\n  add         r1, #50\n  cmp         r1, #200\n  movgt       r1, #200\n  str         r1, [r0]\n\n  mov         pc, lr\n\n@-------------------------------------------------------------------------------\n@ Handles firing rockets\n@-------------------------------------------------------------------------------\ndo_rocket:\n  stmfd       sp!, {lr}\n\n  @ Fire when B was clicked\n  ldr         r0, =button_clicked\n  ldr         r1, [r0]\n  tst         r1, #0x02\n  moveq       pc, lr\n\n  @ Check number of rockets left\n  ldr         r0, =player_rockets\n  ldr         r1, [r0]\n  tst         r1, r1\n  moveq       pc, lr\n  sub         r1, #1\n  str         r1, [r0]\n\n  @ Play rocket sound\n  bl          snd_play_rocket\n\n  @ Fire the rocket\n  bl          spawn_rocket\n\n  ldmfd       sp!, {pc}\n\n@-------------------------------------------------------------------------------\n@ Increses the charge of barrell roll\n@-------------------------------------------------------------------------------\ndo_charge:\n  @ Check for roll\n  ldr         r0, =player_rolling\n  ldr         r0, [r0]\n  tst         r0, r0\n  movne       pc, lr\n\n  @ Update charge\n  ldr         r0, =player_charge\n  ldr         r1, [r0]\n  cmp         r1, #200\n  add         r1, #1\n  strlt       r1, [r0]\n\n  mov         pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Computes mtx_view and mtx_vp\n@ ------------------------------------------------------------------------------\ndo_matrices:\n  stmfd       sp!, {lr}\n\n  @ Clear the view matrix\n  ldr         r0, =mtx_id\n  vldm.f32    r0, {s0 - s15}\n  ldr         r0, =mtx_view\n  vstm.f32    r0, {s0 - s15}\n\n  @ Shake the world\n  ldr         r0, =player_shake\n  ldr         r1, [r0]\n  tst         r1, r1\n  subne       r1, r1, #1\n  str         r1, [r0]\n  vmov.f32    s0, r1\n  fsitos      s0, s0\n  bl          sin\n  ldr         r0, =0x42700000\n  vmov.f32    s2, r0\n  vmul.f32    s5, s0, s1\n  vdiv.f32    s5, s5, s2\n\n  @ Compute the view matrix (translation)\n  ldr         r0, =player_pos\n  vldm.f32    r0, {s0 - s2}\n  vadd.f32    s1, s1, s5\n  vabs.f32    s5, s5\n  vsub.f32    s0, s5, s0\n  ldr         r0, =mtx_view\n  bl          mat4_translate\n\n  @ Compute the proj * view matrix\n  ldr         r0, =mtx_proj\n  ldr         r1, =mtx_view\n  ldr         r2, =mtx_vp\n  bl          mat4_mul_mat4\n\n  ldmfd       sp!, {pc}\n\n@ ------------------------------------------------------------------------------\n@ Clamps a coordinate, forcing it inside bounds on X and Y axis\n@\n@ Arguments:\n@   s0 - x\n@   s1 - y\n@   s2 - z\n@ Returns:\n@   s0 - clamped x\n@   s1 - clamped y\n@   s2 - clamped z\n@ Clobbers\n@   none\n@ ------------------------------------------------------------------------------\nclamp:\n  stmfd         sp!, {r0}\n  vstmdb.f32    sp!, {s3}\n\n  ldr           r0, =0x41080000     @ 8.5\n  vmov.f32      s3, r0\n  vcmp.f32      s0, s3\n  fmstat\n  vmovgt.f32    s0, s3\n\n  ldr           r0, =0xc1080000     @ -8.5\n  vmov.f32      s3, r0\n  vcmp.f32      s0, s3\n  fmstat\n  vmovlt.f32    s0, s3\n\n  ldr           r0, =0x3f000000     @ 0.5\n  vmov.f32      s3, r0\n  vcmp.f32      s1, s3\n  fmstat\n  vmovgt.f32    s1, s3\n\n  ldr           r0, =0xc0900000     @ -4.5\n  vmov.f32      s3, r0\n  vcmp.f32      s1, s3\n  fmstat\n  vmovlt.f32    s1, s3\n\n  vldmia.f32    sp!, {s3}\n  ldmfd         sp!, {r0}\n  mov           pc, lr\n\n@-------------------------------------------------------------------------------\n@ Draws health / charge bar\n@\n@ Arguments:\n@   r0 - x\n@   r1 - y\n@   r5 - current amount address\n@   r6 - colour\n@ Returns:\n@   none\n@ Clobbers:\n@   none\n@-------------------------------------------------------------------------------\ndraw_bar:\n  stmfd       sp!, {r0 - r6, lr}\n\n  @ Draw frame\n  mov         r2, #108\n  mov         r3, #20\n  ldr         r4, =0xFFFFFF00\n  bl          gfx_draw_frame\n\n  @ Draw current charge\n  add         r0, #4\n  add         r1, #4\n  ldr         r2, [r5]\n  lsr         r2, r2, #1\n  sub         r3, r3, #8\n  mov         r4, r6\n  bl          gfx_draw_rect\n\n  ldmfd       sp!, {r0 - r6, pc}\n\n@-------------------------------------------------------------------------------\n@ Draws character\n@ Arguments:\n@   r0 - x\n@   r1 - y\n@   r5 - picture address\n@   r6 - message address\n@ Returns:\n@   none\n@ Clobbers:\n@   none\n@-------------------------------------------------------------------------------\ndraw_pop_up:\n  stmfd       sp!, {r0 - r6, lr}\n\n  @ Draw frame\n  mov         r2, #58\n  mov         r3, #57\n  ldr         r4, =0xFFFFFF00\n  bl          gfx_draw_frame\n\n  add         r2, r1, #3\n  add         r1, r0, #3\n  mov         r0, r5\n  bl          gfx_draw_image\n\n  mov         r0, r6\n  add         r1, r1, #60\n  add         r2, r2, #16\n  ldr         r3, =0xFFFFFF00\n  bl          printf\n\n  ldmfd       sp!, {r0 - r6, pc}     \n\n@ ------------------------------------------------------------------------------\n@ Applies damage to the player\n@ Arguments:\n@   r0 - damage\n@ Returns:\n@   none\n@ Clobbers:\n@   none\n@ ------------------------------------------------------------------------------\nplayer_damage:\n  stmfd       sp!, {r0 - r4, lr}\n\n  ldr         r3, =player_speed_mod     @ Decrement score\n  ldr         r4, [r3]\n  subs        r4, r4, #300\n  movlt       r4, #0\n  str         r4, [r3]\n\n\n  @ Play damage sound\n  bl          snd_play_crash\n\n  ldr         r1, =player_health    @ Decrement health\n  ldr         r2, [r1]\n  cmp         r2, #100\n  blt         1f\n  sub         r3, r2, r0\n  cmp         r3, #100\n  bgt         1f\n\n  @ Pop-up Tristan\n  ldr         r3, =tristan_timer\n  mov         r4, #110\n  str         r4, [r3]\n\n  bl          snd_play_roll\n\n\n1:\n  sub         r2, r2, r0\n  cmp         r2, #0\n  movle       r2, #0\n  str         r2, [r1]\n\n  ldr         r1, =player_shake\n  mov         r2, #40\n  str         r2, [r1]\n\n  ldmfd       sp!, {r0 - r4, pc}\n\n@-------------------------------------------------------------------------------\n@ Resets player movement\n@-------------------------------------------------------------------------------\nreset_player_mov:\n  stmfd       sp!, {r0 -r1, lr}\n  vstmdb.f32  sp!, {s0}\n\n  mov         r0, #0\n  vmov.f32    s0, r0\n\n  ldr         r1, =player_tilt_z\n  vstm.f32    r1, {s0}\n\n  ldr         r1, =player_tilt_x\n  vstm.f32    r1, {s0}    \n\n  ldr         r1, =player_rolling\n  str         r0, [r1]\n\n  ldr         r1, =player_shake\n  str         r0, [r1]\n\n  ldr         r1, =player_speed\n  vstm.f32    r1, {s0}\n\n  ldr         r1, =player_roll_dir\n  ldr         r0, =0x3E19999A         @ 0.15\n  vmov.f32    s0, r0\n  vstm.f32    r1, {s0}\n\n  vldmia.f32  sp!, {s0}  \n  ldmfd       sp!, {r0 - r1, pc}\n  \n"
  },
  {
    "path": "ports.s",
    "content": "@ This file is part of the Team 28 Project\n@ Licensing information can be found in the LICENSE file\n@ (C) 2014 The Team 28 Authors. All rights reserved.\n\n@ ------------------------------------------------------------------------------\n@ System timer\n@ ------------------------------------------------------------------------------\n.equ STIMER_CS,        0x20003000\n.equ STIMER_CLO,       0x20003004\n.equ STIMER_CHI,       0x20003008\n.equ STIMER_C0,        0x2000300C\n.equ STIMER_C1,        0x20003010\n.equ STIMER_C2,        0x20003014\n.equ STIMER_C3,        0x20003018\n\n@ ------------------------------------------------------------------------------\n@ Interrupt register\n@ ------------------------------------------------------------------------------\n.equ IRQ_PENDING,      0x2000B200\n.equ IRQ_GPU_PENDING1, 0x2000B204\n.equ IRQ_GPU_PENDING2, 0x2000B208\n.equ IRQ_FIQ,          0x2000B20C\n.equ IRQ_EN1,          0x2000B210\n.equ IRQ_EN2,          0x2000B214\n.equ IRQ_ENB,          0x2000B218\n.equ IRQ_DS1,          0x2000B21C\n.equ IRQ_DS2,          0x2000B220\n.equ IRQ_DSB,          0x2000B224\n\n@ ------------------------------------------------------------------------------\n@ ARM timer\n@ ------------------------------------------------------------------------------\n.equ TIMER_LOD,        0x2000B400\n.equ TIMER_VAL,        0x2000B404\n.equ TIMER_CTL,        0x2000B408\n.equ TIMER_CLI,        0x2000B40C\n.equ TIMER_RIS,        0x2000B410\n.equ TIMER_MIS,        0x2000B414\n.equ TIMER_RLD,        0x2000B418\n.equ TIMER_DIV,        0x2000B41C\n.equ TIMER_CNT,        0x2000B420\n\n@ ------------------------------------------------------------------------------\n@ Mailbox Ports\n@ ------------------------------------------------------------------------------\n.equ MBOX_BASE,        0x2000B880\n.equ MBOX_READ,        0x2000B880\n.equ MBOX_POLL,        0x2000B890\n.equ MBOX_SENDER,      0x2000B894\n.equ MBOX_STATUS,      0x2000B898\n.equ MBOX_CONFIG,      0x2000B89C\n.equ MBOX_WRITE,       0x2000B8A0\n\n@ ------------------------------------------------------------------------------\n@ GPIO Ports\n@ ------------------------------------------------------------------------------\n.equ GPIO_FSEL0,       0x20200000\n.equ GPIO_FSEL1,       0x20200004\n.equ GPIO_FSEL2,       0x20200008\n.equ GPIO_FSEL3,       0x2020000C\n.equ GPIO_FSEL4,       0x20200010\n.equ GPIO_FSEL5,       0x20200014\n.equ GPIO_SET0,        0x2020001C\n.equ GPIO_SET1,        0x20200020\n.equ GPIO_CLR0,        0x20200028\n.equ GPIO_CLR1,        0x2020002C\n.equ GPIO_LEV0,        0x20200034\n.equ GPIO_LEV1,        0x20200038\n.equ GPIO_EDS0,        0x20200040\n.equ GPIO_EDS1,        0x20200044\n.equ GPIO_REN0,        0x2020004C\n.equ GPIO_REN1,        0x20200050\n.equ GPIO_FEN0,        0x20200058\n.equ GPIO_FEN1,        0x2020005C\n.equ GPIO_HEN0,        0x20200064\n.equ GPIO_HEN1,        0x20200068\n.equ GPIO_LEN0,        0x20200070\n.equ GPIO_LEN1,        0x20200074\n.equ GPIO_AREN0,       0x2020007C\n.equ GPIO_AREN1,       0x20200080\n.equ GPIO_AFEN0,       0x20200088\n.equ GPIO_AFEN1,       0x2020008C\n.equ GPIO_PUD,         0x20200094\n.equ GPIO_UDCLK0,      0x20200098\n.equ GPIO_UDCLK1,      0x2020009C\n\n@ ------------------------------------------------------------------------------\n@ PL011 UART Ports\n@ ------------------------------------------------------------------------------\n.equ UART_DR,          0x20201000\n.equ UART_RSECR,       0x20201004\n.equ UART_FR,          0x20201018\n.equ UART_ILPR,        0x20201020\n.equ UART_IBRD,        0x20201024\n.equ UART_FBRC,        0x20201028\n.equ UART_LCRH,        0x2020102C\n.equ UART_CR,          0x20201030\n.equ UART_IFLS,        0x20201034\n.equ UART_IMSC,        0x20201038\n.equ UART_RIS,         0x2020103C\n.equ UART_MIS,         0x20201040\n.equ UART_ICR,         0x20201044\n.equ UART_DMACR,       0x20201048\n.equ UART_ITCR,        0x20201080\n.equ UART_ITIP,        0x20201084\n.equ UART_ITOP,        0x20201088\n.equ UART_TDR,         0x2020108C\n\n@ ------------------------------------------------------------------------------\n@ Clock manager\n@ ------------------------------------------------------------------------------\n.equ CM_PWMCTL,        0x201010A0\n.equ CM_PWMDIV,        0x201010A4\n\n@ ------------------------------------------------------------------------------\n@ Direct Memory Access\n@ ------------------------------------------------------------------------------\n.equ DMA0_CS,          0x20007000\n.equ DMA0_CONBLK,      0x20007004\n.equ DMA_INT_STATUS,   0x20007FE0\n.equ DMA_ENABLE,       0x20007FF0\n\n@ ------------------------------------------------------------------------------\n@ Pulse Width modulator\n@ ------------------------------------------------------------------------------\n.equ PWM_CTL,          0x2020C000\n.equ PWM_STA,          0x2020C004\n.equ PWM_DMAC,         0x2020C008\n.equ PWM_RNG1,         0x2020C010\n.equ PWM_DAT1,         0x2020C014\n.equ PWM_FIF1,         0x2020C018\n.equ PWM_RNG2,         0x2020C020\n.equ PWM_DAT2,         0x2020C024\n"
  },
  {
    "path": "printf.s",
    "content": "@ This file is part of the Team 28 Project\n@ Licensing information can be found in the LICENSE file\n@ (C) 2014 The Team 28 Authors. All rights reserved..global printf\n.global printf\n\n.section .text\n@ ------------------------------------------------------------------------------\n@ Print formatted string.\n@ The format string may contain the following sequences:\n@   %[n]x - print hexadecimal, pad to n chars\n@   %[n]d - print decimal, pad to n chars\n@   %s    - print string\n@ Arguments are taken from the stack and they must be pushed from the right to\n@ the left. Stack cleanup is the responsibility of the caller.\n@\n@ Arguments:\n@   r0    - address of the output format string\n@   stack - number(s)/string(s) to be printed, in reversed order\n@ Return:\n@   None\n@ Clobbers:\n@   None\n@ ------------------------------------------------------------------------------\nprintf:\n  stmfd   sp!, {r0 - r12, lr} @ r0 will store address of the format string\n                              @ r1 will store beginning of the output string\n  add     r4, sp, #56\n  mov     r3, sp\n\n  ldr     lr, =1f\n1:\n  mov     r2, #0\n  ldrb    r1, [r0], #1        @ put next char in r1\n  tst     r1, r1\n  beq     4f                  @ exit if r2 == '\\0'\n  cmp     r1, #37\n  beq     2f\n  strb    r1, [sp, #-1]!      @ store character on stack\n  b       1b\n2:\n  ldrb    r1, [r0], #1\n  cmp     r1, #100            @ d = decimal\n  beq     printf_d\n  cmp     r1, #115            @ s = string\n  beq     printf_s\n  cmp     r1, #120            @ x = hexadecimal\n  beq     printf_x\n  cmp     r1, #48\n  blo     3f\n  cmp     r1, #57\n  bhi     3f\n\n  @ Charater is a digit\n  subs    r2, r1, #48\n  b       2b\n3:\n  mov     r2, #37\n  strb    r2, [sp, #-1]!\n  strb    r1, [sp, #-1]!\n  tst     r1, r1\n  bne     1b\n4:\n  mov     r1, #0\n  strb    r1, [sp, #-1]!      @ Store a null terminator\n  @ Reverse buffer\n  mov     r4, sp\n  sub     r5, r3, #1\n5:\n  ldrb    r1, [r4]\n  ldrb    r2, [r5]\n  strb    r1, [r5], #-1\n  strb    r2, [r4], #1\n  cmp     r4, r5\n  blo     5b\n\n  @ Print to stdout with a syscall\n  mov     r4, r3\n  mov     r0, sp\n  ldr     r1, [r3, #4]\n  ldr     r2, [r3, #8]\n  ldr     r3, [r3, #12]\n  bl      gfx_draw_text\n\n  mov     sp, r4\n  ldmfd   sp!, {r0 - r12, pc}\n\n@ ------------------------------------------------------------------------------\n@ Decimal helper for printf\n@ Arguments:\n@   r5 - Number to print\n@   r2 - Max size of buffer\n@ ------------------------------------------------------------------------------\nprintf_d:\n  ldr     r5, [r4], #4\n  ldr     r7, =429496730\n\n  sub     r10, sp, #1\n\n  cmp     r5, #0                @ check sign\n  bge     1f\n  mov     r6, #45               @ r6 = '-'\n  neg     r5, r5\n1:\n  cmp     r2, #0\n  bne     3f                    @ if r2 != 0 then write the digits with padding\n2:\n  @ Handles the case where padding is not required i.e. r2 = 0\n  mov     r9, r5\n  sub     r5, r5, r5, lsr #30\n  umull   r8, r5, r7, r5\n\n  mov     r8, #10\n  mul     r8, r5, r8\n  sub     r9, r9, r8\n  add     r9, #48\n  strb    r9, [sp, #-1]!\n  cmp     r5, #0\n  bgt     2b\n  b       5f\n3:\n  mov     r11, #32              @ r11 = ' '\n4:\n  @ Handles padding\n  mov     r9, r5\n  sub     r5, r5, r5, lsr #30\n  umull   r8, r5, r7, r5\n\n  mov     r8, #10\n  mul     r8, r5, r8\n  sub     r9, r9, r8\n  add     r9, #48\n  strb    r9, [sp, #-1]!\n  sub     r2, r2, #1\n  cmp     r2, #0\n  beq     5f\n  cmp     r5, #0\n  bgt     4b\n5:\n  @ Puts minus if negative\n  cmp     r6, #45\n  bne     6f\n  strb    r6, [sp, #-1]!\n  sub     r2, r2, #1\n6:\n  @ Padds with spaces if necessary\n  cmp     r2, #0\n  ble     7f\n  strb    r11, [sp, #-1]!\n  sub     r2, r2, #1\n  b       6b\n7:\n  mov     r11, sp\n8:\n  @ Reverses the buffer\n  ldrb    r8, [r10]\n  ldrb    r9, [r11]\n  strb    r8, [r11], #1\n  strb    r9, [r10], #-1\n  cmp     r10, r11\n  bgt     8b\n\n  mov     pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Hexadecimal helper for printf\n@ Arguments:\n@   r5 - Number to print\n@ ------------------------------------------------------------------------------\nprintf_x:\n  ldr     r5, [r4], #4\n\n  tst     r2, r2\n  bne     2f\n\n  mov     r6, r5\n1:\n  add     r2, #1\n  lsrs    r6, r6, #4\n  bne     1b\n2:\n  sub     sp, r2\n\n  @ Unroll for first digit\n  and     r6, r5, #0xF\n  lsr     r5, r5, #4\n  cmp     r6, #10\n  addlo   r6, #48\n  addhs   r6, #55\n  strb    r6, [sp]\n  mov     r7, #1\n  subs    r2, r2, #1\n  beq     4f\n3:\n  @ Write the rest of the digits with padding\n  and     r6, r5, #0xF\n  cmp     r6, #10\n  addlo   r6, #48\n  addhs   r6, #55\n  lsr     r5, r5, #4\n  strb    r6, [sp, r7]\n  add     r7, r7, #1\n  subs    r2, r2, #1\n  bne     3b\n4:\n  mov     pc, lr\n\n@ ------------------------------------------------------------------------------\n@ String helper for printf\n@ Arguments:\n@   r5 - Address of the string\n@ ------------------------------------------------------------------------------\nprintf_s:\n  ldr     r5, [r4], #4\n1:\n  ldrb    r6, [r5], #1\n  cmp     r6, #0\n  beq     2f\n  strb    r6, [sp, #-1]!\n  b       1b\n2:\n  mov pc, lr\n"
  },
  {
    "path": "rockets.s",
    "content": "@ This file is part of the Team 28 Project\n@ Licensing information can be found in the LICENSE file\n@ (C) 2014 The Team 28 Authors. All rights reserved.\n.global draw_rockets\n.global spawn_rocket\n.global reset_rockets\n\n.section .data\n@-------------------------------------------------------------------------------\n@ Rockets\n@-------------------------------------------------------------------------------\n.equ          ROCKET_COUNT, 5\nrocket_list:\n  .rept ROCKET_COUNT\n    .float 0.0, 0.0, 0.0   @ (x, y, z)\n    .float 0.25            @ speed\n    .float 0.0             @ rotation\n    .long 0                @ active\n  .endr\n\n.section .text\n@-------------------------------------------------------------------------------\n@ Draws rockets\n@-------------------------------------------------------------------------------\ndraw_rockets:\n  stmfd       sp!, {lr}\n\n  ldr         r12, =ROCKET_COUNT\n  ldr         r11, =rocket_list  \n  ldr         r10, =0x40a00000      \n  vmov.f32    s31, r10              @ radius = 5\n\n1:\n  vldmia.f32  r11!, {s0 - s4}\n  ldmia       r11!, {r9}\n\n  tst         r9, r9\n  beq         3f\n\n  vmov.f32  s11, s0\n  vmov.f32  s12, s1\n  vmov.f32  s13, s2\n  mov       r0, r9\n  bl        collide_objects\n  bl        collide_enemies\n  mov       r9, r0\n\n  @ Update position\n  vsub.f32    s2, s2, s3     \n\n  @ Update rotation\n  ldr         r0, =0x3C23D70A       @ r0 = 0.01\n  vmov.f32    s5, r0\n  vadd.f32    s4, s4, s5\n\n  ldr         r0, =0xc3480000\n  vmov.f32    s5, r0                @ s5 = -200  \n  vcmp.f32    s2, s5\n  fmstat\n  movle       r9, #0\n\n3:\n  stmdb       r11!, {r9}  \n  vstmdb.f32  r11!, {s0 - s4}\n\n  tst         r9, r9 \n  blne        draw_rocket\n  add         r11, r11, #24\n  subs        r12, r12, #1\n  bne         1b\n\n  ldmfd       sp!, {pc}\n\n@-------------------------------------------------------------------------------\n@ Spawn rocket\n@-------------------------------------------------------------------------------\nspawn_rocket:\n  stmfd       sp!, {lr}\n\n  ldr         r12, =ROCKET_COUNT\n  ldr         r11, =rocket_list\n\n1:\n  vldmia.f32  r11!, {s0 - s4}\n  ldmia       r11!, {r9}\n\n  @ do not overwrite an existing rocket\n  tst         r9, r9\n  bne         2f\n\n  ldr         r0, =player_pos\n  vldmia.f32  r0, {s0 - s2}\n\n  @ set z\n  ldr         r0, =0xC1200000       \n  vmov.f32    s2, r0                @ z = -10\n\n  @ set y\n  ldr         r0, =0xc0000000\n  vmov.f32    s5, r0\n  vsub.f32    s1, s1, s5            @ y = p.y + 2\n\n  @ set speed\n  ldr         r0, =0x3f800000\n  vmov.f32    s3, r0                @ speed = 0.25\n\n  @ set rotation\n  ldr         r0, =0\n  vmov.f32    s4, r0                \n\n  @ activate\n  mov         r9, #1\n\n  stmdb       r11!, {r9} \n  vstmdb.f32  r11!, {s0 - s4}\n  ldmfd       sp!, {pc}\n\n2:\n  stmdb       r11!, {r9} \n  vstmdb.f32  r11!, {s0 - s4}\n\n  add         r11, r11, #24\n  subs        r12, r12, #1\n  bne         1b\n\n  ldmfd       sp!, {pc}\n\n@-------------------------------------------------------------------------------\n@ Draws a single rocket\n@ Arguments:\n@   s0 - s4: Rocket attributes\n@ Returns:\n@   none\n@ Clobbers:\n@   s0 - s31, r0 -r4\n@-------------------------------------------------------------------------------\ndraw_rocket:\n  stmfd       sp!, {lr}\n\n  @ Clear model matrix\n  ldr         r0, =mtx_id\n  vldm.f32    r0, {s16 - s31}\n  ldr         r0, =mtx_model\n  vstm.f32    r0, {s16 - s31}\n  ldr         r0, =mtx_temp\n  vstm.f32    r0, {s16 - s31}\n\n  @ Translate\n  vneg.f32    s1, s1 \n  ldr         r0, =mtx_model\n  bl          mat4_translate\n\n  @ Rotate\n  vmov.f32   s0, s4            @ s0 = angle\n  ldr        r0, =mtx_temp\n  bl         mat4_rot_z\n\n  ldr        r0, =mtx_model\n  ldr        r1, =mtx_temp\n  ldr        r2, =mtx_model\n  bl         mat4_mul_mat4\n\n  @ Compute mvp\n  ldr        r0, =mtx_vp\n  ldr        r1, =mtx_model    @ v' = MVP * v\n  ldr        r2, =mtx_mvp      \n  bl         mat4_mul_mat4\n\n  ldr        r0, =rocket_vtx\n  ldr        r1, =rocket_idx\n  ldr        r2, =30\n  ldr        r3, =mtx_mvp\n  ldr        r4, =light_dir\n  bl         gfx_draw_trgs\n\n  ldmfd      sp!, {pc}\n\n@-------------------------------------------------------------------------------\n@ Collide rocket at (s11, s12, s13) with all objects\n@ Arguments:\n@   s11 - x\n@   s12 - y\n@   s13 - z\n@   s31 - radius\n@ Returns:\n@\n@ Clobbers:\n@-------------------------------------------------------------------------------\ncollide_objects:\n  stmfd       sp!, {r0 - r12, lr}\n  vstmdb.f32  sp!, {s0 - s7}\n\n  ldr         r12, =OBJECT_COUNT\n  ldr         r11, =object_list\n\n1:\n  vldm.f32    r11, {s0 - s6}  \n\n  @ Check x\n  vsub.f32    s7, s11, s0\n  vabs.f32    s7, s7\n  vcmp.f32    s7, s31\n  fmstat\n  bgt         2f\n\n  @ Check y\n  vsub.f32    s7, s12, s1\n  vabs.f32    s7, s7\n  vcmp.f32    s7, s31\n  fmstat\n  bgt         2f\n\n  @ Check z\n  vsub.f32    s7, s13, s2\n  vabs.f32    s7, s7\n  vcmp.f32    s7, s31\n  fmstat\n  bgt         2f\n\n  @ Cause damage & update score if needed\n  vmov.f32    r9, s5\n  cmp         r9, #2\n  moveq       r9, #0\n  movgt       r9, #1\n  ldreq       r1, =player_score\n  ldreq       r2, [r1]\n  addeq       r2, r2, #5\n  streq       r2, [r1]\n  vmoveq.f32  s2, r9\n  vmov.f32    s5, r9\n\n2:\n  vstm.f32    r11!, {s0 - s6}\n  subs        r12, r12, #1\n  bne         1b\n\n  vldmia.f32  sp!, {s0 - s7}\n  ldmfd       sp!, {r0 - r12, pc}\n\n@-------------------------------------------------------------------------------\n@ Collide rocket at (s11, s12, s13) with all enemies\n@ Arguments:\n@   s11 - x\n@   s12 - y\n@   s13 - z\n@   s31 - radius\n@ Returns:\n@   r0 - 0 if collision happened\n@ Clobbers:\n@-------------------------------------------------------------------------------\ncollide_enemies:\n  stmfd       sp!, {r1 - r12, lr}\n  vstmdb.f32  sp!, {s0 - s8}\n\n  ldr         r12, =ENEMY_COUNT\n  ldr         r11, =enemies\n\n1:\n  vldm.f32    r11, {s0 - s7}  \n\n  @ Check x\n  vsub.f32    s8, s11, s0\n  vabs.f32    s8, s8\n  vcmp.f32    s8, s31\n  fmstat\n  bgt         2f\n\n  @ Check y\n  vsub.f32    s8, s12, s1\n  vabs.f32    s8, s8\n  vcmp.f32    s8, s31\n  fmstat\n  bgt         2f\n\n  @ Check z\n  vsub.f32    s8, s13, s2\n  vabs.f32    s8, s8\n  vcmp.f32    s8, s31\n  fmstat\n  bgt         2f\n\n  @ Cause damage & update score if needed\n  vmov.f32    r9, s6\n  subs        r9, r9, #2\n  movlt       r9, #0\n  ldr         r1, =player_score\n  ldr         r2, [r1]\n  addlt       r2, r2, #50\n  addge       r2, r2, #100\n  str         r2, [r1]\n  vmovle.f32  s2, r9\n  vmov.f32    s6, r9\n  mov         r0, #0\n\n2:\n  vstm.f32    r11!, {s0 - s7}\n  subs        r12, r12, #1\n  bne         1b\n\n  vldmia.f32  sp!, {s0 - s8}\n  ldmfd       sp!, {r1 - r12, pc}\n\n@-------------------------------------------------------------------------------\n@ Resets rockets\n@-------------------------------------------------------------------------------\nreset_rockets:\n  stmfd       sp!, {r0 - r3, lr}\n  vstmdb.f32  sp!, {s0 - s5}\n\n  ldr         r3, =ROCKET_COUNT\n  ldr         r2, =rocket_list\n  ldr         r1, =0x3E800000    @ 0.25\n  mov         r0, #0\n\n1:\n  vldm.f32    r2, {s0 - s5}\n\n  vmov.f32    s0, r0\n  vmov.f32    s1, r0\n  vmov.f32    s2, r0\n  vmov.f32    s3, r1\n  vmov.f32    s4, r0\n  vmov.f32    s5, r0\n\n  vstm.f32    r2!, {s0 - s5}\n\n  subs        r3, #1\n  bne         1b\n\n  vldmia.f32  sp!, {s0 - s5}\n  ldmfd       sp!, {r0 - r3, pc}\n"
  },
  {
    "path": "sound.s",
    "content": "@ This file is part of the Team 28 Project\n@ Licensing information can be found in the LICENSE file\n@ (C) 2014 The Team 28 Authors. All rights reserved.\n.global setup_sound\n.global update_sound\n\n.include \"ports.s\"\n\n@ ------------------------------------------------------------------------------\n@ Macro that simplifies adding new sounds\n@ ------------------------------------------------------------------------------\n.macro sound name\n  .long 0                    @ Play flag\n  .long \\name\\()_start       @ Address of current chunk\n  .long \\name\\()_start       @ Start address of sample\n  .long \\name\\()_end         @ End address of sample\n  .global snd_play_\\name\n  snd_play_\\name:            @ Start playing\n    push  {r0}\n    mov   r0, #1\n    str   r0, [pc, #-32]\n    pop   {r0}\n    mov   pc, lr\n  .global snd_stop_\\name\n  snd_stop_\\name:\n    push  {r0}\n    mov   r0, #0\n    str   r0, [pc, #-52]\n    pop   {r0}\n    mov   pc, lr\n.endm\n\n.section .text\n@ ------------------------------------------------------------------------------\n@ Initialises the sound module, setting up GPIO 40 and 45 to use PWM and\n@ programming DMA channel 1 with two control blocks chained together that\n@ write data to the GPIO ports\n@\n@ Arguments:\n@   none\n@ Returns:\n@   none\n@ Clobbers:\n@   r0 - r3\n@ ------------------------------------------------------------------------------\nsetup_sound:\n  @ Copy first chunk of background music into buffers\n  ldr         r0, =corneria_start\n  ldr         r1, =dma_buffer_0\n  ldr         r2, =0x2000\n  mov         r3, #0\n1:\n  ldrb        r3, [r0], #1\n  str         r3, [r1], #4\n  subs        r2, r2, #1\n  bne         1b\n\n  ldr         r1, =dma_buffer_1\n  ldr         r2, =0x2000\n1:\n  ldrb        r3, [r0], #1\n  str         r3, [r1], #4\n  subs        r2, r2, #1\n  bne         1b\n\n  @ Set GPIO 40 & 45 to PWM\n  ldr         r0, =GPIO_FSEL4\n  ldr         r1, [r0]\n  ldr         r2, =0x00038007\n  bic         r1, r1, r2\n  ldr         r2, =0x00020004\n  orr         r1, r1, r2\n  str         r1, [r0]\n\n  @ Setup clock\n  ldr         r0, =CM_PWMDIV\n  ldr         r1, =0x5A002000\n  str         r1, [r0]\n  ldr         r0, =CM_PWMCTL\n  ldr         r1, =0x5A000016\n  str         r1, [r0]\n\n  @ Setup PWM\n  ldr         r1, =0x00002C48\n  ldr         r0, =PWM_RNG1\n  str         r1, [r0]\n  ldr         r0, =PWM_RNG2\n  str         r1, [r0]\n  ldr         r0, =PWM_CTL\n  ldr         r1, =0x00002161\n  str         r1, [r0]\n\n  @ Setup PWM to use DMA\n  ldr         r0, =PWM_DMAC\n  ldr         r1, =0x80000001\n  str         r1, [r0]\n\n  @ Enable DMA0\n  ldr         r0, =DMA_ENABLE\n  ldr         r1, =0x00000001\n  str         r1, [r0]\n\n  @ Set DMA0 control block\n  ldr         r0, =DMA0_CONBLK\n  adr         r1, DMA_CTRL_1\n  str         r1, [r0]\n\n  @ Start DMA0\n  ldr         r0, =DMA0_CS\n  ldr         r1, =0x00000001\n  str         r1, [r0]\n\n  mov         pc, lr\n\n@ ------------------------------------------------------------------------------\n@ Should be called when DMA triggers an interrupt, but unfortunately the\n@ hardware seems incapable of triggering it. Fortunately, we can poll for the\n@ interrupt flag in the DMA interrupt status register and call the function\n@ ourselves\n@\n@ Arguments:\n@   none\n@ Clobbers:\n@   none\n@ Returns:\n@   none\n@ ------------------------------------------------------------------------------\nupdate_sound:\n  stmfd       sp!, {r0 - r10, lr}\n\n  ldr         r0, =DMA_INT_STATUS\n  ldr         r1, [r0]\n  tst         r1, r1\n  ldmeqfd     sp!, {r0 - r10, pc}\n\n  ldr         r0, =DMA0_CS\n  ldr         r1, =0x00000005\n  str         r1, [r0]\n\n  @ Swap buffers\n  ldr         r1, =buffer_index\n  ldr         r0, [r1]\n  add         r0, r0, #1\n  and         r0, r0, #1\n  str         r0, [r1]\n\n  @ Find target buffer\n  tst         r0, r0\n  ldrne       r0, =dma_buffer_0\n  ldreq       r0, =dma_buffer_1\n\n  @ Copy background sound\n  ldr         r1, =corneria_start\n  ldr         r2, =corneria_ptr\n  ldr         r3, [r2]\n  ldr         r4, =corneria_end\n  sub         r4, r4, #0x2000\n  add         r3, r3, #0x2000\n  cmp         r3, r4\n  movge       r3, r1\n  str         r3, [r2]\n\n  ldr         r4, =0x2000\n  mov         r2, r0\n1:\n  ldrb        r5, [r3], #1\n  lsl         r5, r5, #3\n  str         r5, [r2], #4\n  subs        r4, r4, #1\n  bne         1b\n\n  @ Play sounds\n  ldr         r9, =sounds\n  mov         r10, #9\n1:\n  ldr         r5, [r9]\n  tst         r5, r5\n  beq         3f\n\n  ldr         r5, [r9, #4]\n  ldr         r3, =0x2000\n  mov         r7, r0\n2:\n  ldrb        r6, [r5], #1\n  sub         r6, r6, #0x7F\n  ldr         r8, [r7]\n  add         r8, r8, r6, lsl #3\n  str         r8, [r7], #4\n\n  subs        r3, r3, #1\n  bne         2b\n\n  ldr         r3, [r9, #8]\n  ldr         r4, [r9, #12]\n  cmp         r5, r4\n  movge       r5, r3\n  str         r5, [r9, #4]\n  movge       r5, #0\n  strge       r5, [r9]\n3:\n  add         r9, #56\n  subs        r10, r10, #1\n  bne         1b\n\n  ldmfd       sp!, {r0 - r10, pc}\n\n\n.ltorg\n.section .text\n@ ------------------------------------------------------------------------------\n@ DMA control structures - chained after each other\n@ ------------------------------------------------------------------------------\n.align 5\nDMA_CTRL_0:\n  .long 0x00050141    @ Attributes\n  .long dma_buffer_0  @ Source address\n  .long 0x7E20C018    @ Destination Address\n  .long 0x8000        @ Transfer length\n  .long 0\n  .long DMA_CTRL_1\n\n.align 5\nDMA_CTRL_1:\n  .long 0x00050141    @ Attributes\n  .long dma_buffer_1  @ Source address\n  .long 0x7E20C018    @ Destination Address\n  .long 0x8000        @ Transfer length\n  .long 0\n  .long DMA_CTRL_0\n\n\n.align 4\n@ ------------------------------------------------------------------------------\n@ DMA buffers\n@ ------------------------------------------------------------------------------\ndma_buffer_0:\n  .space 0x8000, 0\ndma_buffer_1:\n  .space 0x8000, 0\n\n\n.align 2\n@ ------------------------------------------------------------------------------\n@ Sound effect states\n@ ------------------------------------------------------------------------------\nbuffer_index:\n  .long 1\n\nsounds:\n  sound bullet\n  sound roll\n  sound rock\n  sound crash\n  sound fail\n  sound boost\n  sound rocket\n  sound cantlet\n  sound pickup\n\n.section .data\n@ ------------------------------------------------------------------------------\n@ Background music\n@ ------------------------------------------------------------------------------\ncorneria_start: .incbin \"assets/corneria.bin\"\ncorneria_end:\ncorneria_ptr:   .long corneria_start\n\n@ ------------------------------------------------------------------------------\n@ Short sounds effects\n@ ------------------------------------------------------------------------------\nbullet_start:   .incbin \"assets/laser.bin\"\nbullet_end:\nroll_start:     .incbin \"assets/roll.bin\"\nroll_end:\nrock_start:     .incbin \"assets/rocknroll.bin\"\nrock_end:\ncrash_start:    .incbin \"assets/crash.bin\"\ncrash_end:\nfail_start:     .incbin \"assets/fail.bin\"\nfail_end:\nboost_start: \t  .incbin \"assets/boost.bin\"\nboost_end:\nrocket_start:   .incbin \"assets/rocketsound.bin\"\nrocket_end:\ncantlet_start:  .incbin \"assets/cantletyou.bin\"\ncantlet_end:\npickup_start:   .incbin \"assets/pickup.bin\"\npickup_end:\n"
  },
  {
    "path": "test.s",
    "content": "@ This file is part of the Team 28 Project\n@ Licensing information can be found in the LICENSE file\n@ (C) 2014 The Team 28 Authors. All rights reserved.\n.global run_tests\n\n.section .data\n@-------------------------------------------------------------------------------\n@ Sin and Cos test cases\n@-------------------------------------------------------------------------------\nangle_input:\n  .float -777.0, -10.0, -6.283, -3.6, -3.1415, -3.0, -2.8, -2.5, -2.2, -2.0\n  .float -1.8, -1.57075, -1.047197, -0.785375, -0.5\n  .float  0.0\n  .float  777.0,  10.0,  6.283,  3.6, 3.1415,  3.0,  2.8,  2.5,  2.2,  2.0\n  .float  1.8, 1.57075,  1.047197,  0.785375,  0.5\n\n@-------------------------------------------------------------------------------\n@ Sin output destination\n@-------------------------------------------------------------------------------\nsin_output:\n  .float  2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0\n  .float  2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0\n  .float  2.0, 2.0, 2.0, 2.0\n\n@-------------------------------------------------------------------------------\n@ Cos output destination\n@-------------------------------------------------------------------------------\ncos_output:\n  .float  2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0\n  .float  2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0\n  .float  2.0, 2.0, 2.0, 2.0\n\n.section .text\n@-------------------------------------------------------------------------------\n@ Runs test functions\n@ Arguments:\n@   None\n@ Returns:\n@   None\n@ Clobbers:\n@   None\n@-------------------------------------------------------------------------------\nrun_tests:\n  stmfd       sp!, {r0 - r2, lr}\n\n  @ test sin\n  ldr         r0, =angle_input\n  mov         r1, #30\n  ldr         r2, =sin_output\n  bl          sin_test\n\n  @ test cos\n  ldr         r0, =angle_input\n  mov         r1, #30\n  ldr         r2, =cos_output\n  bl          cos_test\n\n  ldmfd       sp!, {r0 - r2, pc}\n\n@ ------------------------------------------------------------------------------\n@ Sin function test\n@ Arguments:\n@   r0 - address of inputs\n@   r1 - number of inputs\n@   r2 - destination for outputs\n@ Returns:\n@  None\n@ Clobbers:\n@  None\n@ ------------------------------------------------------------------------------\nsin_test:\n  stmfd       sp!, {r0 - r4, lr}\n  vstmdb      sp!, {s0 - s1}\n  mov         r3, #0\n\n1:\n  cmp         r3, r1\n  bge         2f\n\n  ldr         r4, [r0]\n  vmov.f32    s0, r4\n  bl          sin\n  vstm.f32    r2, {s1}\n\n  add         r0, r0, #4\n  add         r2, r2, #4\n  add         r3, r3, #1\n  b           1b\n\n2:\n  vldmia.f32  sp!, {s0 - s1}\n  ldmfd       sp!, {r0 - r4, pc}\n\n@ ------------------------------------------------------------------------------\n@ Cos function test\n@ Arguments:\n@   r0 - address of inputs\n@   r1 - number of inputs\n@   r2 - destination for outputs\n@ Returns:\n@  None\n@ Clobbers:\n@  None\n@ ------------------------------------------------------------------------------\ncos_test:\n  stmfd       sp!, {r0 - r4, lr}\n  vstmdb      sp!, {s0 - s1}\n  mov         r3, #0\n\n1:\n  cmp         r3, r1\n  bge         2f\n\n  ldr         r4, [r0]\n  vmov.f32    s0, r4\n  bl          cos\n  vstm.f32    r2, {s1}\n\n  add         r0, r0, #4\n  add         r2, r2, #4\n  add         r3, r3, #1\n  b           1b\n\n2:\n  vldmia.f32  sp!, {s0 - s1}\n  ldmfd       sp!, {r0 - r4, pc}\n"
  },
  {
    "path": "toolchains/arm-none-eabi.cmake",
    "content": "#   Copyright (c) 2013, Brian Sidebotham\n#   All rights reserved.\n\n#   Redistribution and use in source and binary forms, with or without\n#   modification, are permitted provided that the following conditions are met:\n\n#   1. Redistributions of source code must retain the above copyright notice,\n#       this list of conditions and the following disclaimer.\n\n#   2. Redistributions in binary form must reproduce the above copyright notice,\n#       this list of conditions and the following disclaimer in the\n#       documentation and/or other materials provided with the distribution.\n\n#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n#   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n#   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n#   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n#   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n#   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n#   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n#   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n#   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n#   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n#   POSSIBILITY OF SUCH DAMAGE.\n\n# A CMake toolchain file so we can cross-compile for the Rapsberry-Pi bare-metal\n\n# usage\n# cmake -DCMAKE_TOOLCHAIN_FILE=../toolchain-arm-none-eabi.cmake ../\n\ninclude( CMakeForceCompiler )\n\n# The Generic system name is used for embedded targets (targets without OS) in\n# CMake\nset( CMAKE_SYSTEM_NAME          Generic )\nset( CMAKE_SYSTEM_PROCESSOR     BCM2385 )\n\n# Set a toolchain path. You only need to set this if the toolchain isn't in\n# your system path. Don't forget a trailing path separator!\nset( TC_PATH \"\" )\n\n# The toolchain prefix for all toolchain executables\nset( CROSS_COMPILE arm-none-eabi- )\n\n# specify the cross compiler. Force the compiler so it doesn't perform checks.\n# We don't want to attempt to test the compiler when we're using a custom\n# linker script for example, or we're not linking against a c library as it'll\n# fail. See: http://www.cmake.org/Wiki/CMake_Cross_Compiling\ncmake_force_c_compiler( ${TC_PATH}${CROSS_COMPILE}gcc GNU )\ncmake_force_cxx_compiler( ${TC_PATH}${CROSS_COMPILE}g++ GNU )\n\n# We must set the OBJCOPY setting into cache so that it's available to the\n# whole project. Otherwise, this does not get set into the CACHE and therefore\n# the build doesn't know what the OBJCOPY filepath is\nset( CMAKE_OBJCOPY      ${TC_PATH}${CROSS_COMPILE}objcopy\n    CACHE FILEPATH \"The toolchain objcopy command \" FORCE )\n\n"
  }
]