News:

The Savage///Circuits website has been upgraded to a more efficient theme.

Main Menu

Random Z80 Hand Disassembly

Started by Chris Savage, Nov 25, 2025, 02:02 PM

Previous topic - Next topic

Chris Savage

Downloaded a random EPROM from a device into the XGPro software and realized immediately it was Z80 code. How? Well, having worked with the Z80 for so many years you start to recognize that the first several bytes of almost every Z80 program start with very specific bytes. This is mostly to show @JKnightandKARR how I decode Z80 assembly code.

You cannot view this attachment.

Here is a screenshot of the buffer window. As you can see, the first byte is $31, which is the Z80 opcode for:

LD SP,<address>, where <address> is the start address of the stack pointer (SP). So, in this case, that would be:

LD SP, $A000

The next byte is $F3, which is the Z80 opcode for:

DI, which disables interrupts.

The next byte is $C3, which is the Z80 opcode for:

JP <address>, where <address> is the the value to be loaded into the program counter (jumped to). The next two bytes are the address, so:

JP $0100

You can see that the program jumps to $0100. That's because $0038 through $0066+ are interrupt vector addresses. At $0100 we see a byte value of CD, which is the Z80 opcode for CALL <address>, with the following two bytes being $19 and $01, the subroutine would be located at $0119.

Next we have $CD $8E $01, which is CALL $018E.

Continuing, this is what we have:

$0100    CALL $0119
$0102    CALL $018E
$0106    CALL $0326
$0109    CALL $OEF6
$010C    LD A,($8E40)
$010F    OR A
$0110    JP NZ,$0106

I will eventually disassemble the entire thing, but thus far we can see that the code does what almost every Z80 program does, which is set the stack pointer, disable interrupts, then start setting up hardware, which is most likely what the first few CALLs are doing. $0110 could be considered a "LOOP" for all intents and purposes, because it unconditionally jumps back to $0106, which would be the "DO" of the loop. In between it's making a couple of calls, the loading the A register with the contents of memory address $8E40, then activating the flags, until it gets a $00 in the A register, at which point the loop exits and the code continues.

It will be interesting to see exactly what is happening here. More to come.

                    Bringing concepts to life through engineering.