Z80 Assembly 50: Floating-Point to ASCII Conversion

The Challenge of Displaying Floats In Z80 assembly, a floating-point number is stored internally across multiple bytes (e.g., 4 or 5 bytes) in a specialized format (Part 30). The screen, however, only displays ASCII characters. Converting the binary float into a series of characters (“3”, “.”, “1”, “4”) is one of the most complex tasks in 8-bit programming. The Conversion Strategy The process is too complex for a single routine and is typically broken down into four major steps: ...

September 27, 2025

Z80 Assembly 49: Memory Diagnostics (Testing RAM Reliability)

The Need for RAM Testing Before running any critical code, especially on vintage or newly built Z80 hardware, you must verify that the Random Access Memory (RAM) is working correctly. Faulty RAM chips can lead to unpredictable crashes and data corruption. Goal: To ensure every memory cell can reliably store both a logic ‘0’ and a logic ‘1’. The Simplest Test: The Fill Test The fastest, simplest test is to fill the entire memory block with a single value (e.g., 00H or FFH) and then read it back to verify. However, this test is weak because a faulty address line might cause two memory locations to point to the same physical chip, and this test wouldn’t catch it. ...

September 27, 2025

Z80 Assembly 48: Interrupt Prioritization and the Daisy Chain

The Challenge of Multiple Devices In a complex Z80 system, you might have several devices that need to interrupt the CPU (e.g., a timer, a keyboard controller, and a disk controller). If two devices signal an interrupt at the exact same time, the CPU needs a clear way to decide which one to service first. This is called priority resolution. The Daisy Chain Protocol The Z80 uses a hardware architecture called a Daisy Chain to resolve interrupt priority. ...

September 27, 2025

Z80 Assembly 47: Debugging with the Stack (Crash Analysis)

The Value of the Stack in Debugging When a Z80 program crashes, the CPU registers often hold garbage data. The Stack, however, holds the historical sequence of return addresses created by every CALL instruction. Examining the stack is the primary method to determine how the program arrived at the crash point—the call chain. The Principle: You read the values on the stack, and these values are the addresses of the instructions immediately following the last few CALL commands. ...

September 27, 2025

Z80 Assembly 46: File I/O and SD Card Interfacing (Mass Storage)

The Challenge of Mass Storage Traditional Z80 systems used slow tape drives, but modern retro systems often use SD cards or CompactFlash for fast, reliable storage. The Z80 must communicate with these devices using a low-level protocol, typically SPI (Serial Peripheral Interface). The SPI Protocol (Simplified) SPI is a synchronous serial protocol that sends data one bit at a time over several dedicated lines controlled by I/O ports: Line Direction Purpose CLK Output The Clock signal (controls timing). MOSI Output Master Out, Slave In (Data sent from Z80 to SD card). MISO Input Master In, Slave Out (Data received by Z80 from SD card). CS Output Chip Select (Activates the specific SD card). Bit-Banging the SPI Signal Since the Z80 doesn’t have a native SPI controller, we must bit-bang the protocol entirely in software using fast I/O port writes and reads. ...

September 27, 2025

Z80 Assembly 45: Software Sprite Scaling and Rotation

The Challenge of Geometric Transformations The Z80 has no native support for the complex trigonometric math needed for rotation, nor does it have floating-point math for precise scaling. All geometric transformations must be calculated using fixed-point math and look-up tables (LUTs). Sprite Scaling (Zooming) Scaling a sprite involves sampling the source image at mathematically calculated intervals and writing the result to the screen. The Principle: To double the size of a sprite (Scale Factor = 2), you read every $1^{st}$ pixel from the source and draw it twice on the screen, both horizontally and vertically. ...

September 27, 2025

Z80 Assembly 44: Sprite Multiplexing and Display Lists

The Limitation: Hardware Sprite Count Many systems with dedicated sprite hardware (like the MSX or certain arcade boards) have a severe limit on the number of sprites that can be displayed on a single horizontal scanline (e.g., 8 or 16 sprites). Exceeding this limit causes sprites to disappear or flicker. The Solution: Sprite Multiplexing Sprite Multiplexing is a software technique that dynamically reuses the hardware’s limited number of sprite slots multiple times per frame. The goal is to quickly change the sprite’s position and pattern as the display beam moves down the screen. ...

September 27, 2025

Z80 Assembly 43: Memory Banking (Switching ROM and RAM)

The Limitation: 64 KB Address Space The Z80 uses 16-bit address lines, meaning it can only directly address 64 kilobytes (65,536 bytes) of memory (from address 0000H to FFFFH). Since many systems (like the MSX or larger Spectrums) have $128$ KB or more of RAM/ROM, they must use Memory Banking to access it all. How Memory Banking Works Memory Banking is the technique of using an I/O port to physically switch which $16$ KB or $8$ KB block of memory is visible to the CPU at a specific address range. ...

September 27, 2025

Z80 Assembly 42: Interfacing with a Real-Time Clock (RTC) Chip

The Need for a Real-Time Clock The Z80’s internal clock is only useful for instruction timing. It cannot track actual time (hours, minutes, days). A Real-Time Clock (RTC) is a separate, dedicated chip (like the DS1307 or MC146818) that contains its own crystal oscillator and often a small battery to maintain time even when the main computer is powered off. Communication: Indexed I/O The Z80 communicates with an RTC chip using a method called indexed I/O (similar to how the AY sound chip works). The RTC has a set of internal registers (e.g., 0-12) that store the seconds, minutes, hours, day, date, and control flags. ...

September 27, 2025

Z80 Assembly 41: Interrupt-Driven Serial Input (The Receiver)

The Challenge of Reliable Input In receiving serial data, the Z80 must wait for the exact moment the Start Bit arrives and then sample the input line precisely at the center of each of the next eight data bits. If the CPU misses the timing, the data is corrupted. The Solution: Interrupt-Driven Sampling The CPU cannot wait in a tight timing loop for data to arrive. Instead, we use a timer interrupt to tell the CPU exactly when to check the input line. ...

September 27, 2025