ASCII, BCD, Signed, and Unsigned Data
Same bits, different meanings — how the 8086 interprets binary patterns as text, decimal, or signed numbers
Open interactive version (quiz + challenge)Real-world analogy
What is it?
The 8086 stores all data as binary patterns; the interpretation depends on the context. ASCII encodes characters (A=41h). BCD represents decimal digits in binary — unpacked (one digit per byte) or packed (two digits per byte) with DAA/DAS/AAA/AAS for correction. Unsigned integers use all bits for magnitude (0-255 for bytes). Signed integers use 2's complement (MSB = sign bit, -128 to +127 for bytes). CBW/CWD sign-extend for division.
Real-world relevance
BCD was essential in early computing for financial applications where decimal precision mattered — bank balances, tax calculations, and point-of-sale systems used BCD to avoid floating-point rounding errors. Modern SQL DECIMAL types and Java BigDecimal serve the same purpose. ASCII remains the foundation of all text processing, and 2's complement signed arithmetic is universal in every processor made today.
Key points
- ASCII Encoding — ASCII uses 7 bits (values 0-127) to represent characters. 'A'=41h, 'Z'=5Ah, 'a'=61h, '0'=30h, '9'=39h. The 8086 stores ASCII in bytes. Strings are sequences of ASCII bytes, typically null-terminated (ending with 00h).
- Unpacked BCD — Unpacked BCD stores one decimal digit per byte, in the lower nibble (0-9), with the upper nibble zero. So decimal 59 is stored as two bytes: 05h and 09h. The AAA and AAS instructions adjust results after arithmetic on unpacked BCD.
- Packed BCD — Packed BCD stores two decimal digits per byte — one in the upper nibble and one in the lower. Decimal 59 is stored as 59h (one byte). DAA and DAS adjust addition and subtraction results for packed BCD.
- DAA and DAS Instructions — DAA (Decimal Adjust for Addition) corrects AL after ADD/ADC of packed BCD values. DAS (Decimal Adjust for Subtraction) corrects AL after SUB/SBB. Both check the AF and CF flags and add/subtract 6 to adjust nibbles that exceed 9.
- AAA and AAS Instructions — AAA (ASCII Adjust for Addition) corrects AL after adding unpacked BCD or ASCII digits. AAS (ASCII Adjust for Subtraction) corrects after subtraction. These adjust the result in AL and increment/decrement AH as needed.
- Unsigned Integers — Unsigned interpretation treats all bits as magnitude. An 8-bit unsigned byte ranges 0 to 255. A 16-bit unsigned word ranges 0 to 65535. The CPU uses CF (Carry Flag) to detect unsigned overflow. Conditional jumps JA/JB test unsigned comparisons.
- Signed Integers (2's Complement) — Signed interpretation uses 2's complement: the MSB is the sign bit (0=positive, 1=negative). An 8-bit signed byte ranges -128 to +127. A 16-bit signed word ranges -32768 to +32767. OF (Overflow Flag) detects signed overflow. JG/JL test signed comparisons.
- Sign Extension: CBW and CWD — CBW (Convert Byte to Word) sign-extends AL into AX: if AL's MSB is 0, AH=00h; if 1, AH=FFh. CWD (Convert Word to Doubleword) sign-extends AX into DX:AX. Essential before signed division (IDIV) which requires a double-width dividend.
- Overflow vs Carry — CF (Carry Flag) indicates unsigned overflow — a carry or borrow beyond the bit width. OF (Overflow Flag) indicates signed overflow — the result is too large or too small for the signed range. The same ADD sets both flags; which you check depends on your interpretation.
Code example
; Complete data representation examples
; === ASCII ===
msg DB 'Score: ', 0 ; String with null terminator
digit DB '7' ; Single ASCII digit
; Convert ASCII digit to number
MOV AL, [digit] ; AL = 37h ('7')
SUB AL, '0' ; AL = 07h (numeric 7)
; === PACKED BCD ADDITION ===
; Add decimal 49 + 38 = 87
MOV AL, 49h ; Packed BCD 49
ADD AL, 38h ; AL = 81h (49h + 38h)
DAA ; AL = 87h (valid packed BCD)
; === UNPACKED BCD with AAM ===
; Multiply BCD digits 7 * 8 = 56
MOV AL, 07h ; Unpacked BCD 7
MOV BL, 08h ; Unpacked BCD 8
MUL BL ; AX = 0038h (7*8=56 in hex)
AAM ; AH = 05h, AL = 06h
; Unpacked BCD result: 56
; === UNSIGNED vs SIGNED ===
MOV AL, 0C0h ; Unsigned: 192, Signed: -64
MOV BL, 40h ; Unsigned: 64, Signed: +64
; Unsigned comparison
CMP AL, BL
JA al_above ; True! 192 > 64 unsigned
; Signed comparison
CMP AL, BL
JG al_greater ; False! -64 < 64 signed
JL al_lesser ; True! -64 < 64 signed
; === SIGN EXTENSION for IDIV ===
MOV AX, -100 ; AX = FF9Ch
CWD ; DX:AX = FFFFFF9Ch = -100
MOV BX, 7
IDIV BX ; AX = -14 (quotient), DX = -2 (remainder)Line-by-line walkthrough
- 1. SUB AL, '0' — converts ASCII digit '7' (37h) to numeric value 7 (07h). Works because ASCII digits 0-9 are consecutive starting at 30h.
- 2. ADD AL, 38h after MOV AL, 49h — binary addition gives 81h, but we want BCD 87 (49+38=87). The result 81h is wrong in BCD because there is no 'digit' for 8 in the ones place.
- 3. DAA checks: low nibble of 81h is 1 (ok), high nibble is 8 (ok), but AF flag from the ADD indicates a low-nibble carry occurred. DAA adds 6 to correct: 81h + 06h = 87h.
- 4. MUL BL — unsigned multiply of AL(7) * BL(8) = 56 decimal, stored as 0038h in AX (binary, not BCD).
- 5. AAM — ASCII Adjust for Multiplication divides AL by 10: AH=quotient=5, AL=remainder=6. This converts binary 38h (56 decimal) to unpacked BCD 05:06.
- 6. CMP AL, BL with AL=C0h and BL=40h — the comparison sets flags based on C0h-40h=80h. CF=0 (no unsigned borrow) so JA is true. But SF=1 and OF=0 so the signed result is negative, making JL true.
- 7. CWD sign-extends AX=FF9Ch (which is -100) into DX:AX. Since bit 15 of AX is 1, DX becomes FFFFh.
- 8. IDIV BX — signed division of DX:AX (-100) by BX (7). Quotient in AX = -14 (FFF2h), remainder in DX = -2 (FFFEh).
Spot the bug
; Goal: Add packed BCD 85 + 29 = 114
MOV AL, 85h ; Packed BCD 85
ADD AL, 29h ; Binary: 85h + 29h = AEh
DAA ; Should give 14h with CF=1
; Programmer stores result:
MOV [result], AL ; Stores 14h
; But forgets about the carry!
; How does the programmer recover the '1' in 114?Need a hint?
Show answer
Explain like I'm 5
Fun fact
Hands-on challenge
More resources
- BCD Arithmetic in 8086 (GeeksforGeeks)
- ASCII and BCD in Assembly (YouTube)
- Signed vs Unsigned Explained (TutorialsPoint)
- Two's Complement (Wikipedia)