First commit
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,3 @@
|
||||
.build/
|
||||
.clangd
|
||||
compile_commands.json
|
||||
@@ -0,0 +1,6 @@
|
||||
[submodule "libs/z80"]
|
||||
path = libs/z80
|
||||
url = https://github.com/redcode/z80
|
||||
[submodule "libs/z"]
|
||||
path = libs/z
|
||||
url = https://github.com/EnricoTrudu/z
|
||||
@@ -0,0 +1,39 @@
|
||||
CXX = g++
|
||||
BUILD = .build
|
||||
TARGET = emulator
|
||||
OPT = g -g
|
||||
DEFINE = -DCPU_Z80_STATIC -DCPU_Z80_USE_LOCAL_HEADER
|
||||
|
||||
CFLAGS = -Wall -Wextra -std=c++20 -O$(OPT) $(DEFINE) -flto -Iinclude `sdl2-config --cflags` -Ilibs/z80/API/emulation/CPU -Ilibs/z/API
|
||||
LDFLAGS = -Wall -Wextra -O$(OPT) -flto `sdl2-config --libs` -lSDL2_image
|
||||
|
||||
SRC = \
|
||||
src/main.cpp \
|
||||
libs/z80/sources/Z80.c \
|
||||
|
||||
OBJ_1 = $(notdir $(SRC:.cpp=.o))
|
||||
OBJ_2 = $(notdir $(OBJ_1:.c=.o))
|
||||
OBJ = $(addprefix $(BUILD)/, $(OBJ_2))
|
||||
# We can't use this as it will use the wrong main
|
||||
# vpath %.c $(sort $(dir $(SRC)))
|
||||
vpath %.cpp $(dir $(SRC))
|
||||
vpath %.c $(dir $(SRC))
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: $(BUILD) $(BUILD)/$(TARGET)
|
||||
|
||||
$(BUILD)/%.o: %.cpp Makefile | $(BUILD)
|
||||
$(CXX) -c $(CFLAGS) $< -o $@
|
||||
|
||||
$(BUILD)/%.o: %.c Makefile | $(BUILD)
|
||||
$(CXX) -c $(CFLAGS) $< -o $@
|
||||
|
||||
$(BUILD)/$(TARGET): $(OBJ) Makefile
|
||||
$(CXX) $(LDFLAGS) $(OBJ) -o $@
|
||||
|
||||
$(BUILD):
|
||||
mkdir $@
|
||||
|
||||
clean:
|
||||
rm -fr $(BUILD)
|
||||
Submodule
+1
Submodule libs/z added at 28ec6ff73b
Submodule
+1
Submodule libs/z80 added at b60d21889e
+224
@@ -0,0 +1,224 @@
|
||||
#include <bits/stdint-uintn.h>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <stdexcept>
|
||||
#include <array>
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_error.h>
|
||||
#include <SDL2/SDL_hints.h>
|
||||
#include <SDL2/SDL_image.h>
|
||||
#include <SDL2/SDL_log.h>
|
||||
#include <SDL2/SDL_main.h>
|
||||
#include <SDL2/SDL_render.h>
|
||||
#include <SDL2/SDL_video.h>
|
||||
#include <string>
|
||||
|
||||
#include "Z/types/base.h"
|
||||
#include "Z80.h"
|
||||
|
||||
template <int W, int H>
|
||||
class Emulator {
|
||||
public:
|
||||
Emulator(std::filesystem::path rom_name) {
|
||||
// SDL
|
||||
int render_flags = SDL_RENDERER_ACCELERATED;
|
||||
int window_flags = 0;
|
||||
|
||||
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
||||
throw std::runtime_error("Failed to initialize SDL2: " + std::string(SDL_GetError()));
|
||||
}
|
||||
|
||||
window = SDL_CreateWindow("Z80 Emulator", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, W*16, H*16, window_flags);
|
||||
if (!window) {
|
||||
throw std::runtime_error("Failed to open window: " + std::string(SDL_GetError()));
|
||||
}
|
||||
|
||||
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
|
||||
renderer = SDL_CreateRenderer(window, -1, render_flags);
|
||||
if (!window) {
|
||||
throw std::runtime_error("Failed to create rendere: " + std::string(SDL_GetError()));
|
||||
}
|
||||
|
||||
if (!IMG_Init(IMG_INIT_PNG)) {
|
||||
throw std::runtime_error("Failed to initialize SDL2_image: " + std::string(SDL_GetError()));
|
||||
}
|
||||
|
||||
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Loading '../convert-font/font.png'");
|
||||
font = IMG_LoadTexture(renderer, "../convert-font/font.png");
|
||||
|
||||
if (!font) {
|
||||
throw std::runtime_error("Failed to open font: " + std::string(IMG_GetError()));
|
||||
}
|
||||
|
||||
// Z80
|
||||
std::ifstream rom_file(rom_name, std::ios::in | std::ios::binary);
|
||||
|
||||
rom_file.seekg(0, std::ios::end);
|
||||
size_t rom_size = rom_file.tellg();
|
||||
rom_file.seekg(0, std::ios::beg);
|
||||
|
||||
rom_file.read(reinterpret_cast<char*>(memory.data()), rom_size);
|
||||
|
||||
z.context = this;
|
||||
z.read = z_read;
|
||||
z.write = z_write;
|
||||
z.in = z_in;
|
||||
z.out = z_out;
|
||||
z.int_data = z_int_data;
|
||||
|
||||
z80_reset(&z);
|
||||
}
|
||||
|
||||
~Emulator() {
|
||||
SDL_DestroyRenderer(renderer);
|
||||
|
||||
SDL_DestroyWindow(window);
|
||||
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
static zuint8 z_read(void* context, zuint16 address) {
|
||||
auto e = (Emulator<W,H>*)context;
|
||||
return e->memory[address];
|
||||
}
|
||||
|
||||
static void z_write(void* context, zuint16 address, zuint8 value) {
|
||||
auto e = (Emulator<W,H>*)context;
|
||||
e->memory[address] = value;
|
||||
}
|
||||
|
||||
static zuint8 z_in(void* /* context */, zuint16 port) {
|
||||
switch (port & 0xFF) {
|
||||
case 0x03:
|
||||
return 0x01;
|
||||
|
||||
// char
|
||||
case 0x1E:
|
||||
return 0x00;
|
||||
|
||||
// has_input
|
||||
case 0x1F:
|
||||
return 0x00;
|
||||
|
||||
default:
|
||||
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "IO Read @ 0x%X\n", (port & 0xFF));
|
||||
|
||||
return 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
static void z_out(void* context, zuint16 port, zuint8 value) {
|
||||
auto e = (Emulator<W,H>*)context;
|
||||
|
||||
switch (port & 0xFF) {
|
||||
case 0x02:
|
||||
e->input(value);
|
||||
break;
|
||||
|
||||
default:
|
||||
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "IO Wrte 0x%X @ 0x%X\n", value, (port & 0xFF));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static zuint32 z_int_data(void* /* context */) {
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void update() {
|
||||
z80_run(&z, 1);
|
||||
}
|
||||
|
||||
// @todo This should handle the input properly (same as fpga)
|
||||
void input(char c) {
|
||||
buffer[cursor.y*W + cursor.x] = c;
|
||||
|
||||
cursor.x++;
|
||||
if (cursor.x > W) {
|
||||
cursor.x = 0;
|
||||
cursor.y++;
|
||||
}
|
||||
}
|
||||
|
||||
void draw_buffer() {
|
||||
SDL_Rect src;
|
||||
src.w = 16;
|
||||
src.h = 16;
|
||||
|
||||
SDL_Rect dest;
|
||||
dest.w = 16;
|
||||
dest.h = 16;
|
||||
|
||||
SDL_SetTextureColorMod(font, 255, 255, 255);
|
||||
|
||||
for (int x = 0; x < W; ++x) {
|
||||
for (int y = 0; y < H; ++y) {
|
||||
char c = buffer[y*W + x];
|
||||
src.x = (c % 16) * 16;
|
||||
src.y = (c / 16) * 16;
|
||||
|
||||
dest.x = x * 16;
|
||||
dest.y = y * 16;
|
||||
|
||||
SDL_RenderCopy(renderer, font, &src, &dest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool handle_events() {
|
||||
SDL_Event event;
|
||||
|
||||
while (SDL_PollEvent(&event)) {
|
||||
switch (event.type) {
|
||||
case SDL_QUIT:
|
||||
return false;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void prepare() {
|
||||
SDL_SetRenderDrawColor(renderer, 96, 128, 255, 255);
|
||||
SDL_RenderClear(renderer);
|
||||
}
|
||||
|
||||
void render() {
|
||||
SDL_RenderPresent(renderer);
|
||||
}
|
||||
|
||||
private:
|
||||
SDL_Renderer* renderer = nullptr;
|
||||
SDL_Window* window = nullptr;
|
||||
SDL_Texture* font = nullptr;
|
||||
|
||||
std::array<char, W*H> buffer = {0};
|
||||
|
||||
struct {
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
} cursor;
|
||||
|
||||
Z80 z;
|
||||
std::array<uint8_t, 0xFFFF> memory;
|
||||
};
|
||||
|
||||
int main() {
|
||||
Emulator<80, 45> e("../../software/monitor/.build/rom_monitor.bin");
|
||||
|
||||
while (e.handle_events()) {
|
||||
e.prepare();
|
||||
|
||||
e.update();
|
||||
|
||||
e.draw_buffer();
|
||||
|
||||
e.render();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user