summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOxore <oxore@protonmail.com>2022-10-19 02:28:03 +0300
committerOxore <oxore@protonmail.com>2022-10-19 02:28:03 +0300
commiteddd0a826b1720c26b0ac5df0269db3982bc8f35 (patch)
tree94548f986eb190c734315db252e57a79c118031f
parentae9a7aef2f0422f6872e6ae27e4e4e2084d8ce8f (diff)
Begin implementing VDP rendering
-rw-r--r--CMakeLists.txt10
-rw-r--r--emulator.cpp17
-rw-r--r--graphics.cpp83
-rw-r--r--graphics.hpp26
-rw-r--r--vdp.cpp6
-rw-r--r--vdp.hpp6
6 files changed, 143 insertions, 5 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5edf23b..994b703 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -19,6 +19,7 @@ set(emulator_sources
bus.cpp
emulator.cpp
gdbremote_parser.cpp
+ graphics.cpp
m68k_debugging.cpp
vdp.cpp
)
@@ -28,6 +29,7 @@ set(musashi_m68k_sources
musashi-m68k/softfloat/softfloat.c
${CMAKE_CURRENT_BINARY_DIR}/m68kops.c
)
+
add_executable(m68kmake musashi-m68k/m68kmake.c)
target_include_directories(m68kmake PRIVATE musashi-m68k)
add_custom_command(
@@ -45,12 +47,20 @@ target_include_directories(musashi_m68k PRIVATE
${CMAKE_CURRENT_BINARY_DIR}
)
+# TODO make SDL2 optional for headless mode
+find_package(SDL2 REQUIRED)
+
add_executable(emulator ${emulator_sources})
target_link_libraries(emulator musashi_m68k)
+# TODO make SDL2 optional for headless mode
+target_include_directories(emulator PRIVATE ${SDL2_INCLUDE_DIRS})
+# TODO make SDL2 optional for headless mode
+target_link_libraries(emulator ${SDL2_LIBRARIES})
target_compile_definitions(emulator PRIVATE
DEBUG_TRACE_INSTRUCTIONS=0
DEBUG_TRACE_GDB_REMOTE=0
DEBUG_TRACE_VDP_ACCESS=1
+ HAS_GRAPHICS=1
)
## Target for GDB Remote Debugging protocol implementation testing
diff --git a/emulator.cpp b/emulator.cpp
index 3ec756d..70927bd 100644
--- a/emulator.cpp
+++ b/emulator.cpp
@@ -2,6 +2,7 @@
*/
#include "bus.hpp"
+#include "graphics.hpp"
#include "vdp.hpp"
#include "m68k_debugging.hpp"
#include "gdbremote_parser.hpp"
@@ -433,7 +434,7 @@ void ParseAndReact(
}
}
-int emulator(M68KDebuggingControl& m68k_debug)
+int emulator(M68KDebuggingControl& m68k_debug, Graphics& graphics)
{
const int port = 3333;
const int socket_fd = setup_socket(port);
@@ -483,8 +484,9 @@ int emulator(M68KDebuggingControl& m68k_debug)
}
if (m68k_debug.IsRunning()) {
do {
- m68k_execute(100000);
+ m68k_execute(1000000);
} while(!g_vdp.Scanline());
+ graphics.Render(g_vdp);
}
if (m68k_debug.HasBreakpoint()) {
m68k_debug.SetRunning(false);
@@ -501,7 +503,7 @@ int emulator(M68KDebuggingControl& m68k_debug)
clock_nanosleep(CLOCK_MONOTONIC, 0, &kOneMillisecond, nullptr);
}
close(conn_fd);
- g_no_ack_mode = false;
+ g_no_ack_mode = false; // TODO move to GDB::ExchangeContext
}
close(socket_fd);
return 0;
@@ -525,12 +527,17 @@ int main(int argc, char* argv[])
exit_error("Error reading %s", argv[1]);
printf("Read into ROM %zu bytes\n", fread_ret);
+ Graphics graphics{};
+ if (!graphics.IsOk()) {
+ return EXIT_FAILURE;
+ }
+
m68k_init();
m68k_set_cpu_type(M68K_CPU_TYPE_68000);
m68k_pulse_reset();
m68k_execute(1); // Skip reset cycles
- emulator(g_m68k_debug);
+ emulator(g_m68k_debug, graphics);
- return 0;
+ return EXIT_SUCCESS;
}
diff --git a/graphics.cpp b/graphics.cpp
new file mode 100644
index 0000000..2455630
--- /dev/null
+++ b/graphics.cpp
@@ -0,0 +1,83 @@
+/* SPDX-License-Identifier: Unlicense
+ */
+
+#include "graphics.hpp"
+#include "vdp.hpp"
+
+#include <cstdlib>
+
+Graphics::Graphics()
+{
+#if HAS_GRAPHICS == 1
+ SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
+
+ if (SDL_Init(SDL_INIT_VIDEO) < 0) {
+ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError());
+ return;
+ }
+ _window = SDL_CreateWindow("Gut (SEGA MD/G emulator)",
+ SDL_WINDOWPOS_UNDEFINED,
+ SDL_WINDOWPOS_UNDEFINED,
+ VDP().render_width, VDP().render_height,
+ SDL_WINDOW_RESIZABLE);
+ if (!_window) {
+ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set create window: %s\n", SDL_GetError());
+ SDL_Quit();
+ return;
+ }
+ _renderer = SDL_CreateRenderer(_window, -1, 0);
+ if (!_renderer) {
+ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set create renderer: %s\n", SDL_GetError());
+ SDL_Quit();
+ return;
+ }
+ _render_texture = SDL_CreateTexture(
+ _renderer,
+ SDL_PIXELFORMAT_ARGB8888,
+ SDL_TEXTUREACCESS_STREAMING,
+ VDP().render_width,
+ VDP().render_height);
+ if (!_render_texture) {
+ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set create texture: %s\n", SDL_GetError());
+ SDL_Quit();
+ return;
+ }
+#endif
+ _initialized_ok = true;
+}
+
+Graphics::~Graphics()
+{
+#if HAS_GRAPHICS == 1
+ SDL_DestroyTexture(_render_texture);
+ SDL_DestroyRenderer(_renderer);
+ SDL_DestroyWindow(_window);
+ SDL_Quit();
+#endif
+}
+
+void Graphics::Render(const VDP& vdp)
+{
+ const uint8_t* buffer = vdp.GetRenderedBuffer();
+#if HAS_GRAPHICS == 1
+ void* pixels;
+ int pitch;
+ if (SDL_LockTexture(_render_texture, NULL, &pixels, &pitch) < 0) {
+ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't lock texture: %s\n", SDL_GetError());
+ abort();
+ }
+ for (int row = 0; (size_t)row < VDP().render_height; row++) {
+ uint32_t *dst = (uint32_t*)((uint8_t*)pixels + row * pitch);
+ for (int col = 0; (size_t)col < VDP().render_width; col++, buffer += 4) {
+ const uint32_t color = ((buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]);
+ *dst++ = color;
+ }
+ }
+ SDL_UnlockTexture(_render_texture);
+ SDL_RenderClear(_renderer);
+ SDL_RenderCopy(_renderer, _render_texture, NULL, NULL);
+ SDL_RenderPresent(_renderer);
+#else
+ (void) buffer;
+#endif
+}
diff --git a/graphics.hpp b/graphics.hpp
new file mode 100644
index 0000000..a88cd61
--- /dev/null
+++ b/graphics.hpp
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: Unlicense
+ */
+
+#pragma once
+
+class VDP;
+
+#if defined(HAS_GRAPHICS) && HAS_GRAPHICS == 1
+# include "SDL.h"
+#endif
+
+class Graphics {
+public:
+ Graphics();
+ ~Graphics();
+ bool IsOk() const { return _initialized_ok; }
+ void Render(const VDP&);
+
+private:
+ bool _initialized_ok{};
+#if defined(HAS_GRAPHICS) && HAS_GRAPHICS == 1
+ SDL_Renderer* _renderer{};
+ SDL_Window* _window{};
+ SDL_Texture* _render_texture{};
+#endif
+};
diff --git a/vdp.cpp b/vdp.cpp
index b1f5817..7fabfef 100644
--- a/vdp.cpp
+++ b/vdp.cpp
@@ -141,6 +141,12 @@ bool VDP::Scanline()
if (!MODESET2_DISP_GET(mode_set_2)) {
return true;
}
+ for (size_t i = 0; i < render_width; i++) {
+ _rendered_buffer[render_width * _lines_counter * 4 + i + 0] = 0xff; // Alpha
+ _rendered_buffer[render_width * _lines_counter * 4 + i + 1] = 0xff; // Red
+ _rendered_buffer[render_width * _lines_counter * 4 + i + 2] = 0x7f; // Green
+ _rendered_buffer[render_width * _lines_counter * 4 + i + 3] = 0x7f; // Blue
+ }
_lines_counter++;
const uint16_t lines_per_screen = _status.pal_mode ? kLinesPerScreenPAL : kLinesPerScreenNTSC;
if (_lines_counter >= lines_per_screen) {
diff --git a/vdp.hpp b/vdp.hpp
index 1db49db..b9e8841 100644
--- a/vdp.hpp
+++ b/vdp.hpp
@@ -15,9 +15,14 @@ class VDP {
void Write(uint32_t offset, enum bitness, uint32_t value);
bool Scanline(); // Returns true if display disabled or vblank happened
void Reset();
+ const uint8_t* GetRenderedBuffer() const { return _rendered_buffer; }
const uint32_t base_address;
+ static constexpr size_t render_height = 224;
+ static constexpr size_t render_width = 320;
+ static constexpr size_t render_buffer_size = 320*224*4;
+
private:
struct StatusRegister {
bool fifo_not_empty{};
@@ -107,4 +112,5 @@ class VDP {
uint8_t _vram[kVRAMSize]{};
uint8_t _cram[kCRAMSize]{};
uint8_t _vsram[kVSRAMSize]{};
+ uint8_t _rendered_buffer[render_buffer_size]{};
};