Z80 Assembly 30: Emulating Floating-Point Arithmetic (High-Level Math)

The Challenge of Floating-Point The Z80 is an integer processor—it can only handle whole numbers. Floating-point numbers (like 3.14159 or 1.2e-5) are necessary for high-precision math used in physics simulations, graphics transformations, or advanced financial calculations. To use them, we must emulate the standard IEEE 754 format using multiple bytes of memory. Floating-Point Structure (The Four-Byte Standard): A typical 32-bit (4-byte) single-precision float is stored across four consecutive memory locations: ...

September 27, 2025

Z80 Assembly 29: Simple Random Number Generation (RNG) for Games

The Challenge of Randomness CPUs are deterministic: they do the same thing every time. To generate a truly unpredictable sequence, we need a source of entropy (unpredictable noise) from the outside world. Method 1: Hardware Noise (Simple Seed) The fastest way to get a simple random number is to read a register or port whose value is constantly changing due to external factors. Noise Sources: I/O Port Reading: Reading from an unused or floating I/O port can return unpredictable bits of electrical noise. The Refresh Register (R): As discussed earlier, the R register increments automatically, making its low bits somewhat unpredictable depending on when it’s read. The Keyboard: Polling the keyboard port and using the lower bits of the input byte before any key is pressed. Example: Reading an Unpredictable Port ...

September 27, 2025

Z80 Assembly 28: Basic Sound Generation (The Beeper Port)

The Basics of Beeper Sound Many simple Z80 systems (like the ZX Spectrum) lack a dedicated sound chip and rely on a simple speaker connected to an I/O port. This speaker is known as the beeper. How Tones are Made: A tone is generated by rapidly toggling a single bit in the output port (switching the speaker ON and OFF) at a specific frequency. Frequency & Pitch: The speed of the toggling loop determines the tone’s frequency (pitch). ...

September 27, 2025

Z80 Assembly 27: Horizontal and Vertical Scrolling (Fast Block Moves)

The Challenge of Scrolling Creating the illusion of movement across a large background map (scrolling) is a major performance challenge for 8-bit CPUs. You must shift thousands of bytes of screen memory every single frame. Slow code will cause a noticeable flicker or lag. The Solution: LDIR The Z80’s LDIR (Load, Increment, Repeat) instruction is the fastest tool for this job. It executes much faster than any software loop built with LD, INC, DEC, and JP. ...

September 27, 2025

Z80 Assembly 26: Collision Detection (Bounding Boxes and Bitwise Checks)

Bounding Box Collision (The Quick Check) Collision detection is computationally expensive. The fastest method is the Bounding Box check. This method checks if the rectangular area occupied by two objects (their boxes) overlap on the X and Y axes. If the boxes don’t overlap, the objects cannot be touching. The Principle: An overlap exists if: Object A’s right edge (A.X + A.Width) is > Object B’s left edge (B.X), AND Object A’s left edge (A.X) is < Object B’s right edge (B.X + B.Width), AND The same two conditions are met for the Y-axis. Z80 Implementation (X-Axis Check): ...

September 27, 2025

Z80 Assembly 25: Timing the Frame Rate (VSync) for Smooth Animation

The Problem: Screen Tearing If your Z80 code draws objects to the screen while the video hardware is actively reading and displaying that part of memory, you get a visual artifact called screen tearing (a horizontal break in the image). The Solution: VSync (Vertical Synchronization) Vertical Synchronization, or VSync, is the process of waiting until the video beam has finished drawing the current frame and is resetting to the top of the screen (the Vertical Blanking Interval, or VBI). By drawing only during the VBI, you ensure the user never sees partially rendered frames. ...

September 27, 2025

Z80 Assembly 24: Color and Attributes (Manipulating Screen Appearance)

The Need for Attribute Memory On many Z80 retro systems (such as the ZX Spectrum), the screen display is split into two distinct areas of memory: Pixel Data: Where the bits defining the shape of the image (the ‘black’ or ‘white’ dots) are stored. Attribute Data: Where the bits defining the appearance (color, brightness, flash) of the image are stored. This separation is necessary to save memory, as one attribute byte typically controls the appearance of an entire $8\times 8$ block of pixels. ...

September 27, 2025

Z80 Assembly 23: Graphics and Pixel Plotting (Bitwise Drawing)

The Screen Memory Layout On a bitmap Z80 system (like the ZX Spectrum), the screen is a large array of memory where each byte controls a group of 8 horizontal pixels. To plot a single pixel at coordinate (X, Y), you need two things: Memory Address: The 16-bit address of the byte that contains the pixel. Bit Mask: A byte with a single bit set (10000000B, 01000000B, etc.) to isolate the target pixel within that byte. Step 1: Calculating the Byte Address The calculation for the byte address is highly complex and specific to each system’s memory layout. It typically involves combining the Y-coordinate (row) and the X-coordinate (column). ...

September 27, 2025

Z80 Assembly 22: Reading Keyboard Input via I/O Ports

The Keyboard Matrix Scan Unlike modern PCs, Z80 systems don’t receive ASCII codes from the keyboard. Instead, the keyboard is wired as a matrix of rows and columns. To detect a keypress, the Z80 must scan this matrix using its I/O ports. The Two-Step Process: Output (Strobe): The CPU writes a value to an I/O port to select (or “strobe”) a single row of the keyboard matrix. Input (Read): The CPU reads a value from another I/O port. The bits set to ‘1’ in the input byte indicate which keys in the selected row are currently being pressed. Example: Scanning a Single Row Let’s assume our target system uses I/O port FEH for both output (strobe) and input (read) and that the rows are addressed by setting one bit to ‘0’. ...

September 27, 2025

Z80 Assembly 21: Setting Up for a Target System (Screen and Memory)

The Shift to System Programming Up until now, our code has been generic. System programming requires us to stop using symbolic addresses (like PRINT_STRING_ADDR) and start using absolute hardware addresses specific to our target machine. Key System-Specific Areas We Must Identify: Program Load Address (ORG): Where our code starts. Screen Memory: The RAM address where display data is stored. I/O Ports: The addresses for keyboard, sound, and display chips. Setting the Origin (ORG) and Stack (SP) Before execution begins, the assembler must know where in memory the program will be placed. ...

September 27, 2025