Warning
This page is located in archive.

Lab 06

MicroPython allows programmers to use inline assembler. The inline assembler supports a subset of the ARM Thumb-2 instruction set. The syntax tries to be as close as possible to that defined in the above ARM manual, converted to Python function calls.

Lesson objectives

  • Introduce ARM assembler instructions

Documents

Assembler instructions

Instructions operate on 32 bit signed integer data except where stated otherwise. Most supported instructions operate on registers R0-R7 only: where R8-R15 are supported this is stated. Registers R8-R12 must be restored to their initial value before return from a function. Registers R13-R15 constitute the Link Register, Stack Pointer and Program Counter respectively.

Register moves

Where immediate values are used, these are zero-extended to 32 bits. Thus mov(R0, 0xff) will set R0 to 255.

  • mov(Rd, imm8) → Rd = imm8
  • mov(Rd, Rn) → Rd = Rn
  • movw(Rd, imm16) → Rd = imm16
  • movt(Rd, imm16) → Rd = (Rd & 0xffff) | (imm16 « 16)

movt writes an immediate value to the top halfword of the destination register. It does not affect the contents of the bottom halfword.

  • movwt(Rd, imm32) → Rd = imm32

movwt is a pseudo-instruction: the MicroPython assembler emits a movw followed by a movt to move a 32-bit value into Rd.

Register load

  • ldr(Rt, [Rn, imm7]) → Rt = [Rn + imm7] Load a 32 bit word
  • ldrb(Rt, [Rn, imm5]) → Rt = [Rn + imm5] Load a byte
  • ldrh(Rt, [Rn, imm6]) → Rt = [Rn + imm6] Load a 16 bit half word

Where a byte or half word is loaded, it is zero-extended to 32 bits.

Register Store

  • str(Rt, [Rn, imm7]) → [Rn + imm7] = Rt Store a 32 bit word
  • strb(Rt, [Rn, imm5]) → [Rn + imm5] = Rt Store a byte (b0-b7)
  • strh(Rt, [Rn, imm6]) → [Rn + imm6] = Rt Store a 16 bit half word (b0-b15)

Logical instructions

  • and_(Rd, Rn) → Rd &= Rn
  • orr(Rd, Rn) → Rd |= Rn
  • eor(Rd, Rn) → Rd ^= Rn
  • mvn(Rd, Rn) → Rd = Rn ^ 0xffffffff i.e. Rd = 1’s complement of Rn
  • bic(Rd, Rn) → Rd &= ~Rn bit clear Rd using mask in Rn

Note the use of and_ instead of and, because and is a reserved keyword in Python.

Shift and rotation instructions

  • lsl(Rd, Rn<0-31>) → Rd «= Rn
  • lsr(Rd, Rn<1-32>) → Rd = (Rd & 0xffffffff) » Rn Logical shift right
  • asr(Rd, Rn<1-32>) → Rd »= Rn arithmetic shift right
  • ror(Rd, Rn<1-31>) → Rd = rotate_right(Rd, Rn) Rd is rotated right Rn bits.

A rotation by (for example) three bits works as follows. If Rd initially contains bits b31 b30..b0 after rotation it will contain b2 b1 b0 b31 b30..b3

Branch to label

  • b(LABEL) → Unconditional branch
  • beq(LABEL) → branch if equal
  • bne(LABEL) → branch if not equal
  • bge(LABEL) → branch if greater than or equal
  • bgt(LABEL) → branch if greater than
  • blt(LABEL) → branch if less than (<) (signed)
  • ble(LABEL) → branch if less than or equal to (⇐) (signed)
  • bcs(LABEL) → branch if carry flag is set
  • bcc(LABEL) → branch if carry flag is clear
  • bmi(LABEL) → branch if negative
  • bpl(LABEL) → branch if positive
  • bvs(LABEL) → branch if overflow flag set
  • bvc(LABEL) → branch if overflow flag is clear
  • bhi(LABEL) → branch if higher (unsigned)
  • bls(LABEL) → branch if lower or equal (unsigned)

Inline assembler functions

Inline assembler functions are denoted by a special function decorator. Let’s start with the simplest example:

@micropython.asm_thumb
def fun():
    movw(r0, 42)

This function takes no arguments and returns the number 42. r0 is a register, and the value in this register when the function returns is the value that is returned. MicroPython always interprets the r0 as an integer, and converts it to an integer object for the caller.

If you run print(fun()) you will see it print out 42.

Inline assembler functions can accept up to 4 arguments. If they are used, they must be named r0, r1, r2 and r3 to reflect the registers and the calling conventions.

Here is a function that adds its arguments:

@micropython.asm_thumb
def asm_add(r0, r1):
    add(r0, r0, r1)

This performs the computation r0 = r0 + r1. Since the result is put in r0, that is what is returned. Try asm_add(1, 2), it should return 3.

GPIO manipulation

To manipulate with GPIO output we can use SIO memory mapped registers:

Registers GPIO_OUT_SET and GPIO_OUT_CLR perform an atomic bit-set and bit-clear respectively.

courses/be2m37mam/labs/06.txt · Last modified: 2024/11/28 16:11 by viteks