Seyed Masoud Hosseini · Overview · Study log · Ideas · Transcript · RSS feed
Embedded Systems, 6502 breadboard computer · Lecture 22 of 29 · 24:49
Lecture 22: Fixing a Hardware Bug in Software (65C51 UART)
Study guide
What this lecture covers
The lecture finishes wiring the 6551 UART into working software, showing how to initialize its control and command registers and use its status register to send and receive bytes. It follows directly from the previous video's hardware wiring of the UART and address decoding.
Partway through, the lecture hits a genuine hardware bug in the modern-production 65C51 chip and shows the process of diagnosing it against the datasheet, comparing behavior against an older original chip, and writing a software workaround. You come away understanding not just UART register programming but also how to debug when the hardware itself is wrong.
Key ideas
- Status register flags: the transmit-data-register-empty and receive-data-register-full bits tell software when it is safe to write the next byte to send or when a received byte is ready to read.
- Overrun and framing errors: the status register also reports if a received byte was overwritten before being read, or if a framing or parity error occurred, so errors can at least be detected.
- Control register: sets stop bits, word length, and baud rate in one byte; the lecture configures 8 data bits, no parity, one stop bit, and 19,200 baud.
- Command register: configures parity mode, echo mode, and interrupt behavior; the lecture disables parity, echo, and interrupts for the simplest working configuration.
- Polling loop pattern: both sending and receiving use a loop that checks a status bit (
ANDwith a mask, then branch) before proceeding, mirroring the pattern used for other status-flag checks in 6502 code. - Real hardware bug: the Western Design Center-manufactured 65C51 always reports the transmit-data-register-empty bit as set, even mid-transmission, so code that waits on that flag proceeds too early and corrupts back-to-back sends.
- Datasheet versions as evidence: comparing an older (2007) and newer (2021) datasheet revision shows the newer one documents the "bug" as expected behavior and recommends a fixed delay instead of polling that bit.
- Cycle-counted delay workaround: a delay loop sized from the baud rate (accounting for start, data, and stop bits) reliably waits long enough for a byte to finish transmitting before the next one is sent.
Walkthrough
Recapping the wiring and removing the old bit-banged code (0:00)
The lecture reviews how the 6551's four registers are mapped to addresses $5000-$5003 and deletes the previous software-timed serial code, keeping only the LCD routines.
Understanding the status register (1:00)
The lecture walks through each status register bit, focusing on the transmit-data-register-empty and receive-data-register-full flags as the two needed for basic communication, and explains overrun, framing, and parity error bits as detectable failure signals. Writing any value to the status register is shown to reset the chip.
Configuring the control and command registers (6:01)
The control register is set to $1F for 19,200 baud, 8 data bits, one stop bit. The command register is set to $0B to disable parity, echo, and interrupts. This is the minimal configuration needed to get the UART running.
Receiving and echoing data (8:02)
A polling loop checks the receive-data-register-full bit, reads a received byte once available, and prints it to the LCD. Adding a send-character subroutine lets received characters be echoed back to the terminal, making typed input visible.
A message-sending bug traced to real hardware (13:05)
Sending a null-terminated greeting message fails silently. The lecture traces the failure to the transmit-data-register-empty bit always reading as set on the Western Design Center 65C51, even while a byte is still transmitting, causing the send loop to overwrite data before it finishes going out. Swapping in an original 1981-dated AMI 6551 chip confirms the same code works correctly, isolating the problem to the chip itself.
Confirming the bug against the datasheet and writing a workaround (19:09)
A newer datasheet revision documents that the flag is effectively unusable and recommends a fixed delay instead. The lecture computes a delay loop length from the 19,200 baud rate and 10 bit-times per byte (520 clock cycles at 1 MHz), adds it after each character send, and confirms the message now transmits correctly on the buggy chip.
Before you watch
- The previous video in this series, which wires the 6551 UART's data bus and address decoding.
- Familiarity with 6502 status-flag polling patterns (
AND,BEQ/BNE) from earlier videos. - Basic understanding of clock-cycle counting for timing, covered in the hardware-timer video.
Check your understanding
- Why does the send-character subroutine need to wait for the transmit-data-register-empty flag before returning, in principle?
- What evidence pointed to a hardware bug rather than a software bug in the message-sending code?
- Why does the delay-based workaround need roughly 520 clock cycles rather than the 52 cycles of one bit time?
- How did comparing an original 1981 chip with the modern reproduction help confirm the root cause?
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.
------------------
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, Aleksey Smolenchuk, Alex, Amit Bueno, An Dương, Anthony Weems, anula, Ben, Ben Cochran, Ben Williams, Bill Cooksey, Bill Watkins, Binh Tran, Богдан Федоров, Bradley Stach, Brian Haug, Burt Humburg, Carl Fooks, Carsten Schwender, Chai, Chris Anders, Chris Lajoie, Chris Sachs, criis, Cristi Cobzarenco, Daniel Jeppsson, Daniel Pink, Daniel Tang, Daniel Zimmer, Dave Walter, David Clark, David Cox, David Dawkins, David House, David Klassen, David Sastre Medina, David Turner, Dean Bevan, Dean Winger, Deep Kalra, Dennis Henderson, Dennis Schubert, Dilip Gowda, Dirk Sperling, Dmitry Guyvoronsky, Dušan Dželebdžić, Dustin Campbell, Dylan Speiser, Dzevad Trumic, Emilio Mendoza, Eric Dynowski, Erik Broeders, Erik Granlund, Ethan Sifferman, Eugene Bulkin, Evan Serrano, Evan Thayer, Eveli László, EvinSaysMarxWasRight!, Florian Bürgi, fxshlein, George Miroshnykov, ghostdunk, GusGold, Hailey, Hovis Biddle, Ingo Eble, Ivan Esparza, Jacob Ford, James Beldock, James Capuder, Jared Dziedzic, Jason Bowen, Jason DeStefano, Jason Grim, Jason Thorpe, JavaXP, Jaxon Ketterman, jemmons, Jeremy Cole, Jesse Miller, Jim Kelly, Jim Knowler, Joe Beda, Joe Pregracke, Joe Rork, Joel, Joey Murphy, John Hamberger jn., John Henning, John Meade, Jon Dugan, Jonn Miller, Joseph Portaro, Jurģis Brigmanis, Justin Graziani, Kai Wells, Kefen, Ken Paul, Kennard Smith, Kenneth Christensen, Kyle Kellogg, Lambda GPU Workstations, László Bácsi, Lithou, Lord Dorogoth, Lukasz Pacholik, Marcos Fujisawa, Marcus Classon, Mariano Uvalle, Mark Day, Martin Noble, Mats Fredriksson, Matthew Clifford, melvin2001, Michael Koreshkov, MICHAEL SLASS, Michael Tedder, Michael Timbrook, Michael Weitman, Miguel Ríos, mikebad, Mikel Lindsaar, Miles Macchiaroli, Muqeet Mujahid, NacOJerk, Nate Welch, Nicholas Counts, Nicholas Moresco, Nick Chapman, Oli Homer, Olivier HUBER, Ori Shamir, Örn Arnarson, Paul Heller, Paul Pluzhnikov, Pete Dietl, Phil Dennis, Philip Hofstetter, ProgrammerDor, Ralph Irons, Randal Masutani, Randy True, raoulvp, real_huitz, ReJ aka Renaldas Zioma, Ric King, Rick Hennigan, Rob Bruno, Robert Diaz, Robert Keown, Robey Pointer, Roland Munsil, Sagnik Bhattacharya, Sam Sturgis, Scott Gorlick, Scott Holmes, Sean Bright, Sean Patrick O’Brien, Sergey Kruk, Shane Mulcahy, SonOfSofaman, Spencer Ruport, Stefan Nesinger, Stephen Kovalcik, Stephen Riley, Steve Jones, TheWebMachine, Thomas Eriksen, Tim Oriol, Tim Walkowski, Tim Wheeler, Tom, Tom Smith, Tyler Latham, Usseod, Vincent Bernat, Warren Miller, Wim Coekaerts, Yee Lam Wan
← Lecture 21: RS232 Interface With the 6551 UART · Lecture 23: Running Apple 1 Software (Wozmon) →
