- Full 8080 instruction set — all documented opcodes including
DAA, rotate group, and the complete conditional branch/call/return matrix - Accurate flag logic — Sign, Zero, Parity, Carry and Auxiliary Carry updated per instruction per the Intel 8080 datasheet
- 64 KB address space backed by
std::array<uint8_t, 0x10000> - Pluggable I/O bus — wire
IN/OUTports to any peripheral viastd::functioncallbacks - CP/M BDOS hook — supports function 2 (character output) and function 9 (string output), enough to run standard
.COMprograms - Returns clock-cycle counts from
Step8080for future timing/throttling
Native8080/
├── src/
│ ├── cpu8080.h # State8080 struct, IOBus, public API
│ ├── cpu8080.cpp # Fetch-Decode-Execute engine
│ └── main.cpp # CP/M loader and main loop
├── samples/
│ └── hello.com # Pre-built CP/M Hello World (generated)
├── docs/
│ └── instruction_set_8080.txt # Opcode reference used during development
├── CMakeLists.txt
└── LICENSE
Requirements: CMake ≥ 3.16, a C++20-capable compiler (GCC 10+, Clang 12+).
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build buildThe binary is placed at build/native8080.
A Debug build automatically enables -fsanitize=address,undefined when the
compiler supports it:
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug
cmake --build build# Standard CP/M .COM program (loaded at 0x0100)
./build/native8080 samples/hello.com
# ROM image loaded at a custom address (hex)
./build/native8080 rom.bin 0000The emulator prints diagnostic messages to stderr and program output to
stdout, so they can be separated:
./build/native8080 samples/hello.com 2>/dev/nullThe emulator installs a minimal BDOS shim:
| C register | Function | Behaviour |
|---|---|---|
| 2 | Console character output | Prints the character in E |
| 9 | Print string | Prints from [DE] until $ |
A RET is placed at 0x0005 and a HLT at 0x0000, so programs that jump
to the warm-boot vector exit cleanly.
Edit make_io_bus() in src/main.cpp to attach real devices:
io.out_handler = [](uint8_t port, uint8_t val) {
if (port == 0x01) my_uart_write(val);
};
io.in_handler = [](uint8_t port) -> uint8_t {
if (port == 0x01) return my_uart_read();
return 0xFF;
};See LICENSE.