{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# THIS IS A WORK IN PROGRESS\n", "\n", "Welcome to the introduction to ARM assembly and IArm\n", "\n", "# What is ARM?\n", "ARM is a RISC CPU architecture that is commonly used on embeded devices.\n", "\n", "# What is Assembly?\n", "Assembly is a low level programming language.\n", "It is generally used for very performant code, very efficient code,\n", "or for direct access to the hardware.\n", "\n", "# What is IArm?\n", "IArm is an ARM assembly language interpreter.\n", "Normally, assembly is compiled from the source code to machine code.\n", "This machine code is then run on the CPU.\n", "IArm allows you to write code on your computer, and run it step by step,\n", "without the need for the actual hardware.\n", "\n", "# How do I write assembly?\n", "Each assembly line is broken up into three parts.\n", "The first part is the label.\n", "The label is used to reference whatever this particular line of code is.\n", "It can be used for loops, or for holding addresses of memory.\n", "The label is optional, so only use it when needed.\n", "\n", "The second part is the instruction.\n", "This is the actual instruction that will be executed.\n", "\n", "The last part is the instruction operands.\n", "These will be used by the instruction to perform the action.\n", "\n", "`[Label] Instruction [Operand1[, Operand2[, Operand3]]]`\n", "\n", "It is important to note that if no label is used,\n", "the instruction must be spaced or tabbed over.\n", "Any word that begins on a line with no spaces to\n", "the left will be interpreted as as a label.\n", "\n", "# Putting values into registers\n", "The first instruction is the `MOVS` instruction.\n", "`MOVS` stands for \"Move, set\" which will move the value of\n", "operand 2 into the register in operand 1 and set the status register.\n", "The `MOVS` instruction must be used to load in immediate.\n", "\n", "Comments can also be added, and start with `;`.\n", "Anything after a `;` will be ignored.\n", "\n", "To execute the code, select the cell and press Shift + Enter" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false }, "outputs": [], "source": [ "; Put the value 5 into register 0\n", " MOVS R0, #5" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This will put the code into a program that can be executed. If there were any problems with the code, an error will be reported.\n", "\n", "In order to read a register in IArm,\n", "we need to use the `%register` magic function.\n", "This will print out the value of the register.\n", "You can also use `%reg` for short." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "R0: 0\n" ] } ], "source": [ "%reg R0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Why is the value 0?\n", "We did not instruct IArm to run the code,\n", "so it is simply spitting out the initial value which is 0.\n", "To run the code, we specify the `%run` magic,\n", "which will run to the end of our current program.\n", "the `%run` magic also can take in an integer\n", "to specify how many instructions to run." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "R0: 5\n" ] } ], "source": [ "%run\n", "%reg R0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Arithmetic\n", "The ARM instruction set comes with a multitude of mathematical instructions to\n", "add, subtract, and multiply (no divide though)." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [], "source": [ "; Add R0 and 1 and store it in R1\n", " ADDS R1, R0, #1\n", "\n", "; Subtract 10 from R1 and store it in R2\n", " SUBS R2, R1, #7\n", "\n", "; Multiply R0 by 5\n", " MOVS R3, #5\n", " MULS R3, R0, R3 ; Operand 1 and Operand 3 must be the same register\n", "\n", "; Integer divide by 4 by bit shifting to the right by 2\n", " LSRS R5, R3, #2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When looking at registers, we can specify multiple registers,\n", "separated by spaces.\n", "Ranges can also be used by specifying the start and end register,\n", "separated by a hyphen (`Rn-Rk`)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "R0: 5\n", "R1: 6\n", "R2: 4294967295\n", "R3: 25\n", "R5: 6\n" ] } ], "source": [ "%run\n", "%reg R0-R3 R5" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\"Whoa, whats going on with R2?\".\n", "We should have gotten -1, why is it in the millions?\n", "\n", "It is -1, that is just the unsigned integer notation for it.\n", "To turn on signed representations,\n", "simply call the `%signed` magic." ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "R2: -1\n" ] } ], "source": [ "%signed\n", "%reg R2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Values can also be represented in hexadecimal by using the `%hex` magic." ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "R2: 0xffffffff\n", "R0: 0x5\n", "R3: 0x19\n" ] } ], "source": [ "%hex\n", "%reg R2 R0 R3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To go back to the unsigned representation, use the `%unsigned` magic." ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "R2: 4294967295\n", "R0: 5\n", "R3: 25\n" ] } ], "source": [ "%unsigned\n", "%reg R2 R0 R3" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "You can get help on any particular magic or instruction by using the `%help` magic.\n", "Calling it with no parameters will list all available magics,\n", "while calling it with a magic or instructin will print out its help." ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "%register\n", "%run\n", "%postpone_execution\n", "%help\n", "%generate_random\n", "%memory\n", "%signed\n", "%mem\n", "%hex\n", "%reg\n", "%unsigned\n" ] } ], "source": [ "%help" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": false, "scrolled": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "unsigned\n", "\n", " All outputted values will be displayed with their unsigned representation\n", "\n", " Usage:\n", " Just call this magic\n", "\n", " `%unsigned`\n", " " ] } ], "source": [ "%help unsigned" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ADDS\n", "\n", " ADDS Ra, Rb, Rc\n", " ADDS Ra, Rb, #imm3\n", " ADDS Ra, Ra, #imm8\n", "\n", " Add the result of the last two operands and store the result in the first operand.\n", " Set the NZCV flags\n", " " ] } ], "source": [ "%help ADDS" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Memory\n", "Memory can be accessed with the `LDR` and `STR`." ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": false }, "outputs": [], "source": [ "; Clear R2\n", " MOVS R2, #0\n", " \n", " ; Load an address into R0\n", " MOVS R0, #4\n", " \n", " MOVS R1, #12\n", " STR R1, [R0, #0] ; Store 11 at byte 4\n", " LDR R2, [R0, #0] ; Load the word at byte 4 and put it into R2" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "R1: 12\n", "R2: 12\n" ] } ], "source": [ "%run\n", "%reg R1 R2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There is also a stack that can be accessed with the `PUSH` and `POP` instructions." ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": false }, "outputs": [], "source": [ " MOVS R0, #100\n", " PUSH {R0} ; List of registers separated by commas\n", " POP {R5}" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "R0: 100\n", "R5: 100\n" ] } ], "source": [ "%run\n", "%reg R0 R5" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Subroutines and branching\n", "In order to make programing easier, one can write subroutines.\n", "These are similar to functions.\n", "Instead of being called, they are branched to.\n", "They will then return to the next instruction after the branch.\n", "\n", "To branch to a subroutine, use the `BL` instruction.\n", "This puts the next instructions address into the Link Register,\n", "a register specifically for use with branching.\n", "\n", "To return from an instruction, use the `BX` instruction.\n", "You can also `PUSH` the link register into the stack,\n", "and then `POP` into the `PC` register.\n", "This allows for multi-subroutine calls." ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "collapsed": false }, "outputs": [], "source": [ " B main ; Branch to the main code. This is to avoid executing the subroutine\n", "\n", "; factorial\n", "; Compute the factorial of the value in R0, storing the result in R1\n", "; Uses R2, but saves state\n", "factorial\n", " PUSH {LR, R2} ; Save the return address and the value of R2\n", " MOVS R1, #1 ; Init the result to 1 (0! and 1! = 1)\n", " MOVS R2, #1 ; Init the coutner to 1\n", "f_compare CMP R0, R2 ; R0 - R2, set flags\n", " BEQ f_cleanup ; Are R0 and R2 equal?\n", " ADDS R2, R2, #1 ; Add one to the counter\n", " MULS R1, R2, R1 ; Multiply the current result with the coutner\n", " B f_compare ; Check to see if we are done\n", "f_cleanup POP {PC, R2} ; Restore R2, then jump to the address\n", "\n", "main\n", " MOVS R2, #0\n", " MOVS R0, #5\n", " BL factorial" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "R0: 5\n", "R1: 120\n", "R2: 0\n" ] } ], "source": [ "%run\n", "%reg R0-R2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Other IArm features\n", "## Instant execution\n", "Be default, IArm will parse code, but delay execution until `%run` is called.\n", "If instructions should instead be immediately execuded after parsing,\n", "call the `%postpone_execution` magic with `false`" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "R7: 0\n", "R7: 1\n" ] } ], "source": [ "%postpone_execution false\n", "%reg R7\n", " MOVS R7, #1\n", "%reg R7" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Generating random values\n", "In a simulator, when a value is not initalized but is read from, normally zero is returned.\n", "This is not the case in hardware, where random bits will be set unless explicitly set so.\n", "This behaviour can be mimiced by setting the `%generate_random` magic.\n", "This is by default set to false.\n", "Once read, this will be the value until set." ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "R11: 0\n", "R11: 1514712368\n", "R11: 1514712368\n" ] } ], "source": [ "%reg R11\n", "%generate_random true\n", "%reg R11\n", "%reg R11" ] } ], "metadata": { "kernelspec": { "display_name": "IArm", "language": "ARM", "name": "iarm" }, "language_info": { "file_extension": ".s", "mimetype": "text/x-asm", "name": "ARM Coretex M0+ Thumb Assembly" } }, "nbformat": 4, "nbformat_minor": 0 }