All Projects → suzukiplan → z80

suzukiplan / z80

Licence: MIT license
Single header Z80 emulator for C++ (C++11 or later)

Programming Languages

C++
36643 projects - #6 most used programming language

Projects that are alternatives of or similar to z80

Z80
Highly portable Zilog Z80 CPU emulator written in ANSI C
Stars: ✭ 131 (+670.59%)
Mutual labels:  cpu, z80, z80-emulator
Zany80
Zany80 fantasy computer system
Stars: ✭ 48 (+182.35%)
Mutual labels:  z80, z80-emulator
a80
Intel 8080/Zilog Z80 assembler written in D.
Stars: ✭ 23 (+35.29%)
Mutual labels:  z80, 8080
8080
A complete emulation of the Intel 8080 processor written in C99.
Stars: ✭ 109 (+541.18%)
Mutual labels:  cpu, 8080
ersatz80
Z80+ARM=BUGS
Stars: ✭ 13 (-23.53%)
Mutual labels:  z80, 8bit
gorilla-cpm
GORILLA.BAS port to CP/M in Turbo Modula-2. Supported terminals: VT52, VT100, ANSI, ADM-31, KayPro, C128, Memotech monochrome, CPC / Zenith Z19
Stars: ✭ 45 (+164.71%)
Mutual labels:  z80, 8bit
zasm
Z80 / 8080 / Z180 assembler (for unix-style OS)
Stars: ✭ 47 (+176.47%)
Mutual labels:  z80, 8080
ccpu
A 8-bit computer made of 74xx series logic gates and memory ICs.
Stars: ✭ 31 (+82.35%)
Mutual labels:  cpu, 8bit
Awesome Cpus
All CPU and MCU documentation in one place
Stars: ✭ 1,602 (+9323.53%)
Mutual labels:  cpu, z80
R8051
8051 soft CPU core. 700-lines statements for 111 instructions . Fully synthesizable Verilog-2001 core.
Stars: ✭ 70 (+311.76%)
Mutual labels:  cpu, 8bit
FPGACosmacELF
A re-creation of a Cosmac ELF computer, Coded in SpinalHDL
Stars: ✭ 31 (+82.35%)
Mutual labels:  cpu, 8bit
awesome-list
Awesome Lists of retrocomputing resources (6502, Apple 2, Atari, ...)
Stars: ✭ 38 (+123.53%)
Mutual labels:  z80, 8080
jsGBC
👾 A GameBoy Color Emulator written in JavaScript
Stars: ✭ 44 (+158.82%)
Mutual labels:  z80, z80-emulator
kernal64
A Scala Commodore 64, 128, VIC20, CBM2 and SuperCPU emulator
Stars: ✭ 87 (+411.76%)
Mutual labels:  z80
asMSX
AsMSX, originally developed by Pitpan. More info: https://www.msx.org/wiki/AsMSX.
Stars: ✭ 58 (+241.18%)
Mutual labels:  z80
MM.Hash
Profit Switching Miner For HiveOS/Linux- OLD VERSION: Project Moved To SWARM! https://github.com/MaynardMiner/SWARM
Stars: ✭ 17 (+0%)
Mutual labels:  cpu
cpu monitor
ROS node that publishes all nodes' CPU and memory usage
Stars: ✭ 52 (+205.88%)
Mutual labels:  cpu
6502.Net
A .Net-based Cross-Assembler for Several 8-Bit Microprocessors
Stars: ✭ 44 (+158.82%)
Mutual labels:  z80
spectrum128 cpm
zx spectrum 128 emulation on stm32f407 + Grant Searle's CP/M system port ili9341 16 bit display
Stars: ✭ 29 (+70.59%)
Mutual labels:  z80
MDSDRV
Sound driver for Sega Mega Drive
Stars: ✭ 44 (+158.82%)
Mutual labels:  z80

SUZUKI PLAN - Z80 Emulator

suzukiplan

The Z80 is an 8-bit CPU developed by Zilog corporation, released in 1976, and widely used in computers and game consoles in the 1980s. It is not just a relic of the past, but continues to be used in embedded systems that require accuracy in processing execution time, such as real-time systems.

SUZUKI PLAN - Z80 Emulator is an emulator under development based on the following design guidelines to support the development of programs and/or emulators using Z80, 8080:

(FOUR EASY GUIDELINES FOR EASILY)

  1. Make emulator implementation EASY & simple (Realized by providing single header: z80.hpp)
  2. EASILY debugging the Z80 programs (Realized by having dynamic disassemble feature)
  3. Highly readable and EASILY customizable (priority for readability over performance)
  4. Provide under the license that EASY to adopt in various programs (MIT)

Since I do not have deep knowledge about Z80 myself, I'm implementing it with reference to the information on the following web sites:

z80.hpp passes all zexdoc and zexall tests. (See the detail)

How to test

Prerequests

You can test on the any 32bit/64bit platform/OS (UNIX, Linux, macOS...etc) but needs following middlewares:

  • Git
  • GNU Make
  • clang
  • clang-format

Build (UNIX, Linux, macOS)

git clone https://github.com/suzukiplan/z80.git
cd z80
make

Minimum usage

1. Include

#include "z80.hpp"

2. Implement MMU & access callback

class MMU
{
  public:
    unsigned char RAM[0x10000]; // 64KB memory (minimum)
    unsigned char IO[0x100]; // 256bytes port

    MMU()
    {
        memset(&RAM, 0, sizeof(RAM));
        memset(&IO, 0, sizeof(IO));
    }
};

// memory read request per 1 byte from CPU
unsigned char readByte(void* arg, unsigned short addr)
{
    // NOTE: implement switching procedure here if your MMU has bank switch feature
    return ((MMU*)arg)->RAM[addr];
}

// memory write request per 1 byte from CPU
void writeByte(void* arg, unsigned short addr, unsigned char value)
{
    // NOTE: implement switching procedure here if your MMU has bank switch feature
    ((MMU*)arg)->RAM[addr] = value;
}

// IN operand request from CPU
unsigned char inPort(void* arg, unsigned char port)
{
    return ((MMU*)arg)->IO[port];
}

// OUT operand request from CPU
void outPort(void* arg, unsigned char port, unsigned char value)
{
    ((MMU*)arg)->IO[port] = value;
}

3. Make Z80 instance

    MMU mmu;
    /**
     * readByte: callback of memory read request
     * writeByte: callback of memory write request
     * inPort: callback of input request
     * outPort: callback of output request
     * &mmu: 1st argument of the callbacks
     */
    Z80 z80(readByte, writeByte, inPort, outPort, &mmu);

4. Execute

    // when executing about 1234Hz
    int actualExecuteClocks = z80.execute(1234);

5. Generate interrupt

IRQ; Interrupt Request

    z80.generateIRQ(vector);

NMI; Non Maskable Interrupt

    z80.generateNMI(address);

Optional features

Dynamic disassemble (for debug)

You can acquire the debug messages with setDebugMessage. Debug message contains dynamic disassembly results step by step.

    z80.setDebugMessage([](void* arg, const char* message) -> void {
        time_t t1 = time(NULL);
        struct tm* t2 = localtime(&t1);
        printf("%04d.%02d.%02d %02d:%02d:%02d %s\n",
               t2->tm_year + 1900, t2->tm_mon, t2->tm_mday, t2->tm_hour,
               t2->tm_min, t2->tm_sec, message);
    });

Use break point

If you want to execute processing just before executing an instruction of specific program counter value (in this ex: $008E), you can set a breakpoint as follows:

    z80.addBreakPoint(0x008E, [](void* arg) -> void {
        printf("Detect break point! (PUSH ENTER TO CONTINUE)");
        char buf[80];
        fgets(buf, sizeof(buf), stdin);
    });
  • addBreakPoint can set multiple breakpoints.
  • call removeBreakPoint or removeAllBreakPoints if you want to remove the break point(s).

Use break operand

If you want to execute processing just before executing an instruction of specific operand number (in this ex: $00; NOP), you can set a breakpoint as follows:

    z80.addBreakOperand(0x00, [](void* arg) -> void {
        printf("Detect break operand! (PUSH ENTER TO CONTINUE)");
        char buf[80];
        fgets(buf, sizeof(buf), stdin);
    });
  • addBreakOperand can set multiple breakpoints.
  • call removeBreakOperand or removeAllBreakOperands if you want to remove the break operand(s).

Detect clock consuming

If you want to implement stricter synchronization, you can capture the CPU clock consumption timing as follows:

    z80.setConsumeClockCallback([](void* arg, int clock) -> void {
        printf("consumed: %dHz\n", clock);
    });
  • call setConsumeClockCallback(NULL) if you want to remove the detector.

With this callback, the CPU cycle (clock) can be synchronized in units of 3 to 4 Hz, and while the execution of a single Z80 instruction requires approximately 10 to 20 Hz of CPU cycle (time), the SUZUKI PLAN - Z80 Emulator can synchronize the CPU cycle (time) for fetch, execution, write back, etc. However, the SUZUKI PLAN - Z80 Emulator can synchronize fetches, executions, writes, backs, etc. in smaller units. This makes it easy to implement severe timing emulation.

If implement quick save/load

Save the member variable reg when quick saving:

    fwrite(&z80.reg, sizeof(z80.reg), 1, fp);

Extract to the member variable reg when quick loading:

    fread(&z80.reg, sizeof(z80.reg), 1, fp);

Handling of CALL instructions

The occurrence of the branches by the CALL instructions can be captured by the CallHandler. CallHandler will be called back immediately after a branch by a CALL instruction occurs.

CallHandle will called back after the return address is stacked in the RAM.

    z80.addCallHandler([](void* arg) -> void {
        printf("Executed a CALL instruction:\n");
        printf("- Branched to: $%04X\n", ((Z80*)arg)->reg.PC);
        unsigned short sp = ((Z80*)arg)->reg.SP;
        unsigned short returnAddr = ((Z80*)arg)->readByte(sp + 1);
        returnAddr <<= 8;
        returnAddr |= ((Z80*)arg)->readByte(sp);
        printf("- Return to: $%04X\n", returnAddr);
    });
  • addCallHandler can set multiple CallHandlers.
  • call removeCallHandler or removeAllCallHandlers if you want to remove the CallHandler(s).
  • CallHandler also catches branches caused by interrupts.
  • In the case of a condition-specified branch instruction, only the case where the branch is executed is callbacked.

Handling of RET instructions

The occurrence of the branches by the RET instructions can be captured by the ReturnHandler. ReturnHandler will be called back immediately before a branch by a RET instruction occurs.

ReturnHandle will called back while the return address is stacked in the RAM.

    z80.addReturnHandler([](void* arg) -> void {
        printf("Detected a RET instruction:\n");
        printf("- Branch from: $%04X\n", ((Z80*)arg)->reg.PC);
        unsigned short sp = ((Z80*)arg)->reg.SP;
        unsigned short returnAddr = ((Z80*)arg)->readByte(sp + 1);
        returnAddr <<= 8;
        returnAddr |= ((Z80*)arg)->readByte(sp);
        printf("- Return to: $%04X\n", returnAddr);
    });
  • addReturnHandler can set multiple ReturnHandlers.
  • call removeReturnHandler or removeAllReturnHandlers if you want to remove the ReturnHandler(s).
  • In the case of a condition-specified branch instruction, only the case where the branch is executed is callbacked.

License

MIT

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].