First commit

This commit is contained in:
Dreaded_X 2021-01-14 20:31:32 +01:00
commit a1818fa31d
54 changed files with 274 additions and 0 deletions

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.

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
.build/
.clangd
compile_commands.json

6
.gitmodules vendored Normal file
View File

@ -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

39
Makefile Normal file
View File

@ -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)

1
libs/z Submodule

@ -0,0 +1 @@
Subproject commit 28ec6ff73bad0528eb22f38f6ca0e53827723cb3

1
libs/z80 Submodule

@ -0,0 +1 @@
Subproject commit b60d21889e246250ee0cac63bd6c64230959fe3c

224
src/main.cpp Normal file
View File

@ -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();
}
}