<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>TinyComputers.io (Posts about zilog)</title><link>https://tinycomputers.io/</link><description></description><atom:link href="https://tinycomputers.io/categories/zilog.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><copyright>Contents © 2026 A.C. Jokela 
&lt;!-- div style="width: 100%" --&gt;
&lt;a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/"&gt;&lt;img alt="" style="border-width:0" src="https://i.creativecommons.org/l/by-sa/4.0/80x15.png" /&gt; Creative Commons Attribution-ShareAlike&lt;/a&gt;&amp;nbsp;|&amp;nbsp;
&lt;!-- /div --&gt;
</copyright><lastBuildDate>Mon, 06 Apr 2026 22:12:57 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Why Some Chips Last 40+ Years: Z80, 68k, 6502, and the Secret to Processor Longevity</title><link>https://tinycomputers.io/posts/why-some-chips-last-40-years.html?utm_source=feed&amp;utm_medium=rss&amp;utm_campaign=rss</link><dc:creator>A.C. Jokela</dc:creator><description>&lt;figure&gt;&lt;img src="https://tinycomputers.io/images/zilog-z80.jpg"&gt;&lt;/figure&gt; &lt;div class="audio-widget"&gt;
&lt;div class="audio-widget-header"&gt;
&lt;span class="audio-widget-icon"&gt;🎧&lt;/span&gt;
&lt;span class="audio-widget-label"&gt;Listen to this article&lt;/span&gt;
&lt;/div&gt;
&lt;audio controls preload="metadata"&gt;
&lt;source src="https://tinycomputers.io/why-some-chips-last-40-years_tts.mp3" type="audio/mpeg"&gt;
&lt;/source&gt;&lt;/audio&gt;
&lt;div class="audio-widget-footer"&gt;22 min · AI-generated narration&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;There's a Zilog Z80 in a graphing calculator sitting in a high school classroom right now. The student using it was born around 2008. The Z80 was designed in 1976. That processor is older than the student's parents.&lt;/p&gt;
&lt;p&gt;This isn't a quirky footnote. It's a pattern. The Z80, the Motorola 68000, the MOS Technology 6502, the Intel 8051: these processors have been in continuous production and active deployment for forty years or more. The Z80 is closing in on fifty. Meanwhile, processors that were objectively superior by nearly every technical measure (the Zilog Z8000, the National Semiconductor 32016, the Motorola 88000, the Intel i960) are footnotes in Wikipedia articles that nobody reads.&lt;/p&gt;
&lt;p&gt;What determines whether a processor lives for decades or dies in five years? I've spent the last two years building &lt;a href="https://tinycomputers.io/posts/clean-room-z80-emulator.html"&gt;Z80 emulators&lt;/a&gt;, writing &lt;a href="https://tinycomputers.io/posts/building-language-compilers-for-the-z80.html"&gt;compilers for the Z80&lt;/a&gt;, running &lt;a href="https://tinycomputers.io/posts/cpm-on-physical-retroshield-z80.html"&gt;CP/M on physical RetroShield hardware&lt;/a&gt;, and exploring the &lt;a href="https://tinycomputers.io/posts/motorola-68000-processor-and-the-ti-89-graphing-calculator.html"&gt;Motorola 68000 through TI calculators&lt;/a&gt;. I've read William Barden's &lt;a href="https://tinycomputers.io/posts/the-z80-microcomputer-handbook-william-barden.html"&gt;1978 handbook&lt;/a&gt; that was still being reprinted in 1985, and Steve Ciarcia's &lt;a href="https://tinycomputers.io/posts/build-your-own-z80-computer-steve-ciarcia.html"&gt;build-your-own guide&lt;/a&gt; that assumed you'd wire up a computer from discrete chips. The deeper I've gone into this world, the more convinced I've become that processor longevity isn't really about the processor. It's about everything around it.&lt;/p&gt;
&lt;h3&gt;The Survivors&lt;/h3&gt;
&lt;p&gt;Four processors stand out for their extraordinary longevity. Each was introduced in the mid-to-late 1970s. Each is still manufactured or cloned today.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Zilog Z80&lt;/strong&gt; (1976) was designed by Federico Faggin and Masatoshi Shima, both of whom had worked on the Intel 4004 and 8080. The Z80 was explicitly designed as a better 8080, backward-compatible with the 8080's instruction set but adding indexed addressing, a second register bank, a built-in DRAM refresh counter, and a single 5V power supply (the 8080 needed three voltage rails). It became the heart of CP/M machines, arcade cabinets, and eventually TI graphing calculators. Zilog's CMOS variant, the Z84C00, was manufactured continuously until &lt;a href="https://baud.rs/IboIHD"&gt;April 2024&lt;/a&gt;, when Littelfuse (Zilog's current owner) finally announced end-of-life after 48 years. The eZ80, a backward-compatible enhanced variant, continues in production, and third-party clones remain available. The Z80 instruction set isn't going anywhere even if the original silicon is.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The MOS Technology 6502&lt;/strong&gt; (1975) was designed by Chuck Peddle and Bill Mensch after they left Motorola. At \$25 when competing processors cost \$150-\$300, the 6502 was a revolution in affordability. It powered the Apple II, the Commodore 64, the Atari 2600, and the NES. Bill Mensch's Western Design Center still manufactures the W65C02S and W65C816S today, fifty years after the original design.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://tinycomputers.io/images/chip-longevity/hitachi-hd68000.jpg" alt="Hitachi HD68000, a second-sourced clone of the Motorola MC68000" style="width: 340px; box-shadow: 0 30px 40px rgba(0,0,0,.1); float: right; margin: 0 0 20px 20px;"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Motorola 68000&lt;/strong&gt; (1979) was the 32-bit processor that arrived a generation early. With a linear 24-bit address space and an orthogonal instruction set that programmers genuinely enjoyed using, it became the foundation for the original Macintosh, the Amiga, the Atari ST, the Sega Genesis, and Sun's first workstations. Its descendants (the 68020, 68030, 68040, ColdFire, and now NXP's modern variants) kept the architecture alive in embedded systems, automotive controllers, and &lt;a href="https://tinycomputers.io/posts/motorola-68000-processor-and-the-ti-89-graphing-calculator.html"&gt;Texas Instruments calculators&lt;/a&gt; well into the 2020s.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://tinycomputers.io/images/chip-longevity/intel-p8051.jpg" alt="Intel P8051 microcontroller in DIP-40 package" style="width: 340px; box-shadow: 0 30px 40px rgba(0,0,0,.1); float: left; margin: 0 20px 20px 0;"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Intel 8051&lt;/strong&gt; (1980) is perhaps the most quietly ubiquitous processor ever made. Designed as a microcontroller (a processor with RAM, ROM, timers, and I/O ports integrated on a single chip), the 8051 found its way into everything from washing machines to automotive engine controllers to industrial PLCs. Over two dozen companies have manufactured 8051 variants. If you've used an appliance, driven a car, or walked through a building with an elevator in the last forty years, you've interacted with an 8051 derivative.&lt;/p&gt;
&lt;p&gt;The 8051 is also a case study in &lt;a href="https://tinycomputers.io/posts/jevons-paradox.html"&gt;Jevons Paradox&lt;/a&gt; applied to silicon. As more manufacturers licensed and produced the 8051, unit costs fell. As unit costs fell, engineers designed it into applications that would never have justified a microcontroller at the original price: a toaster, a thermostat, a toy. Each new application expanded the market, which attracted more manufacturers, which drove costs lower still. The cycle fed itself for decades. Technically superior alternatives existed at every point along this curve, but they couldn't compete with an architecture whose ecosystem was compounding while their price-per-unit was still on the wrong side of the volume curve.&lt;/p&gt;
&lt;h3&gt;The Fallen&lt;/h3&gt;
&lt;p&gt;For every processor that lasted decades, dozens vanished. Some of these were technically impressive, arguably more capable than the survivors.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Zilog Z8000&lt;/strong&gt; (1979), designed as the Z80's successor, offered a 16-bit architecture with segmented memory addressing. It was more powerful than the Z80 in every measurable way. It lasted roughly five years in the market before fading into obscurity. The segmented memory model (the same curse that plagued Intel's 8086/286) made programming painful. And critically, it wasn't backward-compatible with the Z80. Every Z80 program, every CP/M application, every line of existing code was useless on the Z8000. Zilog was asking customers to abandon their entire software investment.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Motorola 88000&lt;/strong&gt; (1988) was Motorola's clean-sheet RISC design, intended to eventually replace the 68k family. It was technically excellent: pipelined, superscalar-capable, and well-designed. Motorola couldn't sell it. Customers had millions of lines of 68k code, working products, trained engineers, and proven toolchains. The 88000 offered better performance but required abandoning everything. Motorola eventually surrendered and joined IBM and Apple to create the PowerPC, which at least had the marketing muscle of three companies behind it.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;National Semiconductor 32016&lt;/strong&gt; (1982) was a full 32-bit processor at a time when the PC world was still on 16-bit. It was used in the Acorn Cambridge Workstation and a few other systems. It had bugs. The early silicon had errata that made reliable system design difficult. By the time National got the bugs out, the market had moved on.&lt;/p&gt;
&lt;p&gt;The pattern is consistent: technical superiority alone doesn't determine survival.&lt;/p&gt;
&lt;h3&gt;Five Factors That Determine Processor Longevity&lt;/h3&gt;
&lt;p&gt;After spending years in this world, I've identified five factors that separate the survivors from the fallen. They're listed roughly in order of importance, which is not the order most engineers would expect.&lt;/p&gt;
&lt;h4&gt;1. Second-Sourcing and Licensing&lt;/h4&gt;
&lt;p&gt;This is the single most important factor, and it's the one that engineers consistently underrate because it's a business decision, not a technical one.&lt;/p&gt;
&lt;p&gt;The Z80 was second-sourced by Mostek, SGS-Thomson, Sharp, NEC, Toshiba, Samsung, and others. When &lt;a href="https://www.littelfuse.com/"&gt;Littelfuse&lt;/a&gt;, the current owner of Zilog, finally discontinued the standalone Z84C00 in 2024, the instruction set didn't die, because it was never dependent on a single manufacturer. This is exactly what second-sourcing was designed to protect against. It mattered enormously to design engineers in the 1980s and 1990s, because committing a product design to a single-source processor was career-threatening. If your sole supplier had a fab fire, or went out of business, or simply decided to discontinue the chip, your product was dead.&lt;/p&gt;
&lt;p&gt;The 6502 was licensed to multiple manufacturers: Rockwell, Synertek, GTE, and later CMD and the Western Design Center. The 8051 took this to its logical extreme: Intel actively encouraged licensing, and the architecture was eventually manufactured by Atmel, Philips/NXP, Silicon Labs, Dallas/Maxim, Infineon, and dozens more. The 8051 became less a product and more a standard, an instruction set architecture that any competent semiconductor company could implement. It was, in hindsight, a preview of the model that ARM and RISC-V would later formalize: sell the design, not the chip, and let the ecosystem do the rest.&lt;/p&gt;
&lt;p&gt;The 68000 family was produced by Motorola, Hitachi, Signetics, Mostek, and Toshiba. Later, the ColdFire and subsequent architectures maintained enough compatibility to keep the ecosystem alive under Freescale and then NXP.&lt;/p&gt;
&lt;p&gt;The x86 architecture tells the same story at a larger scale. IBM refused to use Intel's 8088 in the original PC without a second source. That requirement forced Intel to license the design to AMD, a decision Intel spent the next four decades regretting and litigating. But the resulting duopoly is a major reason x86 survived the RISC revolution of the 1990s. When Sun, SGI, and DEC were pushing SPARC, MIPS, and Alpha, customers considering a switch to RISC had to weigh superior performance against the uncomfortable fact that each RISC architecture had exactly one supplier. x86 had two. That mattered more than clock speeds.&lt;/p&gt;
&lt;p&gt;Contrast all of this with the Z8000, which was essentially Zilog-only. Or the 88000, which was Motorola-only. Single-source processors carry existential risk for every product that uses them. Purchasing managers know this even when engineers don't.&lt;/p&gt;
&lt;h4&gt;2. Ecosystem and Toolchain Maturity&lt;/h4&gt;
&lt;p&gt;A processor without a mature toolchain is a science project. A processor with assemblers, compilers, debuggers, reference designs, application notes, textbooks, and a community of experienced engineers is an ecosystem.&lt;/p&gt;
&lt;p&gt;The Z80 ecosystem by the mid-1980s was staggering. There were books (&lt;a href="https://baud.rs/EZ3Bwg"&gt;Rodnay Zaks' &lt;em&gt;Programming the Z80&lt;/em&gt;&lt;/a&gt;, Barden's &lt;a href="https://baud.rs/5brWaW"&gt;handbook&lt;/a&gt;, Ciarcia's &lt;a href="https://baud.rs/kiLcPY"&gt;build guide&lt;/a&gt;, Coffron's &lt;a href="https://baud.rs/3hw1CF"&gt;applications manual&lt;/a&gt;) available at any technical bookstore. There were assemblers, C compilers, BASIC interpreters, and Forth systems. There were thousands of CP/M applications. There were magazines publishing Z80 projects monthly. There were university courses teaching Z80 assembly. Every year, this ecosystem grew, and every year, the cost of switching to a different processor increased.&lt;/p&gt;
&lt;p&gt;The 6502 had a similar ecosystem, driven heavily by the Apple II and Commodore 64 communities. The 8051 accumulated the largest ecosystem of any microcontroller family, with Keil (now ARM), IAR, SDCC, and many other toolchains providing development environments across every host platform.&lt;/p&gt;
&lt;p&gt;When I wrote about &lt;a href="https://tinycomputers.io/posts/how-we-learned-hardware-in-1983.html"&gt;how we learned hardware in 1983&lt;/a&gt;, I was documenting a snapshot of this ecosystem at its peak. Those books, those reference designs, those shared conventions: they weren't just educational resources. They were infrastructure. And infrastructure, once built, resists replacement.&lt;/p&gt;
&lt;h4&gt;3. ISA Simplicity and Predictability&lt;/h4&gt;
&lt;p&gt;There's a counterintuitive truth about instruction set architecture: the "best" ISA often isn't the one that survives. The one that survives is the one that's simple enough to implement cheaply, predictable enough to verify thoroughly, and small enough to teach in a semester.&lt;/p&gt;
&lt;p&gt;The Z80's instruction set is large by 8-bit standards, with 158 base instructions and variants pushing toward 700 when you count all the addressing modes. But the fundamental execution model is simple: fetch an instruction, decode it, execute it. No pipeline. No branch prediction. No speculative execution. No out-of-order dispatch. The behavior is deterministic. If you clock the Z80 at 4 MHz, you can calculate exactly how many T-states each instruction takes and predict your program's execution time down to the microsecond.&lt;/p&gt;
&lt;p&gt;This determinism is extraordinarily valuable in embedded systems. When you're designing an engine controller or a medical device, you need to know (not estimate, &lt;em&gt;know&lt;/em&gt;) that your interrupt handler will complete within a specific time window. Pipelined processors with branch prediction make this analysis much harder. Simple processors make it trivial.&lt;/p&gt;
&lt;p&gt;The 6502 takes this even further. With only 56 instructions and 13 addressing modes, the entire ISA fits on a single reference card. You can hold the complete instruction set in your head. This isn't a limitation; it's a feature. Engineers who can reason about every instruction their processor executes build more reliable systems than engineers who rely on abstractions they don't fully understand.&lt;/p&gt;
&lt;p&gt;The 8051 instruction set is similarly compact: 111 instructions, most executing in one or two machine cycles. The architecture includes bit-addressable memory, a feature that seems quirky until you're writing firmware for a device with dozens of individual control signals, at which point it becomes indispensable.&lt;/p&gt;
&lt;h4&gt;4. Power, Size, and Cost&lt;/h4&gt;
&lt;p&gt;The survivors share a common economic profile: they're cheap to manufacture, cheap to buy, and cheap to power.&lt;/p&gt;
&lt;p&gt;A Z84C00 in CMOS draws microwatts in standby. A W65C02S runs on a coin cell battery for years. An 8051 derivative can be manufactured on mature process nodes that have been paid for decades ago, with die sizes so small that the packaging costs more than the silicon. When your processor costs \$0.50 in volume and runs on the leakage current of a lithium cell, the engineering case for replacing it with something faster but more expensive becomes very hard to make.&lt;/p&gt;
&lt;p&gt;This is where processor longevity intersects with the economics I've written about in the &lt;a href="https://tinycomputers.io/posts/jevons-paradox.html"&gt;Jevons Paradox series&lt;/a&gt;. The relevant cost isn't just the chip; it's the total cost of the design: the processor, the toolchain, the engineering time, the qualification testing, the regulatory certification, and the opportunity cost of a redesign. A \$0.50 Z80 clone in a proven design with ten years of field data is almost impossible to displace, even if a \$0.30 ARM Cortex-M0 is technically superior, because the redesign and requalification costs dwarf the per-unit savings.&lt;/p&gt;
&lt;h4&gt;5. Inertia and Institutional Knowledge&lt;/h4&gt;
&lt;p&gt;The final factor is the hardest to quantify and the most powerful: institutional inertia.&lt;/p&gt;
&lt;p&gt;Somewhere in Germany, there's a factory running a production line controlled by Z80-based PLCs installed in 1988. The line produces automotive components. It runs 24/7. It works. The engineer who designed the control system retired fifteen years ago. The firmware was written in Z80 assembly and documented in a binder that lives in a filing cabinet near the line.&lt;/p&gt;
&lt;p&gt;Replacing this system would require: reverse-engineering the existing firmware (the original source code may or may not still exist), designing a new control system, writing new firmware, testing it against every production scenario the old system handles, qualifying the new system for automotive safety standards, scheduling downtime for installation, and training operators on the new system. The cost runs into hundreds of thousands of dollars. The risk is non-trivial; any bug could halt production.&lt;/p&gt;
&lt;p&gt;So they order more Z80s. And the Z80 stays in production for another year.&lt;/p&gt;
&lt;p&gt;Multiply this scenario by thousands of factories, millions of installed devices, and billions of lines of proven firmware, and you begin to understand why some processors simply cannot die. The cost of replacing them exceeds the cost of maintaining them, indefinitely.&lt;/p&gt;
&lt;p&gt;This is also why the &lt;a href="https://tinycomputers.io/posts/exploring-ti-84%2B.html"&gt;TI-84+ still uses a Z80&lt;/a&gt;. Texas Instruments has decades of TI-BASIC software, decades of teacher training materials, decades of standardized test approvals, and a user base that expects backward compatibility with programs written in 2004. The Z80 isn't the best processor for a modern calculator. But replacing it would require replacing &lt;em&gt;everything else&lt;/em&gt;, and "everything else" is where the real value lives.&lt;/p&gt;
&lt;h3&gt;The Newcomen Pattern&lt;/h3&gt;
&lt;p&gt;There's a historical analogy I keep returning to. Thomas Newcomen built his atmospheric steam engine in 1712. It was inefficient, converting roughly 1% of the heat energy in coal into useful work. James Watt's improved design, introduced in the 1760s, was dramatically better: separate condenser, double-acting cylinder, and eventually five times the thermal efficiency. By any rational engineering measure, the Newcomen engine should have vanished overnight.&lt;/p&gt;
&lt;p&gt;It didn't. Newcomen engines continued to be built and operated for decades after Watt's design was available. In some mining operations, they remained in service into the 19th century. The reasons were the same ones that keep Z80s in factories today: the existing engines worked, the operators knew how to maintain them, the replacement cost was high, and the performance of the old engine was &lt;em&gt;adequate&lt;/em&gt; for the task.&lt;/p&gt;
&lt;p&gt;"Adequate for the task" is the phrase that explains processor longevity better than any technical specification. The Z80 is adequate for a graphing calculator. The 6502 is adequate for a simple embedded controller. The 8051 is adequate for a washing machine. And "adequate" plus "proven" plus "cheap" plus "available from multiple sources" is a combination that "superior but new and unfamiliar" almost never beats.&lt;/p&gt;
&lt;h3&gt;The Numbers Tell the Story&lt;/h3&gt;
&lt;p&gt;It's worth pausing to appreciate the sheer scale of the survivors' deployment.&lt;/p&gt;
&lt;p&gt;The 8051 family has been manufactured in quantities estimated at over 10 billion units. That's not a typo. Ten billion. More 8051 derivatives have been produced than any other processor architecture in history, including x86. They're in your car; a modern automobile contains dozens of microcontrollers, many of them 8051 variants, handling everything from window controls to tire pressure monitoring. They're in your thermostat, your microwave, your garage door opener.&lt;/p&gt;
&lt;p&gt;The Z80 and its clones have shipped in quantities that are harder to pin down precisely, but conservative estimates exceed a billion units across all manufacturers and derivatives. The 6502 family, counting all variants from the original through the 65C816 that powered the Apple IIGS and the Super Nintendo, is in a similar range.&lt;/p&gt;
&lt;p&gt;The 68000 family took a different path: fewer total units but higher-value applications. Where the 8051 went wide and cheap, the 68k went deep and capable. It dominated the workstation market before RISC architectures displaced it, then settled into a long career in automotive and industrial control. NXP's ColdFire and subsequent QorIQ Layerscape processors carry DNA that traces back to the original 68000. The architecture didn't die; it evolved.&lt;/p&gt;
&lt;p&gt;What's remarkable about these numbers is that they &lt;em&gt;continue to grow&lt;/em&gt;. These aren't static installed bases slowly decaying as old equipment is retired. New products are still being designed with 8051 cores. New Z80-compatible processors are still being fabricated; even after Littelfuse discontinued the original Z84C00 in 2024, third-party clones and the eZ80 keep the instruction set alive. When I built a &lt;a href="https://tinycomputers.io/posts/designing-a-dual-z80-retroshield-part-1.html"&gt;dual Z80 RetroShield&lt;/a&gt;, I ordered Z84C0020PEC chips that were still in stock from the final production runs. A 1976 design, manufactured nearly half a century later. And the fact that Zilog's discontinuation made international headlines tells you everything about how deeply embedded these chips remain. You don't mourn a processor nobody uses.&lt;/p&gt;
&lt;h3&gt;What This Means for Modern Processors&lt;/h3&gt;
&lt;p&gt;The ARM Cortex-M0, introduced in 2009, is arguably the first modern processor that has a plausible shot at matching the longevity of the 8-bit survivors. It's licensable (like the 8051), simple (like the 6502), power-efficient (like the Z84C00), and backed by an ecosystem that's growing rapidly. ARM's licensing model (selling the design, not the chip) mirrors the model that made the 8051 ubiquitous.&lt;/p&gt;
&lt;p&gt;RISC-V, as an open ISA, goes even further. No licensing fees, no single company that can discontinue the architecture, no vendor lock-in. I've &lt;a href="https://tinycomputers.io/posts/milk-v-mars-review.html"&gt;reviewed RISC-V boards&lt;/a&gt; and watched the ecosystem grow. If any modern ISA is positioned to last fifty years, it's RISC-V, not because it's the best architecture, but because it's the hardest to kill.&lt;/p&gt;
&lt;p&gt;But here's the uncomfortable truth for anyone designing a new processor architecture: the window for establishing a forty-year processor is probably closed. The Z80, 6502, 68000, and 8051 all emerged during a period when the microprocessor market was being established. There were no entrenched incumbents. Every design win was greenfield. Every new application (calculators, arcade cabinets, industrial controllers, medical devices) was being designed for the first time with microprocessors.&lt;/p&gt;
&lt;p&gt;That era is over. Every new design now competes against an installed base. Every new ISA competes against ARM's ecosystem. The switching costs that keep forty-year-old processors alive are the same switching costs that prevent new architectures from gaining traction. The moat works in both directions.&lt;/p&gt;
&lt;h3&gt;The Lesson&lt;/h3&gt;
&lt;p&gt;The processors that last aren't the ones that push the performance envelope. They're the ones that solve a problem well enough, cheaply enough, reliably enough, and from enough sources that replacing them is never worth the trouble. Technical excellence is necessary but not sufficient. What matters more is the web of dependencies (the toolchains, the trained engineers, the certified designs, the proven firmware, the institutional knowledge) that accumulates around a processor over decades.&lt;/p&gt;
&lt;p&gt;The Z80 will outlive many of the engineers reading this, not because it's a great processor, but because it's woven into the fabric of systems that nobody has a compelling reason to redesign. The 8051 will outlive the Z80, because it's woven into even more systems. And somewhere in a high school classroom, a student is pressing buttons on a &lt;a href="https://tinycomputers.io/posts/exploring-ti-84%2B.html"&gt;TI-84+&lt;/a&gt; that runs on a fifty-year-old instruction set, completely unaware that the chip executing their quadratic formula has been doing this job since before their grandparents started dating.&lt;/p&gt;
&lt;p&gt;That's longevity. Not the kind you engineer. The kind that happens when everything around the chip conspires to keep it in place.&lt;/p&gt;
&lt;div style="margin-top: 3em; padding-top: 1em; border-top: 1px solid #ccc; font-size: 0.85em; color: #666;"&gt;
&lt;strong&gt;Image credits:&lt;/strong&gt; Hitachi HD68000 and Intel P8051 photographs by Konstantin Lanzet, via &lt;a href="https://commons.wikimedia.org/wiki/File:KL_Hitachi_HD68000.jpg"&gt;Wikimedia Commons&lt;/a&gt;. Licensed under GFDL and CC BY-SA 3.0 respectively.
&lt;/div&gt;</description><category>6502</category><category>8051</category><category>68000</category><category>embedded systems</category><category>isa</category><category>microprocessors</category><category>mos technology</category><category>motorola</category><category>processor architecture</category><category>retrocomputing</category><category>second-sourcing</category><category>z80</category><category>zilog</category><guid>https://tinycomputers.io/posts/why-some-chips-last-40-years.html</guid><pubDate>Sun, 08 Mar 2026 16:00:00 GMT</pubDate></item><item><title>An LLM Clean Room Z80 Emulator: Building from Specifications, Not Source Code</title><link>https://tinycomputers.io/posts/clean-room-z80-emulator.html?utm_source=feed&amp;utm_medium=rss&amp;utm_campaign=rss</link><dc:creator>A.C. Jokela</dc:creator><description>&lt;div class="audio-widget"&gt;
&lt;div class="audio-widget-header"&gt;
&lt;span class="audio-widget-icon"&gt;🎧&lt;/span&gt;
&lt;span class="audio-widget-label"&gt;Listen to this article&lt;/span&gt;
&lt;/div&gt;
&lt;audio controls preload="metadata"&gt;
&lt;source src="https://tinycomputers.io/clean-room-z80-emulator_tts.mp3" type="audio/mpeg"&gt;
&lt;/source&gt;&lt;/audio&gt;
&lt;div class="audio-widget-footer"&gt;43 min · AI-generated narration&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;&lt;img src="https://tinycomputers.io/images/clean-room-z80-emulator/zilog-z80.jpg" alt="An original Zilog Z80 CPU in a white ceramic DIP-40 package, manufactured in Dallas, 1976" style="float: right; max-width: 300px; margin: 0 0 1em 1.5em; border-radius: 4px; box-shadow: 0 10px 20px rgba(0,0,0,.1);" loading="lazy"&gt;&lt;/p&gt;
&lt;p&gt;There's a particular kind of satisfaction in building something from specifications rather than from someone else's implementation. When you take timing diagrams and instruction tables and turn them into working code, you're not copying; you're reconstructing. Every decision about how to decode an opcode, how to handle the flag register's undocumented bits, how to sequence a block transfer instruction: these become deliberate choices, informed by the original engineering documents but filtered through genuine understanding of the problem.&lt;/p&gt;
&lt;p&gt;This is the story of writing a complete Z80 emulator under clean room constraints, with the twist that the implementer is an LLM. I used &lt;a href="https://baud.rs/claude-code"&gt;Claude Code&lt;/a&gt; to write every line of C (the CPU core, the test suite, the system emulator) with a single, non-negotiable rule: &lt;strong&gt;no reference to existing Z80 emulator source code&lt;/strong&gt;. The inputs were the &lt;a href="https://baud.rs/EESjG1"&gt;Zilog Z80 CPU User Manual&lt;/a&gt;, my architectural plan, and the test ROMs to prove it works.&lt;/p&gt;
&lt;p&gt;An important clarification on what "clean room" means here. The constraint was no existing emulator source code, not "only the official Zilog manual." The Z80's undocumented behaviors (the F3/F5 flag bits, IXH/IXL half-index registers, DDCB register copy side effects) aren't in Zilog's official documentation. They come from decades of community reverse-engineering documented in references like Sean Young's "&lt;a href="https://baud.rs/s0MAzk"&gt;The Undocumented Z80 Documented&lt;/a&gt;" and similar technical write-ups. Claude's training data includes this secondary documentation, and the clean room constraint didn't prohibit drawing on that knowledge; it prohibited referencing how &lt;em&gt;other emulators implemented&lt;/em&gt; that knowledge. The distinction matters: a specification of behavior is not the same as someone else's code that implements it.&lt;/p&gt;
&lt;h3&gt;Why an LLM Clean Room?&lt;/h3&gt;
&lt;p&gt;The term "clean room" comes from the semiconductor and software industries, where it describes a development methodology designed to produce implementations that are legally and intellectually independent of existing ones. In the chip fabrication sense, it's a literal dust-free environment. In the software sense, it means building from specifications and documentation without ever examining existing implementations.&lt;/p&gt;
&lt;p&gt;When an LLM writes code, there's always the question: is this implementation derived from the specification I gave it, or is it pattern-matching against emulator source code in its training data? This is the central tension of using AI for systems programming. An LLM has likely seen dozens of Z80 emulators during training. If you just ask it to "write a Z80 emulator," you'll get something that works, but you can't know whether it's an original implementation or a recombination of memorized code.&lt;/p&gt;
&lt;p&gt;The clean room constraint changes the experiment. By explicitly instructing Claude that this is a clean room project (that all implementation must be derived solely from specifications and documentation, not from existing emulator source code), you're testing whether the model can work from first principles rather than from pattern recall. Can it read an instruction set specification, understand the semantics of each opcode, and produce correct flag computations without cribbing from someone else's &lt;code&gt;z80.c&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;Antirez explored this territory recently with his &lt;a href="https://baud.rs/Gwet5H"&gt;own Z80 emulator project&lt;/a&gt;, using Claude Code to generate a working ZX Spectrum emulator. His experiment demonstrated something important about LLM-assisted development: that providing an agent with proper specifications and documentation, rather than asking it to regurgitate training data, produces implementations that are genuinely novel assemblies of knowledge rather than memorized patterns. The code Claude produced for antirez passed the notoriously thorough ZEXALL test suite, validating every documented Z80 behavior including the undocumented flag bits. Antirez's conclusion was that the LLM wasn't decompressing training data; it was &lt;em&gt;assembling knowledge&lt;/em&gt;, the way a human developer would when working from a datasheet.&lt;/p&gt;
&lt;p&gt;Reading antirez's write-up was the catalyst for this project. I wanted to see whether the same approach (specifications in, working emulator out, clean room constraints enforced throughout) would hold up when I drove the process myself. The Z80 User Manual is one of the best-documented processor specifications ever written. Everything you need to build a working emulator is in that document. The question is whether an LLM, given that document as its source of truth and told not to reference existing implementations, can produce something correct.&lt;/p&gt;
&lt;h3&gt;The Process&lt;/h3&gt;
&lt;p&gt;The workflow looked nothing like "prompt and pray." I started by writing a detailed architectural plan: the CPU state struct layout, the instruction decoding strategy (bit field decomposition), the system emulator's responsibilities, the test coverage targets. This plan became Claude's specification, not just "write a Z80 emulator" but "implement the Z80 CPU using x/y/z/p/q bit field decoding of the opcode byte, with these specific callback interfaces, these T-state timing requirements, and this test structure."&lt;/p&gt;
&lt;p&gt;Claude then implemented each component: &lt;code&gt;z80.h&lt;/code&gt; first, then the full &lt;code&gt;z80.c&lt;/code&gt; CPU core, then the test suite, then the system emulator. I reviewed each piece, ran the tests, identified failures, and fed the errors back. The first compile had a T-state timing issue with DD/FD prefixed instructions; the prefix overhead was being double-counted. One test out of 117 failed. Claude diagnosed the problem (the prefix dispatch was adding 4 T-states on top of instruction timings that already included the prefix cost) and fixed it.&lt;/p&gt;
&lt;p&gt;This iterative loop (plan, implement, test, fix) is exactly how a human developer would work. The difference is velocity. The entire CPU core, all 1,300 lines of C covering every official Z80 instruction plus undocumented behaviors, was produced in a single session. A human developer working from the same specification would spend days or weeks reaching the same point. The LLM's advantage isn't that it knows more; it's that it can hold the entire instruction set specification in context and translate it to code without the cognitive overhead of context-switching between the manual and the editor.&lt;/p&gt;
&lt;h3&gt;The Architecture&lt;/h3&gt;
&lt;p&gt;What Claude produced is a four-file emulator:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;File&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;z80.h&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;CPU state struct, flag constants, public API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;z80.c&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Complete Z80 CPU emulation core&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;z80_test.c&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;117 unit tests covering all instruction groups&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;zxs.c&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Unified emulator binary with ACIA serial and CP/M support&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The design philosophy is straightforward: the CPU core knows nothing about the system it's running in. It communicates with the outside world exclusively through four callback functions: memory read, memory write, I/O in, and I/O out. The system emulator (&lt;code&gt;zxs.c&lt;/code&gt;) provides these callbacks and implements whatever hardware peripherals the target system requires.&lt;/p&gt;
&lt;p&gt;This separation matters. The same CPU core can run a Grant Searle BASIC SBC, an RC2014, or a CP/M program without any changes to &lt;code&gt;z80.c&lt;/code&gt;. The system-specific behavior lives entirely in the callbacks.&lt;/p&gt;
&lt;h3&gt;The CPU State&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://tinycomputers.io/images/clean-room-z80-emulator/z80-architecture.png" alt="Z80 CPU architecture block diagram showing the register file with main and shadow registers, ALU, instruction decoder, and 8-bit data bus / 16-bit address bus" style="max-width: 100%; margin: 0 0 1em 0; border-radius: 4px; box-shadow: 0 10px 20px rgba(0,0,0,.1);" loading="lazy"&gt;&lt;/p&gt;
&lt;p&gt;A Z80 has more programmer-visible state than you might expect if you're used to simpler processors. The main register file includes the accumulator &lt;code&gt;A&lt;/code&gt; and flags register &lt;code&gt;F&lt;/code&gt;, plus three general-purpose register pairs &lt;code&gt;BC&lt;/code&gt;, &lt;code&gt;DE&lt;/code&gt;, and &lt;code&gt;HL&lt;/code&gt;. But then there's a complete &lt;em&gt;shadow&lt;/em&gt; set of all those registers (&lt;code&gt;A'&lt;/code&gt;, &lt;code&gt;F'&lt;/code&gt;, &lt;code&gt;BC'&lt;/code&gt;, &lt;code&gt;DE'&lt;/code&gt;, &lt;code&gt;HL'&lt;/code&gt;), accessible only through the &lt;code&gt;EX AF,AF'&lt;/code&gt; and &lt;code&gt;EXX&lt;/code&gt; exchange instructions.&lt;/p&gt;
&lt;p&gt;Add the two 16-bit index registers &lt;code&gt;IX&lt;/code&gt; and &lt;code&gt;IY&lt;/code&gt;, the stack pointer &lt;code&gt;SP&lt;/code&gt;, the program counter &lt;code&gt;PC&lt;/code&gt;, the interrupt vector register &lt;code&gt;I&lt;/code&gt;, and the memory refresh counter &lt;code&gt;R&lt;/code&gt;, and you've got a substantial amount of state to track. Then there's the interrupt system: two flip-flops &lt;code&gt;IFF1&lt;/code&gt; and &lt;code&gt;IFF2&lt;/code&gt;, the interrupt mode register (modes 0, 1, or 2), a halt flag, and a one-instruction delay flag for the &lt;code&gt;EI&lt;/code&gt; instruction.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* Main registers */&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;D&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;E&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;L&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* Shadow registers */&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;A_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;F_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;B_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;C_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;D_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;E_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;H_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;L_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* Index registers */&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint16_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* Stack pointer and program counter */&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint16_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* Interrupt and refresh registers */&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* Interrupt state */&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;IFF1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IFF2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;halted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ei_delay&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* Cycle counter */&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t_states&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* Memory and I/O callbacks */&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;z80_read_fn&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;mem_read&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;z80_write_fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mem_write&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;z80_in_fn&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;io_in&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;z80_out_fn&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;io_out&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;z80_t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I chose to store each register as an individual byte rather than using unions or bitfields to form 16-bit pairs. This makes the code more explicit; when you see &lt;code&gt;cpu-&amp;gt;B&lt;/code&gt;, you know exactly what's being accessed. Register pairs are assembled and disassembled through inline helper functions like &lt;code&gt;rp_bc()&lt;/code&gt; and &lt;code&gt;set_bc()&lt;/code&gt;. The compiler optimizes these away completely, so there's no performance cost for the clarity.&lt;/p&gt;
&lt;h3&gt;Instruction Decoding: The Bit Field Approach&lt;/h3&gt;
&lt;p&gt;The Z80's instruction encoding has a structure that isn't immediately obvious if you're just looking at an opcode table, but becomes clear once you read the User Manual carefully. Every opcode byte can be decomposed into bit fields:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;x&lt;/code&gt; = bits 7:6 (the two highest bits)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;y&lt;/code&gt; = bits 5:3 (the middle three bits)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;z&lt;/code&gt; = bits 2:0 (the lowest three bits)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;p&lt;/code&gt; = bits 5:4 (y &amp;gt;&amp;gt; 1)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;q&lt;/code&gt; = bit 3 (y &amp;amp; 1)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These fields determine the instruction's category and operands. For the unprefixed opcodes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;x=0&lt;/strong&gt;: Miscellaneous: relative jumps, 16-bit loads, 16-bit arithmetic, INC/DEC, 8-bit loads with immediate data, and the accumulator rotate/DAA/CPL/SCF/CCF group&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;x=1&lt;/strong&gt;: Register-to-register loads (&lt;code&gt;LD r, r'&lt;/code&gt;), with the special case of &lt;code&gt;LD (HL),(HL)&lt;/code&gt; encoding &lt;code&gt;HALT&lt;/code&gt; instead&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;x=2&lt;/strong&gt;: ALU operations between the accumulator and a register (&lt;code&gt;ADD A,r&lt;/code&gt; through &lt;code&gt;CP r&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;x=3&lt;/strong&gt;: Returns, jumps, calls, stack operations, RST vectors, I/O, exchange instructions, interrupt control, and the prefix bytes for extended instruction groups&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This structure means you can decode most unprefixed instructions with a three-level switch on x, then z (or y), rather than a 256-entry lookup table. The code reads more like the specification:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="cm"&gt;/* HALT */&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;halted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;PC&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="cm"&gt;/* LD r[y], r[z] */&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;set_reg8&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get_reg8&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* ALU A, r[z] */&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;do_alu&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get_reg8&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The register index mapping (0=B, 1=C, 2=D, 3=E, 4=H, 5=L, 6=(HL), 7=A) is used consistently throughout the instruction set. Index 6 always means the memory byte pointed to by &lt;code&gt;HL&lt;/code&gt;, which is why &lt;code&gt;LD (HL),(HL)&lt;/code&gt; would be meaningless (load memory from the same memory location) and gets repurposed as &lt;code&gt;HALT&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;The Prefix System&lt;/h3&gt;
&lt;p&gt;The Z80 extends its instruction set through prefix bytes: &lt;code&gt;CB&lt;/code&gt;, &lt;code&gt;ED&lt;/code&gt;, &lt;code&gt;DD&lt;/code&gt;, and &lt;code&gt;FD&lt;/code&gt;. Each opens up a different dimension of functionality.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CB prefix&lt;/strong&gt;: Rotate/shift operations and bit manipulation. The same x/y/z decode applies, but now x=0 is rotate/shift, x=1 is &lt;code&gt;BIT&lt;/code&gt; (test), x=2 is &lt;code&gt;RES&lt;/code&gt; (reset), and x=3 is &lt;code&gt;SET&lt;/code&gt;. This gives you eight different rotate/shift operations on any of the eight register positions, and bit test/set/reset for any of eight bit positions on any register. That's 248 instructions from a single prefix byte.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ED prefix&lt;/strong&gt;: Extended operations that don't fit the main opcode map. Block transfer and search instructions (&lt;code&gt;LDI&lt;/code&gt;, &lt;code&gt;LDIR&lt;/code&gt;, &lt;code&gt;LDD&lt;/code&gt;, &lt;code&gt;LDDR&lt;/code&gt;, &lt;code&gt;CPI&lt;/code&gt;, &lt;code&gt;CPIR&lt;/code&gt;, and their output counterparts), 16-bit arithmetic with carry (&lt;code&gt;ADC HL,rp&lt;/code&gt; and &lt;code&gt;SBC HL,rp&lt;/code&gt;), extended I/O (&lt;code&gt;IN r,(C)&lt;/code&gt; and &lt;code&gt;OUT (C),r&lt;/code&gt;), interrupt mode selection, and a handful of register transfer instructions (&lt;code&gt;LD I,A&lt;/code&gt;, &lt;code&gt;LD A,R&lt;/code&gt;, etc.).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DD and FD prefixes&lt;/strong&gt;: These modify the &lt;em&gt;following&lt;/em&gt; instruction by replacing &lt;code&gt;HL&lt;/code&gt; with &lt;code&gt;IX&lt;/code&gt; or &lt;code&gt;IY&lt;/code&gt; respectively. Wherever the unprefixed instruction uses &lt;code&gt;HL&lt;/code&gt; as a 16-bit register, the prefixed version uses &lt;code&gt;IX&lt;/code&gt; or &lt;code&gt;IY&lt;/code&gt;. Wherever it accesses &lt;code&gt;(HL)&lt;/code&gt; as a memory operand, the prefixed version accesses &lt;code&gt;(IX+d)&lt;/code&gt; or &lt;code&gt;(IY+d)&lt;/code&gt;, where &lt;code&gt;d&lt;/code&gt; is a signed displacement byte inserted between the opcode and any immediate data.&lt;/p&gt;
&lt;p&gt;This substitution extends to the individual &lt;code&gt;H&lt;/code&gt; and &lt;code&gt;L&lt;/code&gt; registers in many contexts. &lt;code&gt;LD A,H&lt;/code&gt; becomes &lt;code&gt;LD A,IXH&lt;/code&gt; with a DD prefix. These "half-index" register operations are technically undocumented but universally supported by real silicon and widely used by software. A clean room implementation needs to handle them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DDCB and FDCB&lt;/strong&gt;: The most complex prefix combination. For bit operations on indexed memory &lt;code&gt;(IX+d)&lt;/code&gt;, the displacement byte comes &lt;em&gt;before&lt;/em&gt; the opcode byte, not after:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;DD CB d op    →    operation on (IX+d)
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This reversed order exists because the Z80's internal pipeline needs the displacement early to begin the memory access while decoding the operation. It's an elegant microarchitectural optimization that reveals itself in the instruction encoding.&lt;/p&gt;
&lt;p&gt;There's an additional subtlety: undocumented behavior where DDCB/FDCB rotate and set/reset operations also copy their result into a register specified by the &lt;code&gt;z&lt;/code&gt; field of the opcode. &lt;code&gt;RLC (IX+5)&lt;/code&gt; with a &lt;code&gt;z&lt;/code&gt; field of 0 also loads the result into &lt;code&gt;B&lt;/code&gt;. This behavior is consistent across all real Z80 chips and is relied upon by some software.&lt;/p&gt;
&lt;h3&gt;The ALU&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://tinycomputers.io/images/clean-room-z80-emulator/z80-die-shot.jpg" alt="High-resolution die photograph of a Zilog Z80 CPU showing the silicon layout of the ALU, register file, and control logic" style="float: right; max-width: 40%; margin: 0 0 1em 1.5em; border-radius: 4px; box-shadow: 0 10px 20px rgba(0,0,0,.1);" loading="lazy"&gt;&lt;/p&gt;
&lt;p&gt;The eight ALU operations (ADD, ADC, SUB, SBC, AND, XOR, OR, CP) share a common pattern in how they affect the flags register. Getting the flags right is the single most important aspect of Z80 emulation, and the area where most subtle bugs hide.&lt;/p&gt;
&lt;p&gt;The Z80's flag register contains eight bits, six of which are documented:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Bit&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;S&lt;/td&gt;
&lt;td&gt;Sign (copy of bit 7 of result)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;Zero (result is zero)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;F5&lt;/td&gt;
&lt;td&gt;Undocumented (copy of bit 5 of result*)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;H&lt;/td&gt;
&lt;td&gt;Half-carry (carry from bit 3 to bit 4)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;F3&lt;/td&gt;
&lt;td&gt;Undocumented (copy of bit 3 of result*)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;P/V&lt;/td&gt;
&lt;td&gt;Parity (logic ops) or Overflow (arithmetic ops)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;N&lt;/td&gt;
&lt;td&gt;Subtract (set if last operation was subtraction)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;td&gt;Carry (carry out of bit 7)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The asterisk on F3 and F5 matters. For most operations, bits 3 and 5 come from the &lt;em&gt;result&lt;/em&gt;. But for &lt;code&gt;CP&lt;/code&gt; (compare), they come from the &lt;em&gt;operand&lt;/em&gt;, not the result. This is because &lt;code&gt;CP&lt;/code&gt; is internally a subtraction that discards the result and keeps only the flags, but the Z80 designers connected the F3 and F5 flag inputs to the operand bus rather than the internal result bus for this particular instruction. It's the kind of detail that only shows up when you're testing against real hardware behavior.&lt;/p&gt;
&lt;p&gt;The overflow flag computation deserves special attention. For addition, overflow occurs when two operands of the same sign produce a result of the opposite sign:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x80&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For subtraction, overflow occurs when two operands of different signs produce a result whose sign differs from the first operand:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;These one-liners replace what would otherwise be multi-branch conditional logic. They work because XOR detects sign differences, and AND combines the two conditions.&lt;/p&gt;
&lt;h3&gt;Block Operations&lt;/h3&gt;
&lt;p&gt;The Z80's block instructions are one of its most powerful features and one of the trickiest to implement correctly. &lt;code&gt;LDIR&lt;/code&gt; (Load, Increment, Repeat) copies a block of memory from the address in &lt;code&gt;HL&lt;/code&gt; to the address in &lt;code&gt;DE&lt;/code&gt;, decrementing &lt;code&gt;BC&lt;/code&gt; as a counter, and repeating until &lt;code&gt;BC&lt;/code&gt; reaches zero.&lt;/p&gt;
&lt;p&gt;The implementation requires careful attention to the repeat mechanism. When &lt;code&gt;BC&lt;/code&gt; is not yet zero, &lt;code&gt;LDIR&lt;/code&gt; decrements &lt;code&gt;PC&lt;/code&gt; by 2 so that the next instruction fetch re-executes the same &lt;code&gt;LDIR&lt;/code&gt; opcode. The repeated iteration takes 21 T-states; the final iteration (when BC reaches zero) takes only 16 T-states. This asymmetry matters for cycle-accurate emulation:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* LDI/LDD/LDIR/LDDR */&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rp_hl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;wb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rp_de&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="cm"&gt;/* Increment or decrement based on instruction */&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;set_hl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rp_hl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;set_de&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rp_de&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;set_hl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rp_hl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;set_de&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rp_de&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;set_bc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rp_bc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="cm"&gt;/* ... flag computation ... */&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rp_bc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;PC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;repeat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;repeat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The flag behavior during block operations is another area where the specification requires careful reading. The &lt;code&gt;P/V&lt;/code&gt; flag reflects whether &lt;code&gt;BC&lt;/code&gt; is non-zero after the decrement, acting as a "more data" indicator. The undocumented F3 and F5 flags come from the sum of the transferred byte and the accumulator, with F5 derived from bit 1 rather than bit 5 of that sum. These details are well-documented in the secondary literature but require careful implementation.&lt;/p&gt;
&lt;p&gt;The search variants (&lt;code&gt;CPI&lt;/code&gt;, &lt;code&gt;CPIR&lt;/code&gt;, etc.) are even more nuanced. They compare the accumulator against memory, set Z if a match is found, and terminate on either a match or &lt;code&gt;BC&lt;/code&gt; reaching zero. The flags after a search operation encode both whether a match was found &lt;em&gt;and&lt;/em&gt; whether the counter has been exhausted, two independent pieces of information packed into the flag register.&lt;/p&gt;
&lt;h3&gt;T-State Timing&lt;/h3&gt;
&lt;p&gt;Every Z80 instruction has a specific T-state (clock cycle) count that's documented in the User Manual. For an emulator driving a simulated UART or polling for terminal input at realistic intervals, accurate timing is essential.&lt;/p&gt;
&lt;p&gt;The timing model uses a simple accumulator. Each call to &lt;code&gt;z80_step()&lt;/code&gt; returns the number of T-states consumed and adds them to a running total in the CPU state. The system emulator uses this to determine when to poll for input or deliver interrupts:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;quit_flag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cpu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t_states&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7373&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cpu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t_states&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;z80_step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;cpu&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* Poll for serial input, deliver interrupts */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The value 7373 represents approximately 2 milliseconds at 3.6864 MHz, the crystal frequency used by many Z80 SBC designs. This frequency was chosen historically because it divides cleanly to produce standard baud rates. At 9600 baud with 10 bits per character (start, 8 data, stop), you get approximately 960 characters per second, or about one character every 3,840 clock cycles. Polling at 7373-cycle intervals gives roughly two opportunities to check for input per character time, enough for reliable serial communication without excessive overhead.&lt;/p&gt;
&lt;p&gt;Conditional instructions have different cycle counts depending on whether the condition is met. A &lt;code&gt;JR Z,d&lt;/code&gt; takes 12 T-states when the jump is taken but only 7 when it falls through. &lt;code&gt;CALL cc,nn&lt;/code&gt; takes 17 T-states when taken, 10 when not. These differences reflect the real pipeline behavior of the Z80; a taken branch requires additional cycles to flush the prefetch and load the new address.&lt;/p&gt;
&lt;h3&gt;The Interrupt System&lt;/h3&gt;
&lt;p&gt;The Z80 supports three interrupt modes and a non-maskable interrupt. Mode 1 is the simplest and most commonly used in SBC designs: a maskable interrupt causes the CPU to push the current PC and jump to address &lt;code&gt;0x0038&lt;/code&gt;, just like an &lt;code&gt;RST 38h&lt;/code&gt; instruction.&lt;/p&gt;
&lt;p&gt;Mode 2 is more sophisticated. The interrupting device places a vector byte on the data bus, which is combined with the &lt;code&gt;I&lt;/code&gt; register to form a 16-bit address into a vector table in memory. The CPU reads the actual interrupt service routine address from that table location. This provides up to 128 different interrupt vectors, enabling complex multi-device interrupt schemes.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;EI&lt;/code&gt; instruction has a subtle but critical behavior: it doesn't enable interrupts immediately. Instead, it sets a one-instruction delay, so the &lt;em&gt;next&lt;/em&gt; instruction after &lt;code&gt;EI&lt;/code&gt; executes before any pending interrupt can be serviced. This guarantees that &lt;code&gt;EI; RETI&lt;/code&gt; (enable interrupts, then return from interrupt) executes atomically; the return completes before any new interrupt can preempt it.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* EI */&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;IFF1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;IFF2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ei_delay&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And in the interrupt handler:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;z80_interrupt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;z80_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;cpu&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;cpu&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;IFF1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cpu&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ei_delay&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* ... process interrupt ... */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;DAA: The Most Misunderstood Instruction&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;DAA&lt;/code&gt; (Decimal Adjust Accumulator) is arguably the Z80's most complex single instruction. It adjusts the result of a previous addition or subtraction to produce a valid BCD (Binary-Coded Decimal) result. The adjustment depends on three pieces of state: the current value of the accumulator, the carry flag, and the half-carry flag. It also behaves differently depending on whether the previous operation was addition or subtraction (tracked by the N flag).&lt;/p&gt;
&lt;p&gt;The algorithm: if the lower nibble exceeds 9 or the half-carry flag is set, add (or subtract) 0x06. If the upper nibble exceeds 9 or the carry flag is set, add (or subtract) 0x60. Update carry if the upper correction was applied.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;daa&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;z80_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;correction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;carry&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Z80_CF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Z80_HF&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x0F&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;correction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x06&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;carry&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x99&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;correction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x60&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;carry&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Z80_CF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Z80_NF&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;correction&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;correction&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sz53p&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;carry&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Z80_NF&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Z80_HF&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;BCD arithmetic was important in the era when the Z80 was designed. Financial calculations, display drivers, and industrial controllers all needed decimal precision without floating-point hardware. The Z80's DAA instruction made BCD arithmetic practical on an 8-bit processor by adjusting binary results back into valid decimal digits after each operation.&lt;/p&gt;
&lt;h3&gt;Testing: 117 Ways to Be Wrong&lt;/h3&gt;
&lt;p&gt;Writing a test suite for a CPU emulator is an exercise in paranoia. Every instruction has multiple paths through the flag logic, multiple edge cases in operand handling, and multiple interactions with the rest of the CPU state. The test suite covers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Register loads&lt;/strong&gt;: 8-bit immediate, register-to-register, 16-bit immediate, indirect through BC/DE/HL, absolute addressing, HL indirect&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;8-bit ALU&lt;/strong&gt;: All eight operations with basic values, carry/borrow propagation, overflow detection, half-carry, undocumented flag bits&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;16-bit arithmetic&lt;/strong&gt;: ADD HL with carry, SBC HL, ADC HL&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;INC/DEC&lt;/strong&gt;: 8-bit with overflow and half-carry edge cases, 16-bit wrapping&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rotates and shifts&lt;/strong&gt;: RLCA/RRCA/RLA/RRA (accumulator), CB-prefixed RLC/RRC/RL/RR/SLA/SRA/SRL on registers&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;BIT/SET/RES&lt;/strong&gt;: Test, set, and reset individual bits&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Jumps and branches&lt;/strong&gt;: JP, JR, DJNZ with taken/not-taken paths&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Calls and returns&lt;/strong&gt;: CALL/RET with condition codes, RST vectors&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stack operations&lt;/strong&gt;: PUSH/POP for all register pairs including AF&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Block operations&lt;/strong&gt;: LDI/LDIR/LDD, CPI/CPIR, INI/OUTI&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Exchange instructions&lt;/strong&gt;: EX AF, EXX, EX DE,HL, EX (SP),HL&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Interrupt system&lt;/strong&gt;: IM modes, Mode 1 and Mode 2 dispatch, NMI, EI delay&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IX/IY indexed&lt;/strong&gt;: Loads, stores, arithmetic, IXH/IXL access, DDCB bit operations&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;T-state timing&lt;/strong&gt;: Verified counts for representative instructions from each group&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;R register&lt;/strong&gt;: Increment behavior, bit 7 preservation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each test sets up a specific CPU state, loads a short instruction sequence into memory, executes it, and verifies the results. The test framework is minimal, just macros for assertions and a runner that reports pass/fail:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="gh"&gt;Z80 CPU Test Suite&lt;/span&gt;
&lt;span class="gh"&gt;==================&lt;/span&gt;
test_nop                                                    PASS
&lt;span class="gh"&gt;test_ld_reg_imm                                             PASS&lt;/span&gt;
&lt;span class="gh"&gt;...&lt;/span&gt;
test_r_bit7_preserved                                       PASS

==================
Results: 117/117 passed
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;All 117 pass. But passing unit tests isn't the same as passing real software. The real validation comes from booting actual ROMs.&lt;/p&gt;
&lt;h3&gt;The System Emulator&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;zxs&lt;/code&gt; binary wraps the CPU core with enough peripheral emulation to run two classes of software: Grant Searle-style BASIC SBCs with ACIA serial I/O, and CP/M .COM programs with a minimal BDOS shim.&lt;/p&gt;
&lt;h4&gt;ACIA Serial Emulation&lt;/h4&gt;
&lt;p&gt;The Motorola MC6850 ACIA (Asynchronous Communications Interface Adapter) is the serial chip used in the Grant Searle Z80 SBC design and many similar projects. It presents two registers to the CPU:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Status register&lt;/strong&gt; (base address): Bit 0 = Receive Data Register Full (RDRF), Bit 1 = Transmit Data Register Empty (TDRE)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data register&lt;/strong&gt; (base + 1): Read for received data, write to transmit&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The emulation maps these to terminal I/O. TDRE is always set (the "transmitter" is always ready since we're writing directly to stdout). RDRF is set when non-blocking &lt;code&gt;read()&lt;/code&gt; has captured a character from stdin. The ACIA's interrupt capability is emulated: when receive interrupts are enabled and data is available, the emulator delivers an RST 38h interrupt to the CPU.&lt;/p&gt;
&lt;h4&gt;Serial Port Auto-Detection&lt;/h4&gt;
&lt;p&gt;Rather than hardcoding the ACIA port address, the emulator scans the loaded ROM for &lt;code&gt;IN A,(n)&lt;/code&gt; (&lt;code&gt;DB xx&lt;/code&gt;) and &lt;code&gt;OUT (n),A&lt;/code&gt; (&lt;code&gt;D3 xx&lt;/code&gt;) instruction patterns. It collects the referenced port addresses and looks for adjacent pairs (status + data ports) that have both IN and OUT references, the signature of a serial peripheral. For the Grant Searle ROM, this reliably detects port base &lt;code&gt;0x80&lt;/code&gt;. For ROMs that use different port configurations, a &lt;code&gt;--port&lt;/code&gt; flag provides a manual override.&lt;/p&gt;
&lt;h4&gt;CP/M Mode&lt;/h4&gt;
&lt;p&gt;For &lt;code&gt;.com&lt;/code&gt; and &lt;code&gt;.cim&lt;/code&gt; files, the emulator switches to CP/M mode: the program is loaded at &lt;code&gt;0x0100&lt;/code&gt;, the stack pointer is set to &lt;code&gt;0xFFFE&lt;/code&gt; with a return address of &lt;code&gt;0x0000&lt;/code&gt; pushed, and BDOS calls are intercepted at address &lt;code&gt;0x0005&lt;/code&gt;. Only the essential BDOS functions are implemented (console output (function 2) and string output (function 9)), but this is enough to run many CP/M utilities and test programs.&lt;/p&gt;
&lt;h4&gt;System Auto-Detection&lt;/h4&gt;
&lt;p&gt;File extension determines the system type: &lt;code&gt;.com&lt;/code&gt; and &lt;code&gt;.cim&lt;/code&gt; files run in CP/M mode, everything else runs as a BASIC SBC. Intel HEX files are detected and parsed regardless of extension. The &lt;code&gt;--system&lt;/code&gt; flag overrides auto-detection when needed.&lt;/p&gt;
&lt;h3&gt;Booting BASIC&lt;/h3&gt;
&lt;p&gt;The real test of any emulator is whether it runs real software. Here's what happens when you point &lt;code&gt;zxs&lt;/code&gt; at Grant Searle's BASIC ROM:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;./zxs&lt;span class="w"&gt; &lt;/span&gt;basic.rom
Loaded&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;8192&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bytes&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;0x0000
BASIC&lt;span class="w"&gt; &lt;/span&gt;SBC&lt;span class="w"&gt; &lt;/span&gt;mode,&lt;span class="w"&gt; &lt;/span&gt;serial&lt;span class="w"&gt; &lt;/span&gt;port&lt;span class="w"&gt; &lt;/span&gt;base:&lt;span class="w"&gt; &lt;/span&gt;0x80&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;Ctrl+&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
Z80&lt;span class="w"&gt; &lt;/span&gt;SBC&lt;span class="w"&gt; &lt;/span&gt;By&lt;span class="w"&gt; &lt;/span&gt;Grant&lt;span class="w"&gt; &lt;/span&gt;Searle

Memory&lt;span class="w"&gt; &lt;/span&gt;top?
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That banner, "Z80 SBC By Grant Searle," represents thousands of Z80 instructions executing correctly. The ROM initializes memory, configures the ACIA, sets up the interrupt handler, and enters the BASIC interpreter's command loop. Each of those steps exercises a different subset of the CPU's instruction set. A single incorrectly implemented instruction (a wrong flag bit, a miscounted displacement, a botched stack operation) would cause the ROM to crash or produce garbage output.&lt;/p&gt;
&lt;p&gt;The RC2014 BASIC ROM boots as well, though it requires specifying the serial port base since its ROM references multiple I/O addresses:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;./zxs&lt;span class="w"&gt; &lt;/span&gt;--port&lt;span class="w"&gt; &lt;/span&gt;0x80&lt;span class="w"&gt; &lt;/span&gt;rc2014_56k.hex
Loaded&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;8154&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bytes&lt;span class="w"&gt; &lt;/span&gt;from&lt;span class="w"&gt; &lt;/span&gt;HEX&lt;span class="w"&gt; &lt;/span&gt;file
BASIC&lt;span class="w"&gt; &lt;/span&gt;SBC&lt;span class="w"&gt; &lt;/span&gt;mode,&lt;span class="w"&gt; &lt;/span&gt;serial&lt;span class="w"&gt; &lt;/span&gt;port&lt;span class="w"&gt; &lt;/span&gt;base:&lt;span class="w"&gt; &lt;/span&gt;0x80&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;Ctrl+&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

RC2014&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;MS&lt;span class="w"&gt; &lt;/span&gt;Basic&lt;span class="w"&gt; &lt;/span&gt;Loader
z88dk&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;feilipu

Memory&lt;span class="w"&gt; &lt;/span&gt;top?
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Intel HEX file loading is handled transparently. The emulator detects the format by checking for the &lt;code&gt;:&lt;/code&gt; record marker and parses the standard Intel HEX record format (data records, EOF records, address fields, checksums).&lt;/p&gt;
&lt;h3&gt;What I Learned About LLM Clean Room Development&lt;/h3&gt;
&lt;p&gt;This project taught me as much about working with LLMs as it did about the Z80. Some observations:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Specification quality determines output quality.&lt;/strong&gt; When I gave Claude a vague instruction like "implement the Z80," the result would have been a generic emulator shaped by whatever training data dominates. When I gave it a detailed architectural plan (bit field decoding, specific callback interfaces, T-state requirements), the result was a coherent, well-structured implementation that reflected the design decisions in the specification. Antirez observed the same thing: the LLM performs dramatically better when you provide documentation and constraints rather than open-ended prompts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;LLMs can work from datasheets, not just from memory.&lt;/strong&gt; The clean room constraint was the whole point: could Claude produce correct Z80 flag behavior, proper DDCB/FDCB displacement ordering, accurate block operation semantics, all derived from specification knowledge rather than memorized source code? The 117 passing tests and booting ROMs suggest it can. The code doesn't look like any particular existing emulator. The bit field decoder, the ALU structure, the prefix dispatch: these are architecturally reasonable but stylistically original.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The bug pattern was illuminating.&lt;/strong&gt; The one test failure in the initial implementation was a T-state timing issue: DD/FD prefix overhead was being double-counted. This is exactly the kind of bug a human developer would make when implementing prefix dispatch, a bookkeeping error at the boundary between the prefix handler and the main decoder. It was not the kind of error you'd see from copying existing code, where the timing would already be correct. The bug was &lt;em&gt;original&lt;/em&gt;, which paradoxically increases confidence that the implementation is too.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Z80's instruction encoding is remarkably systematic.&lt;/strong&gt; Once you express the x/y/z/p/q bit field decomposition in the architectural plan, the entire instruction set becomes a small number of patterns applied consistently across register indices and operation codes. Claude picked up on this structure immediately and produced a decoder that reads like the specification. The elegance of Zilog's encoding is invisible in an opcode table but obvious in a decoder, and an LLM can see that structure when pointed at it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The DD/FD prefix system is essentially a register renaming mechanism.&lt;/strong&gt; It doesn't introduce new operations; it modifies existing ones by replacing HL with IX or IY. Expressing this in the plan as "replace HL→IX/IY, H→IXH/IYH, L→IXL/IYL, (HL)→(IX+d)/(IY+d)" gave Claude the conceptual framework to implement DD/FD support as a modifier on the existing decoder rather than duplicating 200+ instruction handlers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Flag behavior is the specification.&lt;/strong&gt; Two Z80 emulators can produce identical results for every instruction and still differ in their flag register output. The undocumented F3 and F5 bits, the special CP flag behavior, the block instruction flag computations: these are what distinguish a correct emulator from an approximately correct one. Claude got the CP flag anomaly right (F3/F5 from the operand, not the result), which suggests it was working from specification knowledge about the Z80's internal bus routing rather than just copying a known-good flag computation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Clean room constraints make LLM output more trustworthy, not less.&lt;/strong&gt; There's an irony here: by &lt;em&gt;restricting&lt;/em&gt; what the LLM can reference, you get &lt;em&gt;more&lt;/em&gt; confidence in the result. If Claude had produced code that looked suspiciously like MAME's Z80 core, you'd wonder whether it was simply reciting training data. Instead, it produced an implementation that's structurally sound, stylistically distinct, and correct, the hallmarks of working from specifications rather than from examples.&lt;/p&gt;
&lt;h3&gt;The Code&lt;/h3&gt;
&lt;p&gt;The complete source is &lt;a href="https://baud.rs/Ae0K75"&gt;on GitHub&lt;/a&gt;, five files totaling roughly 3,000 lines of C. It builds with &lt;code&gt;make&lt;/code&gt;, produces zero warnings with &lt;code&gt;-Wall -Wextra&lt;/code&gt;, and runs Grant Searle and RC2014 BASIC ROMs out of the box.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;make
cc&lt;span class="w"&gt; &lt;/span&gt;-Wall&lt;span class="w"&gt; &lt;/span&gt;-Wextra&lt;span class="w"&gt; &lt;/span&gt;-O2&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;zxs&lt;span class="w"&gt; &lt;/span&gt;zxs.c&lt;span class="w"&gt; &lt;/span&gt;z80.c
cc&lt;span class="w"&gt; &lt;/span&gt;-Wall&lt;span class="w"&gt; &lt;/span&gt;-Wextra&lt;span class="w"&gt; &lt;/span&gt;-O2&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;z80_test&lt;span class="w"&gt; &lt;/span&gt;z80_test.c&lt;span class="w"&gt; &lt;/span&gt;z80.c

$&lt;span class="w"&gt; &lt;/span&gt;./z80_test
Z80&lt;span class="w"&gt; &lt;/span&gt;CPU&lt;span class="w"&gt; &lt;/span&gt;Test&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;Suite&lt;/span&gt;
&lt;span class="o"&gt;==================&lt;/span&gt;
...
Results:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;117&lt;/span&gt;/117&lt;span class="w"&gt; &lt;/span&gt;passed

$&lt;span class="w"&gt; &lt;/span&gt;./zxs&lt;span class="w"&gt; &lt;/span&gt;basic.rom
Z80&lt;span class="w"&gt; &lt;/span&gt;SBC&lt;span class="w"&gt; &lt;/span&gt;By&lt;span class="w"&gt; &lt;/span&gt;Grant&lt;span class="w"&gt; &lt;/span&gt;Searle
Memory&lt;span class="w"&gt; &lt;/span&gt;top?
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There is more to do. ZEXALL compliance would be the next validation milestone; it tests every instruction against known-good results captured from real Z80 hardware. ZX Spectrum emulation would require adding ULA video, keyboard matrix scanning, and Spectrum-specific memory banking. Cycle-exact timing would enable accurate sound emulation and demo-scene effects.&lt;/p&gt;
&lt;p&gt;But for now, the ROM boots, BASIC runs, and every line of the emulator traces back to Z80 specifications and documentation rather than someone else's &lt;code&gt;z80.c&lt;/code&gt;. An LLM wrote it, but a human designed it, constrained it, tested it, and validated it against real hardware ROM images. The clean room constraint didn't just produce a trustworthy emulator; it produced a trustworthy &lt;em&gt;process&lt;/em&gt; for using LLMs on systems programming tasks. Give the model a specification instead of an open-ended prompt. Enforce constraints that prevent training data regurgitation. Validate against real-world artifacts, not just unit tests.&lt;/p&gt;
&lt;p&gt;Antirez asked whether LLMs create original code or decompress training data. This project is one more data point on the side of original creation, but only when you set up the conditions for it. The clean room is what makes the difference.&lt;/p&gt;</description><category>acia</category><category>ai</category><category>c</category><category>claude</category><category>clean room</category><category>cp/m</category><category>cpu design</category><category>emulation</category><category>grant searle</category><category>instruction decoding</category><category>llm</category><category>rc2014</category><category>retrocomputing</category><category>serial</category><category>z80</category><category>zilog</category><guid>https://tinycomputers.io/posts/clean-room-z80-emulator.html</guid><pubDate>Fri, 27 Feb 2026 00:00:00 GMT</pubDate></item><item><title>The Z-80 Microcomputer Handbook: A 1978 Reference That Outlived Its Era</title><link>https://tinycomputers.io/posts/the-z80-microcomputer-handbook-william-barden.html?utm_source=feed&amp;utm_medium=rss&amp;utm_campaign=rss</link><dc:creator>A.C. Jokela</dc:creator><description>&lt;div class="audio-widget"&gt;
&lt;div class="audio-widget-header"&gt;
&lt;span class="audio-widget-icon"&gt;🎧&lt;/span&gt;
&lt;span class="audio-widget-label"&gt;Listen to this article&lt;/span&gt;
&lt;/div&gt;
&lt;audio controls preload="metadata"&gt;
&lt;source src="https://tinycomputers.io/the-z80-microcomputer-handbook-william-barden_tts.mp3" type="audio/mpeg"&gt;
Your browser does not support the audio element.
&lt;/source&gt;&lt;/audio&gt;
&lt;div class="audio-widget-footer"&gt;26 min · AI-generated narration&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;&lt;img src="https://tinycomputers.io/images/z80-barden-book/cover-001.jpg" style="width: 400px; box-shadow: 0 30px 40px rgba(0,0,0,.1); float: right; margin: 25px;"&gt;&lt;/p&gt;
&lt;p&gt;In 1978, William Barden, Jr. set out to write a book with a threefold purpose: to acquaint the reader with the hardware of the Z80, to discuss its "almost overwhelming" software instruction set, and to describe the microcomputer systems being built around it. The result was &lt;em&gt;&lt;a href="https://baud.rs/5brWaW"&gt;The Z-80 Microcomputer Handbook&lt;/a&gt;&lt;/em&gt;, published by Howard W. Sams &amp;amp; Co., one of the most prolific technical publishers of the era. At just over 300 pages, Barden delivered on all three promises, producing a reference that served as both tutorial and encyclopedia for what was arguably the most important &lt;a href="https://baud.rs/DlwHJZ"&gt;microprocessor&lt;/a&gt; of the late 1970s.&lt;/p&gt;
&lt;p&gt;The copy I have is the eighth printing from 1985. Eight printings. The book was first published in 1978, and Howard W. Sams was still running the presses seven years later. I'll confess I hadn't fully appreciated that the Z80's popularity carried that kind of momentum into the mid-1980s, by which point Intel's 80286 had been on the market for three years and IBM's AT was already sitting on desks in corporate offices across America. Yet here was a book about an 8-bit processor from 1976, still selling briskly enough to justify another print run. That tells you something about the Z80's staying power, and something about the quality of Barden's handbook.&lt;/p&gt;
&lt;h3&gt;The Author and the Publisher&lt;/h3&gt;
&lt;p&gt;William Barden, Jr. was a prolific technical author who wrote extensively about microprocessors and microcomputers throughout the late 1970s and 1980s. His writing style sits in a comfortable middle ground between the dry precision of a Zilog datasheet and the conversational approachability of a hobbyist magazine column. He assumes the reader has some technical foundation but doesn't demand an electrical engineering degree. The prose is clear, methodical, and, when the subject matter allows, occasionally wry.&lt;/p&gt;
&lt;p&gt;Howard W. Sams &amp;amp; Co., a subsidiary of Macmillan, was headquartered in Indianapolis and had built a reputation as one of the go-to publishers for electronics and computing references. Their catalog included the famous &lt;em&gt;&lt;a href="https://baud.rs/samstechnical"&gt;Photofact&lt;/a&gt;&lt;/em&gt; service manuals and a long list of titles covering everything from transistor theory to amateur radio. A Sams book on your shelf carried a certain implicit endorsement: this was going to be technically sound, well-organized, and useful.&lt;/p&gt;
&lt;h3&gt;Three Sections, One Processor&lt;/h3&gt;
&lt;p&gt;Barden organized the book into three distinct sections, each approaching the Z80 from a different angle. Section I covers Z80 hardware: the architecture, interface signals and timing, addressing modes, instruction set, flags and arithmetic operations, interrupt sequences, and interfacing memory and I/O devices. Section II shifts to Z80 software, beginning with the assembly process itself and then working through the major instruction groups: data movement, arithmetic and logical operations, shifting and bit manipulation, list and table operations, subroutine calls, I/O and interrupt operations, and commonly used subroutines. Section III surveys five commercial microcomputer systems built around the Z80.&lt;/p&gt;
&lt;p&gt;This three-part structure gives the book a completeness that many competing references lacked. Readers who wanted to understand the Z80 at the silicon level could camp out in Section I. Programmers who needed to write assembly code had a thorough software reference in Section II. And anyone trying to decide which Z80 system to buy, or trying to understand what made these systems different from one another, could turn to Section III for a comparative tour.&lt;/p&gt;
&lt;h3&gt;The Hardware Foundation&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://tinycomputers.io/images/z80-barden-book/architecture-016.jpg" style="width: 500px; box-shadow: 0 30px 40px rgba(0,0,0,.1); float: left; margin: 25px;"&gt;&lt;/p&gt;
&lt;p&gt;Section I opens with a concise but thorough treatment of the Z80's internal architecture. Barden walks the reader through the processor's register set: fourteen general-purpose 8-bit registers organized in two banks (A through L, and their primed counterparts A' through L'), plus the special-purpose registers: two index registers (IX and IY), the stack pointer, program counter, interrupt vector register, and memory refresh counter.&lt;/p&gt;
&lt;p&gt;The dual register bank architecture receives careful attention, and rightly so. The ability to swap between two complete register sets with a single EXX instruction was one of the Z80's most distinctive features. Barden explains not just the mechanics but the motivation: fast interrupt handling without the overhead of pushing and popping registers to the stack. For real-time applications (process control, data acquisition, communications) this was a significant advantage over the Intel 8080A, which required explicit save-and-restore sequences.&lt;/p&gt;
&lt;p&gt;The flag register documentation is similarly thorough. Each of the six testable flags (Sign, Zero, Half-carry, Parity/Overflow, Subtract, and Carry) gets individual treatment, with clear diagrams showing bit positions and the conditions under which each flag is set or cleared. Barden's flag register diagram on page 19 is the kind of figure you'd photocopy and tape to the wall above your workbench.&lt;/p&gt;
&lt;p&gt;Chapter 3 dives into the Z80's interface signals and timing with a level of detail that borders on the exhaustive. Every control signal is documented: MREQ, IORQ, RD, WR, RFSH, HALT, WAIT, INT, NMI, BUSRQ, BUSAK, and the rest. The timing diagrams for M1 cycles, memory read and write cycles, I/O cycles, interrupt acknowledge sequences, and bus request/acknowledge handshakes are presented with the precision needed for hardware designers wiring up actual systems. This is reference material, not light reading, but it's the kind of reference material you desperately need when your homebrew system isn't behaving and you're staring at an oscilloscope trace trying to figure out why.&lt;/p&gt;
&lt;p&gt;Chapter 4's treatment of addressing modes deserves special mention. The Z80 supported ten addressing modes: implied, immediate, extended immediate, register, register indirect, extended, modified page zero, relative, indexed, and bit addressing. Barden documents each with examples showing the instruction encoding at the bit level. The indexed addressing mode, using IX or IY plus a displacement byte, was a Z80 innovation that made structured data access far more practical than on the 8080A. Barden's diagrams showing multi-byte instruction formats, with op-codes, displacement values, and immediate data laid out byte by byte, are models of technical illustration.&lt;/p&gt;
&lt;p&gt;The instruction set itself, covered in Chapter 5, is presented in tabular form with every detail a programmer needs: mnemonic, symbolic operation, flag effects, op-code encoding in binary, byte count, machine cycle count, and T-state count. These tables span dozens of pages and represent the kind of painstaking documentation that made the book worth keeping within arm's reach during coding sessions. The eleven instruction groups (from 8-bit loads through block transfers, arithmetic operations, rotates and shifts, bit manipulation, jumps, calls, and I/O) are each given systematic treatment.&lt;/p&gt;
&lt;p&gt;Chapter 8 rounds out the hardware section with a practical discussion of interfacing memory and I/O devices to the Z80. The treatment of the Z80 PIO (Parallel Input/Output) chip is particularly detailed, covering all four operating modes with programming examples. Barden walks through the initialization sequences for each mode, the interrupt vector configuration, and the handshaking protocols, exactly the kind of information you'd struggle to extract from &lt;a href="https://baud.rs/MIPV1T"&gt;Zilog's own documentation&lt;/a&gt; without considerable effort.&lt;/p&gt;
&lt;h3&gt;The Software Perspective&lt;/h3&gt;
&lt;p&gt;Section II opens with what might be the most pedagogically effective chapter in the book: Chapter 9, the Z80 Assembler. Rather than jumping straight into assembly language syntax, Barden starts with raw machine language. He presents a trivial program (adding the numbers one through ten) first as a series of mnemonics, then as hand-assembled machine code with each op-code and operand byte spelled out in hexadecimal. He then shows the same program rewritten with a loop, and walks through the manual assembly process step by step: calculating instruction lengths, assigning memory addresses, resolving label references, filling in the binary encoding of each instruction.&lt;/p&gt;
&lt;p&gt;This is brilliant pedagogy. By forcing the reader through the pain of manual assembly (calculating that a JP NZ,LOOP instruction at address 0105H needs to encode the target address 0103H as bytes 03H and 01H in little-endian order) Barden ensures they understand exactly what an assembler does before they start using one. The transition from manual assembly to symbolic assembly language feels earned rather than arbitrary. When Barden introduces labels, pseudo-operations, expression evaluation, and the two-pass assembly process, the reader understands &lt;em&gt;why&lt;/em&gt; these features exist, not just how to use them.&lt;/p&gt;
&lt;p&gt;Chapters 10 through 15 systematically work through the instruction groups from a programmer's perspective. Each chapter takes a logical group (data movement, arithmetic and logic, shifting and bit manipulation, list and table operations, subroutines, I/O and CPU control) and provides detailed examples showing how the instructions are used in practice. The block transfer instructions (LDI, LDIR, LDD, LDDR) and block search instructions (CPI, CPIR) receive particularly good coverage, as these were among the Z80's most powerful features and had no equivalent in the 8080A instruction set.&lt;/p&gt;
&lt;p&gt;Chapter 16, covering commonly used subroutines, is where the book transitions from reference to practical cookbook. Barden provides complete, tested subroutine implementations for comparison, timing loops, multiply, divide, multiple-precision arithmetic, ASCII-to-binary conversion, base conversion, memory fill, string comparison, and table search. Each subroutine is documented with its entry conditions, exit conditions, and register usage, the kind of disciplined documentation that professional assembly programmers live by. The table search routine, using IX as a base pointer with entry size in DE, is a clean example of the Z80's indexed addressing mode earning its keep.&lt;/p&gt;
&lt;h3&gt;A Snapshot of the Ecosystem&lt;/h3&gt;
&lt;p&gt;Section III is where the book transforms from a processor reference into a historical document. In two chapters, Barden surveys five companies manufacturing Z80-based microcomputer systems: Zilog itself, Technical Design Labs (TDL), Cromemco, The Digital Group, and Radio Shack.&lt;/p&gt;
&lt;p&gt;The Zilog chapter covers the Z80 MCB (Microcomputer Board), a complete single-board computer measuring 7.7 by 7.75 inches. With 4K of dynamic RAM, up to 4K of EPROM or PROM, a PIO for parallel I/O, a USART for serial communication, and a CTC for timing, the MCB was a capable development platform. Barden documents the memory map, I/O port addressing, interrupt configuration, and the 1K monitor program with its eight commands for examining memory, setting breakpoints, and controlling program execution. The minimum MCB system (the board itself, a 5-volt power supply, and a Teletype ASR-33) was a complete development environment, albeit a spartan one.&lt;/p&gt;
&lt;p&gt;The Cromemco coverage reveals a more ambitious ecosystem. Their Z-1 and Z-2 systems were built around the &lt;a href="https://tinycomputers.io/posts/george-morrow-pioneer-of-personal-computing.html"&gt;S-100 bus&lt;/a&gt;, with the Z-2 offering a chassis with 21 card slots, a 30-amp power supply, and room for serious expansion. Cromemco's peripheral lineup included a TV DAZZLER for color graphics, a Digital Interface Board with analog-to-digital and digital-to-analog converters, and their BYTESAVER EPROM programmer board. Their CONTROL BASIC (a specialized BASIC interpreter designed for process control and automated testing) hints at the industrial applications that were already finding the Z80.&lt;/p&gt;
&lt;p&gt;The Digital Group section reveals a company taking a different approach: offering CPU boards for multiple processor families (Motorola 6800, MOS Technology 6502, Intel 8080A, and Z80) all interchangeable at the board level. Their Phi-Deck cassette storage system, with 800 bytes per second transfer rates and CRC error checking, was a notably sophisticated approach to the cassette storage problem.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://tinycomputers.io/images/z80-barden-book/trs80-273.jpg" style="width: 500px; box-shadow: 0 30px 40px rgba(0,0,0,.1); float: left; margin: 25px;"&gt;&lt;/p&gt;
&lt;p&gt;And then there's Radio Shack. Barden's description of the TRS-80 stands out because of what it represented: a completely integrated, turnkey system that a consumer could purchase, take home, plug in, and immediately begin programming in BASIC. While the other systems in this chapter required varying degrees of assembly, configuration, and technical knowledge, the TRS-80 was designed for people who wanted to use a computer, not build one. With its 53-key keyboard, 12-inch monitor, cassette storage, and 4K of ROM containing a BASIC interpreter, it was a vision of the microcomputer's commercial future, even if its 64-character-by-16-line display and 4K of RAM seem quaint today.&lt;/p&gt;
&lt;p&gt;Reading these system descriptions in sequence, you can see the microcomputer market stratifying in real time. At one end, boards like Zilog's MCB served engineers and serious hobbyists who wanted maximum flexibility. In the middle, S-100 systems from Cromemco and others offered expandability with some degree of standardization. And at the consumer end, Radio Shack was proving that microcomputers could be mass-market products. All of them ran on the Z80.&lt;/p&gt;
&lt;h3&gt;The Intel Shadow&lt;/h3&gt;
&lt;p&gt;What makes the 1985 printing date so remarkable is the context in which someone would have been buying this book. By 1985, the microcomputer landscape had shifted dramatically from the world Barden documented in 1978.&lt;/p&gt;
&lt;p&gt;Intel had introduced the 8086 in 1978 (the same year this book was published) and its cost-reduced sibling, the 8088, in 1979. When IBM chose the 8088 for its Personal Computer in 1981, the x86 architecture gained a gravitational pull that would reshape the entire industry. The Intel 80286, launched in 1982, brought protected mode, a 16-megabyte address space, and hardware memory management. When IBM built the 80286 into the PC/AT in August 1984, it created what would become the standard business computer platform for years to come. The AT was fast, expandable, and, critically, backward compatible with the enormous library of software already written for the original PC.&lt;/p&gt;
&lt;p&gt;By 1985, the trajectory was clear. The x86 architecture was the future of personal computing. CP/M, which had been the dominant operating system for Z80 machines, was fading in the face of MS-DOS. The TRS-80 line was winding down. Cromemco had pivoted to 68000-based systems. The Z80's reign as the king of personal computing was effectively over.&lt;/p&gt;
&lt;p&gt;And yet the eighth printing rolled off the presses.&lt;/p&gt;
&lt;p&gt;The Z80 endured because personal computing was never the whole story. The processor had found its way into embedded systems, industrial controllers, point-of-sale terminals, scientific instruments, and countless other applications where its simplicity, low cost, and well-understood behavior were more valuable than raw performance. The Z80 didn't need a 16-megabyte address space to control a factory floor. It didn't need protected mode to run a cash register. It needed to be cheap, reliable, and thoroughly documented, and books like Barden's were part of that documentation ecosystem.&lt;/p&gt;
&lt;p&gt;There's also the educational angle. In 1985, the Z80 was still one of the best processors for &lt;em&gt;learning&lt;/em&gt; computer architecture. Its instruction set was complex enough to illustrate real-world design tradeoffs (accumulator-based operations, register pairs for 16-bit addressing, multiple addressing modes, condition flags) without being so complex as to overwhelm a student. Many universities and technical colleges were still teaching microprocessor courses using the Z80 well into the late 1980s. For those students and their instructors, Barden's handbook was still entirely relevant.&lt;/p&gt;
&lt;h3&gt;The Book as Reference&lt;/h3&gt;
&lt;p&gt;Evaluating &lt;em&gt;The Z-80 Microcomputer Handbook&lt;/em&gt; as a technical reference, it holds up remarkably well within its domain. The instruction set tables in Chapter 5 are comprehensive and clearly formatted, with every detail needed for hand-coding or verifying assembler output. The appendices (covering electrical specifications, an 8080-to-Z80 instruction cross-reference, a complete instruction summary, binary and hexadecimal tables, and ASCII codes) round out the reference material.&lt;/p&gt;
&lt;p&gt;The 8080/Z80 comparison in Appendix B is particularly useful for readers coming from the Intel side. Since the Z80 included the entire 8080A instruction set as a subset (using Zilog's own mnemonics rather than Intel's), this cross-reference served as a Rosetta Stone for programmers transitioning between the two architectures. Many Z80 systems needed to run software originally written for the 8080A, and understanding the mapping between Intel and Zilog mnemonics was a practical necessity.&lt;/p&gt;
&lt;p&gt;Where the book shows its age most clearly is in Section III. The specific microcomputer systems described (the Zilog MCB, the TDL ZPUTM and Xitan, the Cromemco Z-1 and Z-2, the Digital Group systems, and the TRS-80) are all long discontinued. But this is precisely what makes Section III valuable today: it's a primary source document of a hardware ecosystem that existed for a brief, vibrant moment and then vanished. You won't find this level of detail about the Digital Group's Phi-Deck cassette system or TDL's System Monitor Board in Wikipedia.&lt;/p&gt;
&lt;h3&gt;A Companion Piece&lt;/h3&gt;
&lt;p&gt;Readers of this site may notice a natural pairing with Steve Ciarcia's &lt;em&gt;&lt;a href="https://tinycomputers.io/posts/build-your-own-z80-computer-steve-ciarcia.html"&gt;Build Your Own Z80 Computer&lt;/a&gt;&lt;/em&gt; (&lt;a href="https://baud.rs/build-z80-ciarcia"&gt;Amazon&lt;/a&gt;), which we reviewed previously. Where Ciarcia's book is a construction manual (guiding the reader through building a complete Z80 system from power supply to CRT terminal) while Barden's handbook is a reference and survey. Ciarcia teaches you to &lt;em&gt;build&lt;/em&gt;; Barden teaches you to &lt;em&gt;understand&lt;/em&gt;. The two books complement each other almost perfectly, and it's easy to imagine a 1978-era hobbyist keeping both within reach: Barden's for looking up instruction encodings and timing specifications, Ciarcia's for wiring up the hardware to run them on.&lt;/p&gt;
&lt;p&gt;The difference in approach also reflects the different publishers. BYTE Books, which published Ciarcia, was rooted in the hobbyist magazine world and emphasized hands-on projects. Howard W. Sams had a longer tradition of comprehensive technical references. Each publisher played to its strengths.&lt;/p&gt;
&lt;h3&gt;Final Thoughts&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;The Z-80 Microcomputer Handbook&lt;/em&gt; is not a book that will teach you to build a computer, nor is it one that will dazzle you with narrative flair. It is, instead, something arguably more valuable: a thorough, well-organized, clearly written reference to a processor and its ecosystem, produced at the moment when that ecosystem was at its peak. Barden's systematic approach (hardware first, then software, then systems) gives the reader a complete understanding of the Z80 world from silicon to finished product.&lt;/p&gt;
&lt;p&gt;That the book was still being printed in 1985, with the IBM AT already on the market and the 80386 just a year away, is a testament to both the Z80's remarkable longevity and the quality of Barden's work. Eight printings don't happen by accident. They happen because engineers, students, hobbyists, and embedded systems designers kept walking into bookstores and electronics shops and deciding that yes, they still needed this book.&lt;/p&gt;
&lt;p&gt;Nearly five decades after its original publication, &lt;em&gt;&lt;a href="https://baud.rs/5brWaW"&gt;The Z-80 Microcomputer Handbook&lt;/a&gt;&lt;/em&gt; remains a worthwhile read for anyone interested in the foundations of microcomputing. Paired with Rodnay Zaks' &lt;em&gt;&lt;a href="https://baud.rs/EsBekO"&gt;Programming the Z80&lt;/a&gt;&lt;/em&gt; for software depth and J.S. Walker's &lt;em&gt;&lt;a href="https://baud.rs/Ch4htI"&gt;Design a Z80 Computer&lt;/a&gt;&lt;/em&gt; for a modern practical build guide, it forms part of an essential Z80 library. The architecture it documents influenced a generation of processor designs. The assembly language techniques it teaches remain relevant for anyone working close to the metal. And the ecosystem it surveys (that brief, fertile period when a handful of small companies were inventing the personal computer industry in real time) deserves to be remembered in the detail that Barden provided.&lt;/p&gt;</description><category>assembly language</category><category>book review</category><category>microprocessors</category><category>retrocomputing</category><category>vintage computing</category><category>william barden</category><category>z80</category><category>zilog</category><guid>https://tinycomputers.io/posts/the-z80-microcomputer-handbook-william-barden.html</guid><pubDate>Thu, 05 Feb 2026 21:00:00 GMT</pubDate></item></channel></rss>