Master the fundamental concepts of instruction set architecture through this focused micro-challenge.
You have read the whole brief, and the concepts above stay free on every task. Writing and running the code needs a plan.
Three hints are available for this task, revealed one at a time inside the code workspace so you can struggle productively before seeing them.
Every task includes starter code, theory, and hidden tests so you can implement and verify locally in the browser.
How it worksThumb-2 is ARM's 16/32-bit mixed ISA used on Cortex-M microcontrollers. Most instructions compress to 16 bits for flash savings; hot paths use 32-bit encodings for full ARM32 expressiveness without switching CPU mode.
cLoading…
Embedded devices care about code size in on-chip flash:
For example, an infinite blink loop on STM32 is almost entirely Thumb-16 B.N and STR instructions packed sequentially.
For this exercise, you will decode sample Thumb-2 halfwords and identify 16 vs 32-bit instruction boundaries. This task asks you to read the ISA map in the ARMv7-M manual the way firmware engineers do when patching a bootloader.
Keep the relevant datasheet, ISA manual, or architecture textbook chapter open while you implement. When your output disagrees with the reference trace on the same program, the bug is usually a mis-decoded opcode, a stale register read, or a flag bit left unchanged after arithmetic.
For this exercise, you will use those habits while implementing the requirement in the starter code. Microarchitectural product names change across CPU generations, but the control ideas (fetch, bypass, cache lines, vector lanes) stay stable enough to debug from first principles.
Decode Thumb-2, the mixed 16/32-bit ARM instruction set used by Cortex-M microcontrollers. The first job is finding the instruction boundaries: the top 5 bits of each halfword say whether it is a complete 16-bit instruction or the first half of a 32-bit one. Then disassemble the common 16-bit instructions and bl. Finally, measure how much flash Thumb-2 saves compared with fixed 4-byte ARM instructions.
Hex halfwords (16-bit values) in instruction-stream order, separated by whitespace. The first is at address 0, the next at 2, and so on.
If bits [15:11] of a halfword are 11101, 11110 or 11111, it is the first half of a 32-bit instruction, and the next halfword is the second half. Otherwise it is a complete 16-bit instruction.
d, n, m, t = 3-bit register numbers)| Pattern | Instruction |
|---|---|
00000 iiiii mmm ddd | lsls rd, rm, #i, or movs rd, rm when i = 0 |
0001100 mmm nnn ddd / 0001101 … | adds rd, rn, rm / subs rd, rn, rm |
0001110 iii nnn ddd / 0001111 … | adds rd, rn, #i / subs rd, rn, #i |
00100 ddd iiiiiiii / 00101 / 00110 / 00111 | movs rd, #i / cmp rd, #i / adds rd, #i / subs rd, #i |
01100 iiiii nnn ttt / 01101 … | str rt, [rn, #4i] / ldr rt, [rn, #4i] |
010001110 mmmm 000 | bx rm (4-bit register) |
1011010 L rrrrrrrr / 1011110 P rrrrrrrr | push {list} (+ lr if L) / pop {list} (+ pc if P) |
1101 cccc iiiiiiii (c < 14) | b<cond> target, cond = eq ne cs cc mi pl vs vc hi ls ge lt gt le, target = addr + 4 + 2·sext(i) |
11011111 iiiiiiii | svc #i |
11100 iiiiiiiiiii | b target, target = addr + 4 + 2·sext(i) |
1011111100000000 (bf00) | nop |
Anything else prints as .short 0xHHHH. Registers 13, 14 and 15 are named sp, lr and pc. Register lists go in ascending order, e.g. {r0, r4, lr}.
blFirst half 11110 S imm10, second half 11 J1 1 J2 imm11. Let I1 = NOT(J1 XOR S) and I2 = NOT(J2 XOR S). Then the offset is sext(S:I1:I2:imm10:imm11:0), 25 bits, and the target is addr + 4 + offset. Any other 32-bit instruction prints (32-bit instruction).
cLoading…
Addresses and targets are 4 hex digits (0x0004 in text). A truncated half counts as one 16-bit instruction. P = 100 · (ARM − T) / ARM with one decimal.
Input:
cLoading…
Output:
cLoading…
nop before the others).Hidden tests cover ldr/str offsets, lsls, beq forward, svc, an unknown 16-bit encoding, a non-bl 32-bit instruction, a backward bl, and a stream ending in half an instruction.