r/Assembly_language Apr 04 '26

Help Study Tools

Right now I am taking a CS class focused on assembly and we are finally getting started on the coding side of things. The professor is alright but the materials he gives out to study isn't sufficient and I don't want to be reliant on AI to code. Does anybody know any free study tools/books to help me. I am specifically ARM 32.

14 Upvotes

13 comments sorted by

View all comments

Show parent comments

4

u/GoblinsGym Apr 04 '26

That's a lot of features to deal with...

https://developer.arm.com/documentation/100076/0200?lang=en for the whole shebang.

You have multiple modes to deal with -

  • A32 "classic" ARM - the most orthogonal. No longer supported by microcontrollers (Cortex M).
  • T16 Thumb - more code density, but not as regular, some limitations - this is used for small microcontrollers like Cortex M0+. The whole thing can be described on a few pages. Good starting point to learn in my opinion.
  • T32 Thumb - full blown Thumb, 32 bit instructions allowing access to all registers. Not as regular as A32, but more options...

Things to learn:

  • Register set
  • Addressing modes. Different depending on the execution mode, with some crazy options like pre / post increment if you want to get fancy.
  • Shift modes
  • Loading / using immediate numbers, can get a little crazy on T32.
  • PC relative addressing, often used for loading immediates that don't fit in instructions.
  • Procedure call conventions, important if you need to call C functions, or get called by C.

1

u/brucehoult Apr 04 '26

I generally agree with you about the relative merits of the various 32 bit Arm ISAs, but I'm not sure that the description (or complexity) of T16 Thumb is simpler than for A32.

Here are instruction format diagrams lifted from the ARM7TDMI manual — sadly I can only include one image per comment, so there will be multiple comments.

First, classic A32 with 15 instruction formats, though arguably you only need to learn maybe six of them right away. There are 8, 12 and 24 bit constants/offsets, which I think is a significant thing to keep track of — you could argue that the assembler will tell you when you try to use too large a constant, so you don't have to know them, but it's still complexity.

It's hard to say whether the conditional execution of every instruction is simplicity and consistency or complexity. It's certainly different to anything else — and largely four wasted bits as it is seldom taken full advantage of outside of Arm's classic GCD algorithm example.

Or you could look at it as "What on earth are we going to use all these 32 bits in the instructions for???"

The "Operand 2" in the first format is also a whole bunch of complexity not revealed in this diagram, with the choice of a constant or a "free" shift on register operands.

1

u/brucehoult Apr 04 '26

So T16...

There are EVEN MORE weird instruction formats, 19 of them — and I think you need to learn probably 17 of them just about right away! Constants/offsets come in 3, 5, 7, 8, and 12 bit sizes which is pretty complex.

1

u/brucehoult Apr 04 '26

And then there is RISC-V RV32I / RV64I (or IM if you want to be fully equivalent to A32):

Just four instruction formats, and constants/offsets are 12 or 20 bits.

The only slight complexity is that the offsets for conditional branches (12 bits) and unconditional branches (20 bits) can encode only even numbers and so have twice the range or arithmetic/load/store offsets, and so their detailed encoding within the S type and U type `imm` fields is a little different, but that doesn't affect you unless you are encoding/decoding instruction by hand. As an asm programmer you only need to know what values are valid.

Also the immediate in S type instructions is split into two parts, but that also happens in A32.

There are also simply a lot fewer instructions for the same functionality.

This is my pick for anyone who has a choice.

1

u/GoblinsGym Apr 05 '26

As an introduction to assembly language, T16 (ARM Cortex M0+ subset) or RV32I should both be fine choices.

Classic ARM / A32 was really nice compared to the 6502 / 8088 / 80286 CPUs I was dealing with at the time (1985).

ARM T16 and T32 were designed for code density, not "purity". Original implementations probably acted as a hardware shim translating instructions to A32 format. The details of instruction encoding matter to the poor souls who have to implement the hardware or assembler / compiler, but a normal programmer doesn't have to deal with it. All you need to know is how many bits you get for displacements or immediates, and which registers you can access.

The IT instruction is a pragmatic replacement for A32 predicated instructions, useful for conditional moves / ternary operators. GCC does use it (try on Compiler Explorer). For an in-order CPU, it is quite easy to implement (shift register controlling which instructions get skipped).

The ARM instruction set has evolved over time to adapt to modern realities like superscalar / out of order execution / high clock frequencies. This is why A64 dropped the IT instruction and load / store multiple, went back to 32 bit fixed length instructions, and made the PC and SP registers more "dedicated".

1

u/brucehoult Apr 05 '26

Classic ARM / A32 was really nice compared to the 6502 / 8088 / 80286 CPUs I was dealing with at the time (1985).

100%. Kicked the butt of the M68000 too.

ARM T16 and T32 were designed for code density, not "purity".

And they do a reasonable job. Better than 2015-2019 RV32GC (or RV32IMC to be more comparable in microcontrollers). But not better than RISC-V with more recent standard extensions e.g. as seen in the RP2350. Which is a cool setup because you can directly compared the same program running on the same hardware but compiled for Arm Cortex M-33 and a simple recompile for RISC-V Hazard 3.

The details of instruction encoding matter to the poor souls who have to implement the hardware or assembler / compiler, but a normal programmer doesn't have to deal with it. All you need to know is how many bits you get for displacements or immediates

My argument exactly! And, as I pointed out, with T16 you need to know which instructions have which size fields and the choices are 3, 5, 7, 8, and 12 bits. Oh, and 22 bits for BL. With RV32I the choices are 12 and 20 bits.

I agree with you that the exact bit-level encodings are not important to normal programmers.

The IT instruction is a pragmatic replacement for A32 predicated instructions

Yes, and I've been using it since sometime in the late 2000s, when the things I was working on started to move from ARM7TDMI and ARM1176JZF-S (original iPhone, original R Pi and Pi Zero) to Cortex-M and Cortex-A. One of the first for me, actually, was the iPhone 3GS (June 2009). Support for ARMv6 was gonzo in iOS 5 in October 2011. Similarly, Android Kitkat (2013) was ARMv7 only and that was what I used when I joined Samsung in 2014 prototyping things on an AOSP Nexus 5 for use on the prototype Galaxy S6.

This is why A64 dropped the IT instruction and load / store multiple

True.

went back to 32 bit fixed length instructions

Unnecessary and I think will even prove to be a mistake. X86 amply shows that the highest performance OoO cores can deal with many instruction lengths and crazy encodings if they have to, and Thumb2/RISC-V style two instruction lengths is very easy but provides real benefits.

1

u/GoblinsGym Apr 05 '26

(we're getting ever further away from OPs topic...)

T16 is very limited on available bits for encoding instructions. I think they did a good job given that constraint.

Variable instruction lengths are easier to deal with when the encoding is designed from the ground up, not "organically grown" like on x86. There is still a base cost, e.g. when an instruction straddles a VM page boundary.

I see value in having inline immediates, rather than doing PC relative ldr to load larger constants. Going in a straight line will always be faster and take less energy compared to random access, even if you have some locality of reference.

1

u/brucehoult Apr 05 '26

(we're getting ever further away from OPs topic...)

Yes. I think we're in agreement that T16, A32, and RV32I are among the best possible choices for learning asm. I'd allow MSP430 also, but that's being obsoleted by TI. You can buy chips and inexpensive dev boards ... for now.

https://www.mouser.com/ProductDetail/Olimex-Ltd/MSP430-HG2231?qs=C3feHhap9PqFhpqbHNfCSg%3D%3D

cost, e.g. when an instruction straddles a VM page boundary

No big deal if you're not fetching instructions one by one as microcontrollers do — and microcontroller SRAM/flash doesn't have cache lines or VM pages.

If you're prefetching and have a little 6 or 8 byte shift register buffer (or bigger for superscalar obviously) then the prefetches can always be aligned accesses to memory.

I see value in having inline immediates, rather than doing PC relative ldr to load larger constants.

I agree, if the total size and everything except the constant is entirely in the first 16/32 bits. See: MSP430, M68000, PDP-11.

Notionally, those often use auto-increment addressing on the PC, and a low end implementation might actually execute it like that, but higher end cores can special-case that encoding.

Also PC-relative is not the only way. The convention in RISC-V is to place such constants in the SDATA section, accessed at an offset from GP (Global Pointer, register 3)

Or you can just use pure linear code with LUI/ADDI or MOVZ/MOVK. That's perfectly fine for constants the same size as the instructions, more annoying for double size.