├── .gitignore
├── .vscode
├── extensions.json
└── settings.json
├── CMakeLists.txt
├── README.md
├── include
├── ClassProperties.h
├── File.h
├── FileSystem.h
├── MemoryPage.h
├── RamPage.h
├── RamVideoPage.h
├── ScreenArea.h
├── SpectrumScreenData.h
├── VideoController.h
├── ay3-8912-state.h
├── emulator.h
├── errorReadingFile.h
├── font8x8.h
├── keyboard.h
├── main_ROM.h
├── ps2Input.h
├── settings.h
├── volume.h
├── z80Emulator.h
├── z80Environment.h
├── z80Input.h
├── z80main.h
└── z80snapshot.h
├── lib
├── z80_AW
│ ├── LICENSE
│ ├── README.md
│ ├── z80.c
│ └── z80_AW.h
├── z80_JLS
│ ├── README.md
│ ├── z80.cpp
│ ├── z80.h
│ └── z80operations.h
├── z80_LKF
│ ├── README.txt
│ ├── instructions.h
│ ├── macros.h
│ ├── tables.h
│ ├── z80config.h
│ ├── z80emu.c
│ ├── z80emu.h
│ └── z80user.h
└── z80_ZEL
│ ├── LICENSE
│ ├── README.md
│ ├── tables
│ ├── cb_prefix.tab
│ ├── dd_prefix.tab
│ ├── ddcb_prefix.tab
│ ├── ed_prefix.tab
│ ├── fd_prefix.tab
│ ├── fdcb_prefix.tab
│ └── no_prefix.tab
│ ├── z80.c
│ ├── z80_instructions.c
│ ├── z80_types.h
│ └── zel
│ ├── z80.h
│ ├── z80_instruction_types.h
│ └── z80_instructions.h
├── platformio.ini
├── sdkconfig
├── sdkconfig.pico32
├── src
├── CMakeLists.txt
├── File.cpp
├── FileSystem.cpp
├── RamPage.cpp
├── RamVideoPage.cpp
├── ScreenArea.cpp
├── VideoController.cpp
├── ay3-8912-state.cpp
├── emulator.cpp
├── errorReadingFile.cpp
├── font8x8.cpp
├── main.cpp
├── main_ROM.c
├── ps2Input.cpp
├── volume.c
├── z80Emulator_AW.cpp
├── z80Emulator_JLS.cpp
├── z80Emulator_LKF.cpp
├── z80Emulator_ZEL.cpp
├── z80Environment.cpp
├── z80Input.cpp
├── z80main.cpp
└── z80snapshot.cpp
└── test
└── README
/.gitignore:
--------------------------------------------------------------------------------
1 | .pio/
2 | /lib/FabGL/
3 | /build/
4 | .vscode/.browse.c_cpp.db*
5 | .vscode/c_cpp_properties.json
6 | .vscode/launch.json
7 | .vscode/ipch
8 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // See http://go.microsoft.com/fwlink/?LinkId=827846
3 | // for the documentation about the extensions.json format
4 | "recommendations": [
5 | "platformio.platformio-ide"
6 | ],
7 | "unwantedRecommendations": [
8 | "ms-vscode.cpptools-extension-pack"
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "files.associations": {
3 | "sstream": "cpp",
4 | "array": "cpp",
5 | "string": "cpp",
6 | "algorithm": "cpp",
7 | "atomic": "cpp",
8 | "*.tcc": "cpp",
9 | "cctype": "cpp",
10 | "cerrno": "cpp",
11 | "cfloat": "cpp",
12 | "climits": "cpp",
13 | "clocale": "cpp",
14 | "cmath": "cpp",
15 | "cstdarg": "cpp",
16 | "cstdbool": "cpp",
17 | "cstddef": "cpp",
18 | "cstdint": "cpp",
19 | "cstdio": "cpp",
20 | "cstdlib": "cpp",
21 | "cstring": "cpp",
22 | "ctime": "cpp",
23 | "cwchar": "cpp",
24 | "cwctype": "cpp",
25 | "deque": "cpp",
26 | "map": "cpp",
27 | "unordered_map": "cpp",
28 | "unordered_set": "cpp",
29 | "vector": "cpp",
30 | "exception": "cpp",
31 | "functional": "cpp",
32 | "system_error": "cpp",
33 | "tuple": "cpp",
34 | "type_traits": "cpp",
35 | "iterator": "cpp",
36 | "memory": "cpp",
37 | "numeric": "cpp",
38 | "random": "cpp",
39 | "fstream": "cpp",
40 | "initializer_list": "cpp",
41 | "iomanip": "cpp",
42 | "ios": "cpp",
43 | "iosfwd": "cpp",
44 | "istream": "cpp",
45 | "limits": "cpp",
46 | "locale": "cpp",
47 | "new": "cpp",
48 | "ostream": "cpp",
49 | "queue": "cpp",
50 | "stdexcept": "cpp",
51 | "streambuf": "cpp",
52 | "cinttypes": "cpp",
53 | "utility": "cpp",
54 | "typeinfo": "cpp",
55 | "z80_instructions.h": "c"
56 | },
57 | "cmake.configureOnOpen": false,
58 | "idf.adapterTargetName": "esp32"
59 | }
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.16.0)
2 | include($ENV{IDF_PATH}/tools/cmake/project.cmake)
3 | project(Test)
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # esp32-z80emu
2 | Spectrum ZX 128K emulator on VGA-32 board
3 |
4 | ## Hardware
5 | [VGA32 v1.4 Board](https://www.lilygo.cc/en-ca/products/fabgl-vga32)
6 |
7 | ## What it can do
8 | * Emulate Spectrum ZX 128K
9 | * Load snapshot in .Z80 format from SD card
10 | * Save snapshot in .Z80 format to SD card
11 | * Output some sounds (partial support for AY3-8912)
12 | * Kempston mouse
13 | * Load ROMs from SD card (`/roms/128-0.rom`; `/roms/128-1.rom`. Fall back to OpenSE Basic if not present)
14 | * Not using any PSRAM
15 |
16 |
19 |
20 | ## Third party software
21 | This project uses the following libraries:
22 | * (GPL v3.0) Display video using VGA, process PS/2 keyboard, and sound output: https://github.com/fdivitto/FabGL
23 | * (GPL v2.0) OpenSE Basic: https://spectrumcomputing.co.uk/index.php?cat=96&id=27510
24 |
25 | Choose one of the following for Z80 CPU emulator:
26 | * (One liner, for those who don't like reading long legal documents) Lin Ke-Fong's https://github.com/anotherlin/z80emu
27 | * (GPL v3.0) José Luis Sánchez's https://github.com/jsanchezv/z80cpp
28 | * (MIT) Steve Checkoway's https://github.com/stevecheckoway/libzel
29 | * (zlib License) Andre Weissflog's https://github.com/floooh/chips (this one seems too slow)
30 |
31 | ## Plans for the future / issues
32 | * Flickering in some games
33 | * Beeper
34 | * Support noise and envelope for AY3-8912 sound
35 | * The speed is 12% faster than it is supposed to be
36 |
37 |
--------------------------------------------------------------------------------
/include/ClassProperties.h:
--------------------------------------------------------------------------------
1 | #ifndef __CLASSPROPERTIES_INCLUDED__
2 | #define __CLASSPROPERTIES_INCLUDED__
3 |
4 | // Magic from https://www.codeproject.com/Articles/12358/C-object-properties-with-no-run-time-or-memory-ove.
5 | template
6 | struct property
7 | {
8 | private:
9 | T* _this;
10 | V _value;
11 | public:
12 | property(T* this_):_this(this_) { }
13 | operator V() { return (_this->*_get)(); }
14 | void operator=(V i) { (_this->*_set)(i);}
15 | };
16 | #define CLASS(NAME) typedef NAME ClassType
17 | #define PROPERTY(TYPE, NAME) \
18 | property NAME
19 |
20 | #endif
21 |
22 |
--------------------------------------------------------------------------------
/include/File.h:
--------------------------------------------------------------------------------
1 | #ifndef __FILE_H__
2 | #define __FILE_H__
3 |
4 | #include
5 |
6 | namespace zx
7 | {
8 |
9 | class File : public std::fstream
10 | {
11 | public:
12 | size_t read(uint8_t* buf, size_t size);
13 | bool seek(uint32_t off, ios_base::seekdir way);
14 | size_t write(const uint8_t *buf, size_t size);
15 | };
16 |
17 | }
18 |
19 | #endif /* __FILE_H__ */
20 |
--------------------------------------------------------------------------------
/include/FileSystem.h:
--------------------------------------------------------------------------------
1 | #ifndef __SDCARD_H__
2 | #define __SDCARD_H__
3 |
4 | void FileSystemInitialize();
5 |
6 | bool loadSnapshotSetup(const char* path);
7 | bool loadSnapshotLoop();
8 |
9 | bool saveSnapshotSetup(const char* path);
10 | bool saveSnapshotLoop();
11 |
12 | bool ReadFromFile(const char* fileName, uint8_t* buffer, size_t size);
13 |
14 | #endif /* __SDCARD_H__ */
15 |
--------------------------------------------------------------------------------
/include/MemoryPage.h:
--------------------------------------------------------------------------------
1 | #ifndef __MEMORYPAGE_INCLUDED__
2 | #define __MEMORYPAGE_INCLUDED__
3 |
4 | #include
5 |
6 | class MemoryPage
7 | {
8 | public:
9 | uint8_t virtual ReadByte(uint16_t addr) = 0;
10 | uint8_t operator[](uint16_t addr)
11 | {
12 | return this->ReadByte(addr);
13 | }
14 | void virtual WriteByte(uint16_t addr, uint8_t data) = 0;
15 |
16 | uint16_t virtual ReadWord(uint16_t addr)
17 | {
18 | return (this->ReadByte(addr + 1) << 8) | this->ReadByte(addr);
19 | }
20 |
21 | void virtual WriteWord(uint16_t addr, uint16_t data)
22 | {
23 | this->WriteByte(addr + 1, data >> 8);
24 | this->WriteByte(addr, data & 0xFF);
25 | }
26 |
27 | void virtual FromBuffer(void* buffer) = 0;
28 | void virtual ToBuffer(void* buffer) = 0;
29 | };
30 |
31 | #endif
32 |
--------------------------------------------------------------------------------
/include/RamPage.h:
--------------------------------------------------------------------------------
1 | #ifndef __RAMPAGE_INCLUDED__
2 | #define __RAMPAGE_INCLUDED__
3 |
4 | #include "MemoryPage.h"
5 |
6 | class RamPage: public MemoryPage
7 | {
8 | private:
9 | uint8_t* _data = nullptr;
10 | public:
11 | RamPage& operator=(void* allocatedRam);
12 | operator uint8_t*();
13 |
14 | uint8_t virtual ReadByte(uint16_t addr) override;
15 | void virtual WriteByte(uint16_t addr, uint8_t data) override;
16 | void virtual FromBuffer(void* buffer) override;
17 | void virtual ToBuffer(void* buffer) override;
18 | };
19 |
20 | #endif
21 |
--------------------------------------------------------------------------------
/include/RamVideoPage.h:
--------------------------------------------------------------------------------
1 | #ifndef __RAMVIDEOPAGE_INCLUDED__
2 | #define __RAMVIDEOPAGE_INCLUDED__
3 |
4 | #include "MemoryPage.h"
5 | #include "SpectrumScreenData.h"
6 |
7 | class RamVideoPage: public MemoryPage
8 | {
9 | private:
10 | SpectrumScreenData* _videoRam = nullptr;
11 | uint8_t* _data = nullptr;
12 |
13 | public:
14 | void Initialize(SpectrumScreenData* _videoRam, void* allocatedRam);
15 |
16 | uint8_t virtual ReadByte(uint16_t addr) override;
17 | void virtual WriteByte(uint16_t addr, uint8_t data) override;
18 | void virtual FromBuffer(void* data) override;
19 | void virtual ToBuffer(void* buffer) override;
20 | };
21 |
22 | #endif
23 |
--------------------------------------------------------------------------------
/include/ScreenArea.h:
--------------------------------------------------------------------------------
1 | #ifndef _SCREENAREA_H
2 | #define _SCREENAREA_H
3 |
4 | #include "VideoController.h"
5 |
6 | class ScreenArea
7 | {
8 | private:
9 | VideoController* _videoController;
10 | uint16_t _xOffset;
11 | uint16_t _yOffset;
12 | uint16_t _Width;
13 | uint16_t _Height;
14 | uint8_t foreColor = 0xFF;
15 | uint8_t backColor = 0xFF;
16 |
17 | public:
18 | bool _isCursorVisible = false;
19 | uint16_t getX();
20 | uint16_t getY();
21 |
22 | ScreenArea(VideoController* videoController,
23 | uint16_t xOffset, uint16_t width,
24 | uint16_t yOffset, uint16_t height);
25 |
26 | void Clear();
27 | void SetAttribute(uint8_t x, uint8_t y, uint8_t foreColor, uint8_t backColor);
28 | void SetCursorPosition(uint8_t x, uint8_t y);
29 | void ShowCursor();
30 | void HideCursor();
31 | void SetPrintAttribute(uint16_t attribute);
32 | void SetPrintAttribute(uint8_t foreColor, uint8_t backColor);
33 | void Print(const char* str);
34 | void PrintAt(uint8_t x, uint8_t y, const char* str);
35 | void PrintAlignRight(uint8_t y, const char *str);
36 | void PrintAlignCenter(uint8_t y, const char *str);
37 | };
38 |
39 | #endif
40 |
--------------------------------------------------------------------------------
/include/SpectrumScreenData.h:
--------------------------------------------------------------------------------
1 | #ifndef _SPECTRUMSCREENDATA_H
2 | #define _SPECTRUMSCREENDATA_H
3 |
4 | #include
5 |
6 | #define SPECTRUM_WIDTH 32
7 | #define SPECTRUM_HEIGHT 24
8 |
9 | typedef struct
10 | {
11 | uint8_t* Pixels;
12 | uint16_t* Attributes;
13 | } SpectrumScreenData;
14 |
15 | #endif
16 |
--------------------------------------------------------------------------------
/include/VideoController.h:
--------------------------------------------------------------------------------
1 | #ifndef __VIDEOCONTROLLER__
2 | #define __VIDEOCONTROLLER__
3 |
4 | #include
5 | #include