Almost everything you'll need is in the ARMv8 Architecture Reference Manual and Cortex-72A Processor Technical Reference Manual. I highly recommend downloading a copy of each PDF. Some of their contents are reproduced below.
Term | Definition |
---|---|
cortex-72a | the processor used by the Raspberry Pi 4 |
broadcom bcm2711 | same as above (???) |
instruction encoding | the encoding for translating assembly into machine code |
This is the fastest place to store data.
Register | Description |
---|---|
MPIDR_EL1 | This read-only identification register, among other things, provides a core identification number (how to access) |
r0-15 | General-purpose registers. Because we're writing our own assembly language, feel free to use these however you want |
Many peripherals (external io stuff) are accessible through special memory addresses. The Raspberry Pi 4's peripherals document has not yet been released, so for now we'll use the RPi 3's BCM2835 ARM Peripherals Manual.
BCM2835 ARM Peripherals, Page 175
PrimeCell UART Technical Reference Manual
Register addresses, with offset 0xFE201000
on raspi4
On QEMU, UART data can be sent/received by simply writing to/from 0xFE201000+0
, but on real hardware, you'll need to do some setup first.
For the following setup steps, use the BCM2836 Peripheral Manual's GPIO address section, replacing 0x7E20
with 0xFE20
for the raspi4. Also see the manual's UART address section.
- disable UART using the UART control register
- disable GPIO pin pull up/down
- delay for 150 cycles (create a loop with a countdown)
- disable GPIO pin pull up/down clock 0
- delay for 150 cycles
- disable GPIO pin pull up/down clock 0 (yeah, again; idk why)
- clear all pending interrupts using the UART interrupt clear register (write zero to the bits representing each interrupt you want to clear)
- set baud rate to 115200 given a 3 Mhz clock (follow the PrimeCell UART Manual's baud rate calculation example)
- write the baud rate divisor integer (BDR_I) to the UART integer baud rate divisor register
- write the calculated fractional part (m) to the UART fractional baud rate divisor register
- enable FIFO and 8-bit data transmission using the UART line control register
- mask all interrupts using the [TODO...]
The aarch64 instruction encoding is 32 bits wide, so we cannot store large constants into registers in a single command.
See the register summaries above for the parameters needed to access a specific system register.
31 21 20 12 11 10 9 6 0
vv v v v v vv vv
'F'E'D'C'B'A'9'8'7'6'5'4'3'2'1'0 F E D C B A 9 8 7 6 5 4 3 2 1 0
1 1 1 1 1 0 0 0 0 0 0 [ imm 9] 1 1 [ Rn 5][ Rt 5]
Reads the address Rn + imm
from memory and stores it into Rt
.
Rt <- *(Rn + imm)
Reads the address Rn
from memory stores it into Rt
, then updates Rn
to Rn + imm
.
Rt <- *Rn
Rn <- Rn + imm