Skip to content

A side: Doing arithmetic

A cassette tape with a handwritten label: "A Side. Assembly - the first language of the machine."

A A side · Assembly · The first language of the machine

How do you tell the machine to calculate?

23 Assembly words in this segment
19 Fortran words for the same job

What Assembly says well here

  • Each verb is one exact processor step. You know the cost of each step.
  • Whole-number and fixed-point arithmetic is very fast.
  • A table in memory replaces a slow verb. MUL by 320 costs about 120 cycles on the 8086. One indexed MOV from a table of row starts costs about 20. The B side makes the table.
  • A byte register wraps at 256 by itself: add al, 64 turns a sine into a cosine. The A side wraps for free.

What is hard to say

  • One formula needs many verbs and many registers.
  • The 8086 has no verbs for decimal-point numbers. It needs an extra maths chip (the 8087) or slow software.
  • The 8086 has no decimal flag. After ADD or ADC on packed decimal bytes, write DAA. After SUB or SBB, write DAS. If you forget it, 09 + 1 becomes 0A, not 10.
  • y * 320 = (y << 8) + (y << 6), because 320 = 256 + 64. Join the two shifts with ADD, never with OR. An OR loses every carry.

One sentence in Assembly

mov ax, [speed]
add ax, [boost]
mov [speed], ax

It says: Make speed equal to speed plus boost. This takes three verbs.

The words, by part of speech

Verbs (22) · An instruction: one step that the processor does, for example MOV or ADD.

WordMeaningExample
ADDAdd a value.add ax, bx
SUBSubtract a value.sub ax, 1
INCAdd 1.inc cx
DECSubtract 1.dec cx
MULMultiply numbers that have no sign. The result goes in DX and AX.mul bx
IMULMultiply numbers that have a sign.imul bx
DIVDivide numbers that have no sign. AX gets the result, DX gets the remainder.div bx
IDIVDivide numbers that have a sign.idiv bx
NEGChange the sign. 5 becomes -5.neg ax
SHLMove the bits left. Each step multiplies by 2.shl ax, 1
SHRMove the bits right. Each step divides by 2 (numbers with no sign).shr ax, 1
SARMove the bits right and keep the sign. Each step divides a signed number by 2.sar ax, 1
ANDKeep only the bits that are 1 in the two values.and al, 0Fh
ORSet each bit that is 1 in one value or the other.or al, 80h
XORFlip the bits where the two values differ. xor ax, ax sets AX to 0.xor ax, ax
NOTFlip every bit.not al
ADCAdd, plus the carry flag. It joins the high bytes of a number that is longer than one register.adc al, 0
SBBSubtract, minus the carry flag (the borrow). The partner of ADC.sbb al, 0
DAADecimal adjust after an ADD or ADC of two packed decimal bytes in AL. It makes 09h + 1 into 10h and sets CF after 99.add al, 1 daa
DASDecimal adjust after a SUB or SBB of two packed decimal bytes in AL. The partner of DAA.sub al, 1 das
AAMDivide AL by 10. The tens go to AH, the units stay in AL: a ready-made step to show a number under 100.aam
CBW / CWDMake a signed number longer: CBW copies the sign of AL into AH. CWD copies the sign of AX into DX, before IDIV.cwd idiv cx

Nouns (1) · A register, a flag, a port or a place in memory, for example AX.

WordMeaningExample
CFCarry flag. It is 1 when a result is too large for its size.

Watch out: what the review found

These notes come from the review of the AI-written guides. They show traps that are easy to miss.

  • D02-C2 critical The document contradicts itself. Without an FPU, Fortran REAL arithmetic runs on software emulation. The document praises Assembly because it prevents this latency (L41). A Fortran simulation with much float math on a 1980s computer is slow.
  • D01-M2 major This names the wrong layer. The CPU hardware does out-of-order execution, and the hardware disambiguates memory at runtime. Aliasing (two names for the same memory) limits compiler reordering and vectorization.
  • D01-m1 minor "replacement of integer division with modular multiplication invariants". The usual term is multiplication by a fixed-point reciprocal (the "magic number").
  • D14-C3 critical The video gives the idea only: from the X and Y of the player, with the scroll, find the tile under the player (05:50). Inkbox says this is "faster" than a loop over a wall list (06:11). He gives no formula, no complexity class and no cycle counts. The formula in image 9 is also wrong. Shift results must be added, not combined with OR: for Y = 3, (3<<7) OR (3<<6) = 448, but 3*192 = 576. The OR between Y*192 and X also fails, for example Y = 1, X = 65 gives 193, not 257. The formula also assumes one byte per tile. The video says that 192 x 168 tiles fill 63 K (06:53), so each tile takes two bytes. The video does not describe timer routines for off-screen enemies. Object collision uses generic hitbox functions against the player (38:55) and against on-screen chickens (42:19).
  • D14-M3 major The 5A22 has a hardware unit: $4202 and $4203 start an 8 x 8 unsigned multiply, $4204 to $4206 start a 16 / 8 unsigned divide, and $4214 to $4217 give the quotient, product and remainder (snes.nesdev.org MMIO registers, checked by WebFetch). The video does not give division cost as the reason. Inkbox uses BCD because "it makes the math so much easier" (32:05). The document also omits the trap of the video: INC and DEC ignore the decimal flag, so he must use ADC (32:05 to 32:26). The "LSR and AND" nibble split at L106 is not in the video.