Seyed Masoud Hosseini · Overview · Study log · Ideas · Transcript · RSS feed
Embedded Systems, 6502 breadboard computer · Lecture 10 of 29 · 42:26
Binary to Decimal: Why It's Not That Simple
Study guide
What this lecture covers
You already know how to read a binary number by adding up place values, but that trick relies on knowing decimal, which a CPU does not "know" in any meaningful sense. This lecture asks a more practical question: given a 16-bit number sitting in memory, how does a computer that can only add and subtract produce the separate decimal digits needed to display it on a screen? It is part of Ben Eater's breadboard 6502 computer series, building directly on the earlier videos where the LCD display and printing routines were set up.
By the end, you can explain why repeated division by 10 extracts decimal digits, why that division can be done using only rotate, subtract-with-carry and branch instructions, and you will have watched a full assembly-language implementation that converts a 16-bit binary value into a printed decimal string on real hardware.
Key ideas
- Digit extraction by repeated division: dividing a number by 10 repeatedly and keeping the remainders produces its decimal digits, one at a time, starting with the least significant digit.
- Long division in binary: dividing by
1010(decimal 10) in binary works the same way as long division in decimal, just with binary subtraction and place values. - CPUs subtract, not divide: the 6502 only has add and subtract (with increment/decrement), so any division has to be built out of those operations.
- Rotate-and-subtract algorithm: shifting a 32-bit workspace left one bit at a time and attempting a subtract-with-carry at each step reproduces long division without ever "dividing" directly.
- Carry flag as a yes/no test: after a subtract-with-carry, a cleared carry means the divisor didn't fit (borrow occurred) and the result is discarded; a set carry means it fit and the result is kept.
- Two 16-bit registers in RAM: the algorithm needs a
value(the number being divided) and amod10(the running remainder/quotient workspace), stored in RAM since there aren't enough CPU registers for four bytes of state. - Detecting completion: the division loop repeats, feeding each quotient back in as the next dividend, until the quotient is entirely zero, which signals that the last digit has been produced.
- Reversing digit order: because the algorithm naturally produces digits from least to most significant, the lecture builds a null-terminated string in RAM and pushes each new digit onto the front of it, rather than printing digits as they're computed.
Walkthrough
Why decimal-to-computer conversion isn't trivial (0:00)
The lecture opens by contrasting how a human reads binary place values with what a computer actually has to do: come up with individual decimal digit characters from a raw binary value, with no built-in notion of decimal.
Separating digits by dividing by 10 (2:09)
Dividing a decimal number by 10 repeatedly and collecting the remainders is shown as a way to peel off digits one at a time, using the example 1729.
Dividing numbers in binary by hand (3:24)
The lecture works a full binary long-division example, dividing a 16-bit binary number by 1010 using the same left-to-right, subtract-and-borrow process taught for decimal long division, to get a quotient and a first remainder digit.
An algorithm for binary division (9:26)
Using a step-through simulation, the video reframes long division as: rotate a 32-bit workspace left one bit, attempt subtract with carry by 10, and use the resulting carry flag to decide whether to keep or discard the subtraction result. Repeating this 16 times processes an entire 16-bit number and produces both a quotient and a remainder digit, with the quotient feeding directly into the next division pass.
Implementing the algorithm in 6502 assembly (19:06)
This is the longest section. It allocates RAM addresses for value and mod10, copies the starting number from ROM into RAM, and builds the rotate/subtract/branch loop using ROL, SBC, BCC and a countdown in the X register. A BNE loop repeats the whole division 16 times per digit, and an outer check (ORing the two bytes of value) detects when the result is zero, which means division is complete.
Running the program and reversing the digits (34:14 and 34:45)
The first run prints the digits in the wrong order (9271 instead of 1729) because the algorithm produces least-significant digits first. The fix builds a push_character subroutine that shifts a null-terminated string in RAM one byte at a time and inserts each new digit at the front, reusing the string-printing code from the earlier "Hello, world" video.
It works (41:38)
After reprogramming the EEPROM, the circuit correctly displays 1729, confirming the algorithm and the digit-reversal logic both work.
Before you watch
- Be comfortable with the 6502's addressing modes, the accumulator/X/Y registers, and the carry flag, as covered in earlier videos in this series.
- Review the LCD initialization and character-printing subroutines from the earlier breadboard computer videos, since this lecture reuses them without re-explaining them.
- Know the difference between
ROL(rotate left through carry) and a plain shift, since the algorithm depends on it.
Check your understanding
- Why can't a CPU that only adds and subtracts perform division directly, and what operation stands in for division in this algorithm?
- What does it mean when the carry flag is cleared after a
subtract with carryin this algorithm, and what does the code do in that case? - Why does the digit-extraction algorithm produce the least significant decimal digit first, and how does the lecture correct for that when printing?
- What two pieces of RAM state does the algorithm need, and why can't they simply live in CPU registers?
- How does the program know it has extracted the last digit and should stop looping?
Chapters
- 0:00 Introduction
- 2:09 Separating digits by dividing by 10
- 3:24 Dividing numbers in binary by hand
- 9:26 An algorithm for binary division
- 19:06 Implementing the algorithm in 6502 assembly
- 34:14 Running the program
- 34:45 Reversing the digits
- 41:38 It works!
From the YouTube description
More 6502: https://eater.net/6502
Support these videos on Patreon: https://www.patreon.com/beneater or https://eater.net/support for other ways to support.
0:00 Introduction
2:09 Separating digits by dividing by 10
3:24 Dividing numbers in binary by hand
9:26 An algorithm for binary division
19:06 Implementing the algorithm in 6502 assembly
34:14 Running the program
34:45 Reversing the digits
41:38 It works!
------------------
Social media:
Website: https://www.eater.net
Twitter: https://x.com/beneater
Patreon: https://patreon.com/beneater
Reddit: https://www.reddit.com/r/beneater
Special thanks to these supporters for making this video possible:
Adrien Friggeri, Alexander Wendland, Andrew Vauter, Anson VanDoren, Armin Brauns, Ben Dyson, Ben Kamens, Ben Williams, Bill Cooksey, Binh Tran, Bouke Groenescheij, Bradley Pirtle, Bryan Brickman, Carlos Ambrozak, Christopher Blackmon, Cole Johnson, Daniel Jeppsson, Daniel Sackett, Daniel Tang, Dave Burley, Dave Walter, David Brown, David Clark, David House, David Sastre Medina, David Turnbull, David Turner, Dean Winger, Dmitry Guyvoronsky, Dušan Dželebdžić, Dzevad Trumic, Emilio Mendoza, Eric Brummer, Eric Busalacchi, Eric Dynowski, Eric Twilegar, Erik Broeders, Eugene Bulkin, fxshlein, George Miroshnykov, Harry McDow, HaykH, Hidde de Jong, Ian Tait, Ingo Eble, Ivan Sorokin, Jason DeStefano, Jason Specland, JavaXP, Jay Binks, Jayne Gabriele, Jeremy A., Jeremy Wise, Joe OConnor, Joe Pregracke, Joel Jakobsson, Joel Messerli, Joel Miller, Johannes Lundberg, John Fenwick, John Meade, Jon Dugan, Joshua King, Kefen, Kenneth Christensen, Kent Collins, Koreo, Lambda GPU Workstations, Larry, London Dobbs, Lucas Nestor, Lukasz Pacholik, Maksym Zavershynskyi, Marcus Classon, Martin Roth, Mats Fredriksson, Matt Alexander, Matthäus Pawelczyk, melvin2001, Michael Burke, Michael Garland, Michael Tedder, Michael Timbrook, Miguel Ríos, Mikel Lindsaar, Nicholas Moresco, Örn Arnarson, Örper Forilan, Paul Pluzhnikov, Paul Randal, Pete Dietl, Philip Hofstetter, Randy True, Ric King, Richard Wells, Rob Bruno, Robert Diaz, Ron Maxwell, sam raza, Sam Rose, Sergey Ten, SonOfSofaman, Stefan Nesinger, Stefanus Du Toit, Stephen Kelley, Stephen Riley, Stephen Smithstone, Steve Jones, Steve Gorman, Steven Pequeno, TheWebMachine, Tom Burns, Vlad Goran, Vladimir Kanazir, Warren Miller, xisente, Yusuke Saito
← How assembly language loops work · Hardware Interrupts on the 6502 →
